Blog

  • I have a longer history with Fedora

    今天拿出一张多年不用的 DVD-RW,想擦了上面的内容做一张服务器的启动盘(因为 HP ML110 G7 被我折腾了几次以后不肯在 USB 上启动,不知道为什么)。无意中发现上面的内容竟然是 Fedora 6 DVD,那时还叫 Fedora Core 6(后来就没 Core),年份是 2007 年。

    看来我跟 Fedora 的渊源在我没有意识到她是 Fedora 的时候已经开始了。我意识地使用 Fedora 是在她的第 9 版。

  • Back from NCL cruise

    day-01-embark-jade

    Image 1 of 30


    平生第一次坐游轮旅游。第一次坐的就是个 Norwegian 公司的大游轮 Jade ——排水量 93,000 吨,沿途只见我这只就是最大的。读 Norweigian 船队介绍,只有 Epic 比 Jade 更大,有 155,000 吨。

    旅行 10 天,Gatwick 飞 Rome,小巴接到 Civitavecchia, Italy (Rome 附近港口),上船;第二天在海上飘;第三天停靠 Katakolon, Greece,附近有 Olympia;第四天停靠 Piraeus, Greece, 附近有 Athens;第五天停靠 Izmir, Turkey,附近有 Ephesus,不过我们没去;第六天停靠 Istanbul, Turkey;第七天傍晚才离开 Istanbul, Turkey;第八天、第九天一直在海上飘;第十天停靠 Naples, Italy,附近有 Pompeii 和 Sorrento;第十一天返回 Civitavecchia, Italy,再由小巴接回 Rome 机场,飞 Gatwick。

    沿途景色很美,但说实话,我们住在 Brighton,大海也是天天见,所以对海景有点审美疲劳。加上 Cruise 不能深度游,我总觉得不尽兴。另外,旅游经验不足,多花费了很多钱。

    首先,船上卖 Wi-Fi 上网时间,250 分钟 100 美元。其实船上发射美国的 GSM 信号(船东是美国的),能用它 3G 或 4G 上网,如果有一张美国的 SIM 卡,就和在美国本土使用一样。似乎靠岸时船上的 GSM 信号是关闭的,我的 Orange 手机不断交替地收到 “You are using data in USA”, “You are using data in Europe” 的提示,最初搞得我莫名其妙——我明明在地中海,怎么说我到美国了?思考了好久问了船员才明白。所以,下次得带美国的 SIM 卡去坐美国游轮。

    其次,发达国家货币兑换处汇率极差,用抢钱来形容也不为过,本币/外币一卖再一买,一个来回约 12% 就没了,而在中国一个回来损失不到 0.25%。我出发前没有准备欧元,想去下一个国家碰碰运气,结果在意大利机场兑换处一看,跟英国一样地抢钱,又忍着不换。到了希腊,更糟,因为一时找不到正规的兑换处,在一个小店兑换,100 镑才换得 110 欧元,边上有个英国游客,跟我说,这个汇率在这种小店已经算很好了,他出发前在英国兑换汇率也只是 1:1.20。我无语,当时招商银行的汇率应该是在 1:1.22 以上。到了土耳其,我终于见到了我认为合理的汇率。发达国家的金融业通常高度发达,但普通的货币兑换却是如此落后。

    再次,如果目的国兑换处不能提供好的汇率,可以找 ATM 直接取现。我的 Visa Debit 卡每次取现、消费都被收取 £1.50 手续费,但汇率是相对合理的。如果单笔金额大,还是合算的。

  • Favicon Controller in Msdk

    昨晚在 Magento 里写了个 FaviconController.php,是为了解决 Magento 根目录下的 favicon.ico 静态文件无法根据多网店不同的 favicon.ico 而变化。

    Magento 有支持多网店多 favicon.ico,但直接访问 example1.com/favicon.ico 和 example2.com/favicon.ico 怎么回应不同的 favicon.ico?我是把静态文件删了,由 FaviconController.php 读取 SystemConfig 从 media 或 skin 目录里读出相应的 favicon.ico,响应 /favicon.ico 的请求。

    逻辑很简单,我调试好了以后决定把这个功能归于我的 Msdk 模块,可是天黑眼花,竟然塞错进了另一个不相干的 Misc 模块,于是怎么看 /favicon.ico 都是 404 Error。这事折腾了有2个小时才发现错误所在。我痛下决心,要把 Misc 模块改个名。

    P.S. Msdk 模块是免费的。下次发布新版大家就会看到 FaviconController.php 了。

  • Using Nivo Slider with Prototype

    我想要一个 jQuery slider plugin 用在 Magento 上。jQuery slider 类不乏优秀的程序。我不及精挑细选,用了 Nivo Slider。

    虽然 slider 能运行,但 FireBug 停止响应。查错发现 too much recursion occured in prototype.js 1132 行。自然想到了 jQuery 和 Prototype 的 conflict,但我有做 noConflict.js,而且 jquery.nivo.slider.js 也没有在全局使用 $,看上去挺规范的呀。

    我让 Magento 暂不加载 prototype.js,too much recursion 错误就没有了,但 Magento 不能没有 prototype.js (盼望 Magento 哪天自动放弃 prototype,用 jQuery 重写)。

    我有意放弃 Nivo Slider,无意中又发现别人竟做过同样的事情——把 Nivo Slider 用在Magento 下,而且没有 javascript 错误。

    我以为是我那段 slider 的 html 写得不好,全盘拷了别人的来用,还是出错。然后我认为是版本问题,可是用别人的 jQuery 库,放在我这里,还是出错。

    最后,直到最后,我意识到一点不同之处,我用不带任何参数启动 Nivo Slider,即

    $('#slider').nivoSlider();
    

    而别人用

    	$('#slider').nivoSlider({
            effect: 'sliceDown', 
            slices: 15, 
           
            animSpeed: 500, 
            pauseTime: 3000, 
            startSlide: 0, 
    		 
            directionNav: true, 
    		        directionNavHide: true, 
    		        controlNav: true, 
                    keyboardNav: true, 
    		        pauseOnHover: true, 
                    captionOpacity: 1, 
            prevText: 'Prev', 
            nextText: 'Next' 
           
        });
    

    就这点造成了 too much recursion。

  • Play with WD MybookWorld

    先说一下我所了解的此网络硬盘的习性:

    • 首先,它在创建用户时,并不创建同名组。
    • 其次,创建用户时,会问及是否创建 User Private Share。User Private Share 是 samba 用的一个名词,我觉得很难理解:既然是 Private,何来 Share?就叫 User Home Directory 更好一些。
    • 再次,删除用户时, User Private Share 并不随之删除,在 Folder Shares 界面里才能删除它。我试过以 root 身份执行 rm 都说“device busy”。

    什么情况下需要共享?最初我想按人分,一类是平级共享,比如同一组织内两个人共事,他们可以相互访问对方的文件;另一类是分级共享,比如上级可以访问下级的文件,而反之不能。后来情况变复杂了:甲要访问乙的部分文件,乙也要访问甲的部分文件,同时甲又给丙共享另一部分文件……所以最后我按文件类别分,某类文件要给哪几个人权限,思路就很清楚了。

  • Can’t retrieve entity config: core/store_group

    老版本的 Magento (1.3.2.3) 跑在新版本的 php (5.4.3) 上有个问题:

    Can't retrieve entity config: core/store_group

    这问题有点莫名其妙,最后发现是因为 SimpleXML 这个库太老了,在新版本的 php 下无法处理 Magento 的一些 xml 文件,所以出错。

    从新版本的 Magento (1.7.0.0) 里拷贝出 lib/Varien/SimpleXML 覆盖原文件就好了。

  • Export VirtualBox snapshots

    我觉得挺奇怪的 —— VirtualBox 怎么不弄个一键连同快照导出虚拟机的功能?这功能应该很有用。

    网上搜了一圈,也没人给个系统的指导。没办法,只好自己摸索着做。其实,导出快照没我想的那么复杂,也就是拷贝和修改一下配置文件。具体步骤是:

    1. 从源机拷出某个虚拟机的整个目录。
    2. 在目标机器上创建跟源虚拟机一样配置的新虚拟机。
    3. 把拷出的目录里所有文件放到新虚拟机所在的目录。用源虚拟机的硬盘文件覆盖新虚拟机的硬盘文件,同时有个 Name_Of_Vbox.vbox 的文件也被覆盖。.vbox 有快照文件们的树形结构信息及所在位置的信息。快件文件在 Snapshots 子目录下, .vbox 里存储的是相对位置,在新虚拟机里仍然使用。.vbox 是个 xml 格式的文件,不妨打开来看一下,里面还有一个 machine uuid,把它拷出来。
    4. 打开 VirtualBox.xml,它是 VirtualBox 的配置文件,在 Fedora 下它保存在 ~/.VirtualBox/ 目录下,新建的虚拟机的 machine uuid 和源虚拟机的 machine uuid 通常是不匹配的,那就用刚刚从 .vbox 里拷出来的 machine uuid 替换。

    这样源虚拟机连同快照文件就迁移到目标机器上了。这时尝试启动虚拟机或许会提示如虚拟网卡不存在之类的错误,一般是因为源机和目标机器环境不一致或所用 VirtualBox 版本不一致所引起的,问题不大,只要重新给虚拟机一张虚拟网卡就行了。

  • Solve Google Drive Sync installation 1603 error

    我不太用Windows,最近却玩得比较多,没办法呀,谁让 Google Drive Sync for Linux 还没问世。

    在安装 Google Drive Sync 时碰到 1603 错误,最后发现要先装 Microsoft Visual C++ 2008 SP1 Redistributable Package。还有人说一定要装 2008 版,我不信邪,先装了个 Microsoft Visual C++ 2010 SP1 Redistributable Package,果然还是出错。再装一个 2008,就 OK 了。

  • 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 直接使用指定的大图、小图和缩略图,这里不再多述。