Author: 芳草苑主

  • System restore is useless

    Windows 里装坏了一个软件,怕卸载不干净,在卸载后运行系统还原,结果说——无法还原!换一个还原点,还是无法还原!

    Unable to perform system restore
    Unable to perform system restore

    以后干脆关闭系统还原,依赖虚拟机的快照功能或许还可靠一些。

  • Manage gallery image with customised URL in Magento

    Magento 后台对产品图片的管理操作非常简单,直接在浏览器里从本地上传,然后指定哪个作大图(image)、哪个作小图(small image)、哪个作缩略图(thumbnail)。这种傻瓜式的操作有三大缺点:

    • 不适合大批量图片的管理;
    • 图片上传后图片的存放位置乱序,不方便远程文件管理。(abc.jpg 上传后被存放在 /media/catalog/product/a/b/abc.jpg。如果之前已经有同名文件,新上传的文件自动更名为abc_1.jpg, abc_2.jpg,以此类推。)
    • 搜索引擎会从图片的 URL 里获取图片的部分信息,杂乱的 URL 不利于图片 SEO。

    我认为最理想的图片管理模式是:在本地按产品分类分级维护一个图片库,用 FTP 上传到服务器,在 Magento 后台可以浏览这些文件(对 Magento 来说是本地文件),然后为某个产品选定它的大图、小图和缩略图。这样 Magento 里保存的图片位置信息就保持了自定义的产品分类信息。

    Magento 的自动缩放图功能很好用,但自动缩放图生成的文件 URL 又臭又长,肯定不利于 SEO,而且服务器硬盘上留下一大堆乱序规则生成的文件夹,实在难看(有种屋子没打扫的感觉)。鉴于一个优质的电子商务网站本应该对整站的图片大小有统一的规范,不妨在本地制作好小图和缩略图,不依赖 Magento 的自动缩放图功能。

    好多年前我就想做个 Magento module 来优化 Magento 的图片管理,但事务繁忙,也不知道什么时候能静下心写代码。与其让听众苦等我的 module,不如我介绍一下 Magento 数据库中 gallery 的结构,让大家懂得直接操作数据库去搭 product 和 local images 之间的桥。

    首先做两个准备工作。

    一是查好每个产品的 ID 备用。如果人可以 SKU 识别产品,那就准备一张 SKU – ID 的一一对应表;如果人可以 product name 识别产品,那就准备一张 product name – ID 的一一对应表。

    二是把每个产品的大图、小图和缩略图命名得有意义,比如是大图是 product-name-1.jpg, product-name-2.jpg, product-name-3.jpg,小图是 product-name-s.jpg,缩略图是 product-name-t.jpg(因为 small 和 thumbnail 不是产品的关键字,所以没必要拼写完整,用自己人能看明白的代号就可以)。FTP 上传图片至 /media/catalog/product/category-name/sub-category-name/SKU/,一个产品的图片归在一个文件夹下。

    现在开始正式操作数据库。操作涉及到 4 个产品属性(attribute)和 4 张表(table)。

    4 个产品属性:image, small_image, thumbnail, media_gallery.

    4 张表:magento_eav_attribute, magento_catalog_product_entity_media_gallery, magento_catalog_product_entity_media_gallery_value, magento_catalog_product_entity_varchar.

    第一步:在 magento_eav_attribute 中查出 4 个产品属性的 attribute_id。在我碰到的 Magento 早期版本中,4 个产品属性的 attribute_id 分别是:

    • image: 70
    • small_image: 71
    • thumbnail: 72
    • media_gallery: 73

    在最新的 1.7.0.0 中,4 个产品属性的 attribute_id 分别是:

    • image: 85
    • small_image: 86
    • thumbnail: 87
    • media_gallery: 88

    当然可以顺便看一下 product 的 entity_type_id,不出意外的话,这应该是 4。后面会用到。

    第二步:在 magento_catalog_product_entity_media_gallery 插入记录。一张图片就是一条记录,插入记录就是定义产品和图片之间一对多的关系。

    Insert record to magento_catalog_product_entity_media_gallery
    Insert record to magento_catalog_product_entity_media_gallery

    magento_catalog_product_entity_media_gallery 中各 column 的意义是:

    • value_id:记录 ID,可以留空让数据库自动生成。
    • attribute_id:media_gallery 的 attribute_id。
    • entity_id:产品 ID。
    • value:文件存放位置信息(略去 /media/catalog/product 部分)。
    Gallery records for one product
    Gallery records for one product

    做完这两步就可以在 Magento 后台 Manage Products 的 Images 那一页上看到属于这产品的图片。后面几步可以移至 Magento 后台完成。我继续介绍如何直接操作数据库,是让大家知道如何用数据库的导入功能去批量处理。

    第三步:在 magento_catalog_product_entity_media_gallery_value 插入记录。这等效于在 Magento 后台为每个图片在各个商店设定 Label, Sort Order, Exclude 值。

    如果只有一个商店,一条 magento_catalog_product_entity_media_gallery 记录就对应一条 magento_catalog_product_entity_media_gallery_value 记录。

    如果有多个商店,default store_id 就是 0,先按一条 magento_catalog_product_entity_media_gallery 记录对应一条 magento_catalog_product_entity_media_gallery_value 插入记录。假设另有两个商店,store_id 分别是 1 和 2,store_id 1 沿用 store_id 0 的 default 值,store_id 2 则使用一组不同的 label/position/disable 值。这样,不需要为 store_id 1 多插入一条记录,因为 Magento 的 Website/Storegroup/Storeview 的规则是没有额外记录就是使用 default value。只需要为 store_id 2 多插入一条记录,这条记录优先于 default value,但只为 store_id 2 而生效。

    magento_catalog_product_entity_media_gallery_value 中各 column 的意义是:

    • value_id:匹配 magento_catalog_product_entity_media_gallery 的记录 ID。
    • store_id:商店 ID。
    • label:图片说明。
    • position:图片排序。
    • disabled:0 就是不 Exclude,1 就是 Exclude。
    Insert record to magento_catalog_product_entity_media_gallery_value
    Insert record to magento_catalog_product_entity_media_gallery_value
    Disable (Exclude) small image and thumbnail
    Disable (Exclude) small image and thumbnail

    第四步:在 magento_catalog_product_entity_varchar 插入记录。这等效于在 Magento 后台为每个产品在各个商店设定哪个是默认大图(大图可以有多张,只有一张是默认的)、哪个是小图、哪个是缩略图。

    magento_catalog_product_entity_varchar 中各 column 的意义是:

    • value_id:记录 ID,可以留空让数据库自动生成。
    • entity_type_id:不出意外的话,应该填 4。
    • attribute_id:image/small_image/thumbnail 的 attribute_id。
    • store_id:商店 ID。
    • entity_id:产品 ID。
    • value:文件存放位置信息(略去 /media/catalog/product 部分)
    Insert record to magento_catalog_product_entity_varchar
    Insert record to magento_catalog_product_entity_varchar

    假设以前用 Magento 后台上传过产品图片,删除了,保存产品,这时,服务器硬盘上的图片不会随之删除,数据库里的 image/small_image/thumbnail 记录也不会随之删除(只是 value column 的值被 NULL 代替)。这也是我不喜欢用 Magento 后台来管理产品图片的一个原因。

    Duplicate record error
    Duplicate record error

    这些 NULL 值的记录会导致插入不成功,因为 magento_catalog_product_entity_vartype 有规定 entity_id, attribute_id, store_id 三值组的唯一性。不让插的话编辑原记录。

    Search by attribute_id and entity_id
    Search by attribute_id and entity_id
    Search result by attribute_id and entity_id
    Search result by attribute_id and entity_id

    或者,把原有的 image/small_image/thumbnail 记录全删了,再插。

    Search by attribute_id
    Search by attribute_id
    Search result by attribute_id
    Search result by attribute_id

    这四步做完后,Magento 前后台就显示了指定的图片。

    Magento GUI manage products images
    Magento GUI manage products images
    Magento store front product page
    Magento store front product page

    这时 Magento 的自动缩放图功能仍在生效,需要修改模板让 Magento 直接使用指定的大图、小图和缩略图,这里不再多述。

  • Deal with Indian

    一直想买一个 metal filing cupboard,在网上溜达了一圈发现都要 £160 – £200,觉得有点贵,一时没下手。上周六, 在 gumtree 上发现同城有人卖一个二手 metal filing cupboard,标价 £40。我觉得金属的文件柜新旧区别不大,决定去买。打个电话问出卖家地址、约好时间就出发了。

    我到达时只有一个印度小孩在家,十多岁,开了门,领我去看文件柜。文件柜大小正好合适,八成新。我看了满意,就说买了,然后我动手拆。因为我想省个租 van 的钱,文件柜不算贵,叫个 van 倒挺贵,而且只搬一个柜子,总觉得不值。

    拆了没几分钟,小孩的印度父母回来了。那个印度男人叫我把整个柜子搬上车就得了,我说我开的是 car,不是 van。他建议我叫辆 van,我说我想省这个钱。

    这时印度男人突然说,“你先把钱付了。”

    我愣了一下,说,“不用那么急讨钱吧,我还没搬走它呢。”

    印度男人说,“你想要了,就付钱。”

    他口气很急切,我却没上心,也犯了个主观主义错误,认为在英国不会有人为 £40 的旧货玩什么猫腻。

    我说,“先付一半,搬运前再付清。”

    印度男人同意,收了 £20 帮我继续拆。没多久,我们碰到难题,有几个螺丝拧不下来。我却又犯了个主观主义错误,认为这种柜子是能拆成一块块的板,我拧不动螺丝是因为印度人提供的螺丝刀不好。

    于是我说回去拿工具,印度男人说把钱付清了再走。我嫌他婆婆妈妈,付了另外 £20。

    然后印度男人说把拆了一半的柜子搬到他车库门口,让我随时来取就是。我说好。

    等搬完这堆散架的柜子,印度男人发表声明似的郑重其事地说,“现在这柜子所有部件都搬出我家了,我不会负任何责任;如有损坏或遗失,都是你的事。”

    我哭笑不得,走人。等我拿了工具回来,多花了一点时间研究,发现这个柜子的上下左右四块板是不能拆卸的,看来租 van 是免不了的了。

    这个印度男人会为了 £40 隐瞒事实,折腾我前后跑了三趟(后来带着 van 又去一次),浪费大量的时间拆柜子、装柜子,非常可恶。

    看来跟印度人打交道要以小人之心度之。

  • Add Google as a search provider in IE

    Microsoft IE made adding Google as a search provier extremely difficult. Google is removed from the search providers list – just because Google is too good to be a search provider?

    For anyone wants to search with Google in IE, add Google UK as a search provider by visiting this link http://www.iegallery.com/gb/addons/detail.aspx?id=13438.

  • Like WordPress, Dislike Cisco

    WordPress 升 3.3了,感觉更清新了。好喜欢。

    Cisco 本是不相干的一件事,为了省事,我放一块说了。两年前买了 Cisco WVC210 wireless IP camera,当时市价 £150左右,我买的是样机,£90。买了之后玩了两天就成了摆设,因为它距离路由器10米的地方隔两堵墙就不工作了。

    最近为 hotel 买了几个 Xenta Wireless Night and Day Wireless IP Network Camera,£50不到,超级满意。我本不太敢买 Xenta 的产品,因为没有这个牌子的使用经验,事实证明我的顾虑是多余的。

    跟 Cisco WVC210 wireless IP camera 相比好在哪?

    • 首先,Xenta 有红线成像而 Cisco 没有;
    • 其次,Xenta 内置喇叭而 Cisco 没有;
    • 再次,Xenta pan & tilt 时静悄悄的而 Cisco 有吱吱声;
    • 最后,Xenta 物美价实,而 Cisco 卖了两年还在卖 £150。
  • Item advertised for less than £18 does not have VAT in Jersey

    我原来仅知道在英国做生意,年营业额到了 £61,000 必须注册 VAT。所以,象 play.com 这样的大网店我认为它是注有 VAT 的。但我在 play.com 买了两个黑色墨盒(Kodak 30XL)和一个彩色墨盒(Kodak 30C),在 shopping cart 页面找不到任何 inc VAT or ex VAT 的价格提示,于是打电话给 play.com customer support。

    I said, “I want to buy some cartridges. Are your price including VAT or excluding VAT?”

    The lady answered, “Yes, including VAT.”

    然后我就买了。买了发现 play.com 没给 VAT receipt(确切地说,没给任何收条,也下载不到)。这回我写信去索要 VAT receipt,结果收到回信说:Item advertised for less than £18 does not have VAT in Jersey.

    这下我要批评起先的电话客服小姐提供错误信息,是业务不精还是故意的?没办法深究了,口说无凭。

    但是,不得不佩服 play.com 挖空心思去避开 VAT:

    首先,Jersey 是个小岛,在 Jersey 经营业务无疑会增加物流成本和其他费用,但 play.com 可以用规模经济来降低这些成本。

    其次,每个墨盒都小于 £18,但三个墨盒在 £30 左右。play.com 发给我的 order confirmation 中为每个墨盒分配了一个 order number。当时我就很奇怪——硬生生拆成三个订单干什么?现在想来,觉得这是在规避 item less than £18 在法律上的歧义。

    再次,单个墨盒都是 free delivery,当时我仅感觉实惠。现在想来,觉得这是为小额商品 no VAT, free delivery 精心设计的低价竞争手段。

    但话说回来,play.com no VAT 的销售对我注有 VAT 的买家来说没有吸引力,其它卖家的 ex VAT price 跟它差不多。反而,我被 play.com 的小伎俩搞得有点懊恼。电话客服小姐不专业、receipt 不能下载是 play.com 的致命伤。

  • Chinese interface in Android

    我不愿意用刷中文 ROM 的方法把手机的界面变为中文。

    我看到这里苹果店的手机都能在设置里调出中文界面,觉得 Android 手机更应该内置了全球语言包。大部分英国卖的 Android 手机看不到中文语言这个选项,是网络提供商把它隐藏起来了。基于这个推理,我 Google 了好久,终于发现在 Market 里搜索 Custom Locale 就能找到若干应用,随便选装一个就能把隐藏的中文调出来。

    随后,我又发现,Android OS 本身已100%国际化,如 Map, Market, Navigation 这些程序都能显示中文。但一些手机厂商自己开发的程序,如拨电话、发短信的程序并没有中文包,比如我的 Samsung Galaxy S2 就没有这样的语言包,所以这些程序在 zh_CN locale 下只能显示英文。

    HTC 在这方面就有独到的优势,毕竟是中国人的公司,它开发的程序一般都照顾到了中文。我买过一个 HTC Wildfire 手机,在 zh_CN locale 时完美汉化,根本不用刷 ROM。

  • Windows XP cannot acquire a valid IP address from DHCP server

    最近碰到一台 Windows XP 无法获得 DHCP 服务器分配的 IP 地址,但若指定 IP 地址则能上网 。辗转好久才找到解决办法:

    首先检查 Services 里 DHCP Client 是否启动;

    其次试着运行 netsh winsock reset /catalog ——我也不清楚这干嘛用的。

    最后重启一下 Windows XP 就能获得 DHCP 服务器分配的地址。

  • Best practices of merging multiple Gmail accounts

    工作需要对外使用多个邮箱,但阅读邮件时又不希望登录多个邮箱,而是希望在单一邮箱里查看和回复邮件。现以在邮箱A查看和回复来自邮箱B的邮件为例讲解设置。

    首先,登录邮箱B,在 Mail settings >> Filters 里 Create a new filter,在 “Doesn’t have” 一栏里填入长串不可能用到的乱字符,如 “J6dPFVFwnCsSBezVfSqRY5JTLNL567Ef”,然后点 “Next step”,选中 “Never send it to Spam“,最后点 “Create Filter”。这避免一些重要邮件被误判为 Spam,留在了邮箱B,不登录就查看不到,会误事。接着,还是在  Mail settings >> Forwarding and POP/IMAP 里 Add a forwarding address,填入邮箱A,follow instructions,不详述。

    然后,登录邮箱A,在 Mail settings >> Accounts >> Send mail as 里 Add another email address you own,填入 Name:whatever 和 Email address:邮箱B,然后点 “Next step”,选中 “Send through 邮箱B SMTP servers”,按 Gmail SMTP 配置去填写 SMTP Server, Username 和 Password,最后点 “Add Account“。

    大功告成。多罗嗦一句,不用邮箱A去POP邮箱B的方法来合并邮件是因为 Gmail 最多允许 POP 5个 accounts,无法合并6个以上邮箱;而且 POP 收取邮件没有从邮箱A转发过来即时。

  • 小美再加一个字

    女儿上学回家跟我说,老师这么称呼她:小美再加一个字
    ——人。

    然后作羞涩状。