Author: 芳草苑主

  • Comparison in PHP

    除非使用 === 或 !== 进行比较,PHP 尽可能地将值转化为数字进行比较。因此,看到比较 “10” == “1e1” 的结果是 true,千万不要大惊小怪。

    “尽可能”如何理解?

    1. 如果等式一边是数字,另一边是字符串,那么字符串一定要 cast to int 后再比较。因此,比较 “10” == 1e1 的结果是 true,比较 “10 ” == 1e1 的结果也是 true。
    2. 如果等式两边都是字符串,且字符串中均不含数学字符以外的字符(包括white space),那么两边的字符串会在 cast to int 后再比较;否则,直接比较字符串。因此,比较 “10” == “1e1” 的结果是 true,但比较 “10 ” == “1e1” 的结果是 false。
    3. 如果等式有一边或两边是数组,则先比较数组结构是否相同,再逐个比较数组元素。在比较数组元素时,索引不会 cast,但值按上述两条规则“尽可能” cast。因此,比较 1 == array(1) 的结果是 false,比较 array(“10”) == array(“1e1”) 的结果是 true,比较 array(10 => 10) == array(“1e1” => 10) 的结果是 false。
  • Paypal vs PaypalUk in Magento

    Magento 里有两个有关 Paypal 支付的模块:Paypal and PaypalUk。我尚未查到文档有关它们的区别,只知道 PaypalUK 依赖于 Paypal,在同时启用 Paypal and PaypalUk 时,后台可以看到

    Configuration Paypal section when PaypalUk is enabled
    Configuration Paypal section when PaypalUk is enabled

    Configuration Payment Methods section when PaypalUk is enabled
    Configuration Payment Methods section when PaypalUk is enabled

    若不启用 PaypalUk 模块,后台变成:

    Configuration Paypal section when PaypalUk is disabled
    Configuration Paypal section when PaypalUk is disabled

    Configuration Payment Methods section when PaypalUk is disabled
    Configuration Payment Methods section when PaypalUk is disabled

    对比可见后台多了 Payflow Edition,估计 PaypalUk 是面向开发者的称呼,Payflow 是面向普通用户的称呼。更多区别还有待摸索。

  • OpenPassword

    Inspired by OpenId, I want to start a project – OpenPassword.

    What is it for?
    People are hesitate to register themselves from site to site. One of the reasons is people are afraid of giving password to the web sites they do not trust much. Most people do not have big memory, so they have to use the same password for all web sites. They may or may not aware that any webmaster / web owner who has access to the password database could try the same password on other sites (or even worse – for online banking). Whether people’s passwords are in safe depends on how honest the webmaster / web owner is. Even the webmaster / web owner is honest, does he have basic skills to keep password in safe? I see a lot of web sites save passwords unencrypted, which could be a disaster.

    OpenId comes to solve this problem. But currently not all web sites support OpenId. What if you are in a position you have to use some web sites which do not support OpenId? You have to take care of security yourself. My proposal is:

    1. You register different web sites with different passwords.
    2. The passwords are generated with one-way encryption.
    3. You host encryption algorithm and salt in a safe place, so you do not need remember the passwords. Every time you need them, you generate / retrieve them on the fly.
  • Dispatched events on a simple Magento homepage

    每访问一次我一个并不复杂的 Magento 站点主页,将会触发多少个事件?我记了下来:


    resource_get_tablename

    resource_get_tablename

    resource_get_tablename

    core_collection_abstract_load_before

    core_collection_abstract_load_after

    core_collection_abstract_load_before

    core_collection_abstract_load_after

    core_collection_abstract_load_before

    core_collection_abstract_load_after

    controller_front_init_before

    controller_front_init_routers

    resource_get_tablename

    resource_get_tablename

    model_load_after

    core_abstract_load_after

    resource_get_tablename

    core_locale_set_locale

    controller_action_predispatch

    controller_action_predispatch_cms

    controller_action_predispatch_cms_index_index

    resource_get_tablename

    resource_get_tablename

    model_load_after

    cms_page_load_after

    resource_get_tablename

    model_load_after

    core_abstract_load_after

    cms_page_render

    controller_action_layout_load_before

    customer_session_init

    resource_get_tablename

    model_load_after

    core_abstract_load_after

    resource_get_tablename

    controller_action_layout_generate_xml_before

    controller_action_layout_generate_blocks_before

    core_block_abstract_prepare_layout_before

    core_block_abstract_prepare_layout_after

    core_block_abstract_prepare_layout_before

    core_block_abstract_prepare_layout_after

    core_block_abstract_prepare_layout_before

    core_block_abstract_prepare_layout_after

    core_block_abstract_prepare_layout_before

    core_block_abstract_prepare_layout_after

    core_block_abstract_prepare_layout_before

    core_block_abstract_prepare_layout_after

    core_block_abstract_prepare_layout_before

    core_block_abstract_prepare_layout_after

    core_block_abstract_prepare_layout_before

    core_block_abstract_prepare_layout_after

    core_block_abstract_prepare_layout_before

    core_block_abstract_prepare_layout_after

    core_block_abstract_prepare_layout_before

    core_block_abstract_prepare_layout_after

    core_block_abstract_prepare_layout_before

    core_block_abstract_prepare_layout_after

    core_block_abstract_prepare_layout_before

    core_block_abstract_prepare_layout_after

    core_block_abstract_prepare_layout_before

    core_block_abstract_prepare_layout_after

    core_block_abstract_prepare_layout_before

    core_block_abstract_prepare_layout_after

    core_block_abstract_prepare_layout_before

    core_block_abstract_prepare_layout_after

    core_block_abstract_prepare_layout_before

    core_block_abstract_prepare_layout_after

    core_block_abstract_prepare_layout_before

    core_block_abstract_prepare_layout_after

    core_block_abstract_prepare_layout_before

    core_block_abstract_prepare_layout_after

    core_block_abstract_prepare_layout_before

    core_block_abstract_prepare_layout_after

    core_block_abstract_prepare_layout_before

    core_block_abstract_prepare_layout_after

    core_block_abstract_prepare_layout_before

    core_block_abstract_prepare_layout_after

    core_block_abstract_prepare_layout_before

    core_block_abstract_prepare_layout_after

    core_block_abstract_prepare_layout_before

    core_block_abstract_prepare_layout_after

    core_block_abstract_prepare_layout_before

    core_block_abstract_prepare_layout_after

    core_block_abstract_prepare_layout_before

    core_block_abstract_prepare_layout_after

    core_block_abstract_prepare_layout_before

    core_block_abstract_prepare_layout_after

    core_block_abstract_prepare_layout_before

    core_block_abstract_prepare_layout_after

    core_block_abstract_prepare_layout_before

    core_block_abstract_prepare_layout_after

    core_block_abstract_prepare_layout_before

    core_block_abstract_prepare_layout_after

    resource_get_tablename

    resource_get_tablename

    core_block_abstract_prepare_layout_before

    core_block_abstract_prepare_layout_after

    core_block_abstract_prepare_layout_before

    core_block_abstract_prepare_layout_after

    core_block_abstract_prepare_layout_before

    core_block_abstract_prepare_layout_after

    core_block_abstract_prepare_layout_before

    core_block_abstract_prepare_layout_after

    core_block_abstract_prepare_layout_before

    core_block_abstract_prepare_layout_after

    core_block_abstract_prepare_layout_before

    core_block_abstract_prepare_layout_after

    core_block_abstract_prepare_layout_before

    core_block_abstract_prepare_layout_after

    core_block_abstract_prepare_layout_before

    core_block_abstract_prepare_layout_after

    core_block_abstract_prepare_layout_before

    core_block_abstract_prepare_layout_after

    core_block_abstract_prepare_layout_before

    core_block_abstract_prepare_layout_after

    core_block_abstract_prepare_layout_before

    core_block_abstract_prepare_layout_after

    core_block_abstract_prepare_layout_before

    core_block_abstract_prepare_layout_after

    core_block_abstract_prepare_layout_before

    core_block_abstract_prepare_layout_after

    core_block_abstract_prepare_layout_before

    core_block_abstract_prepare_layout_after

    core_block_abstract_prepare_layout_before

    core_block_abstract_prepare_layout_after

    core_block_abstract_prepare_layout_before

    core_block_abstract_prepare_layout_after

    core_block_abstract_prepare_layout_before

    core_block_abstract_prepare_layout_after

    controller_action_layout_generate_blocks_after

    controller_action_layout_render_before

    controller_action_layout_render_before_cms_index_index

    core_block_abstract_to_html_before

    core_block_abstract_to_html_before

    core_block_abstract_to_html_before

    core_block_abstract_to_html_after

    core_block_abstract_to_html_before

    core_block_abstract_to_html_after

    core_block_abstract_to_html_after

    core_block_abstract_to_html_before

    core_block_abstract_to_html_before

    core_block_abstract_to_html_after

    core_block_abstract_to_html_after

    core_block_abstract_to_html_before

    core_block_abstract_to_html_after

    core_block_abstract_to_html_before

    core_block_abstract_to_html_after

    core_block_abstract_to_html_before

    core_block_abstract_to_html_after

    core_block_abstract_to_html_before

    core_block_abstract_to_html_after

    core_block_abstract_to_html_before

    core_block_abstract_to_html_before

    core_block_abstract_to_html_after

    core_block_abstract_to_html_before

    core_block_abstract_to_html_before

    core_block_abstract_prepare_layout_before

    core_block_abstract_prepare_layout_after

    core_block_abstract_to_html_before

    core_block_abstract_to_html_after

    core_block_abstract_prepare_layout_before

    core_block_abstract_prepare_layout_after

    core_block_abstract_to_html_before

    model_load_after

    core_abstract_load_after

    resource_get_tablename

    resource_get_tablename

    resource_get_tablename

    resource_get_tablename

    resource_get_tablename

    resource_get_tablename

    resource_get_tablename

    resource_get_tablename

    eav_collection_abstract_load_before

    catalog_product_collection_load_before

    resource_get_tablename

    model_load_after

    catalog_entity_attribute_load_after

    model_load_after

    catalog_entity_attribute_load_after

    model_load_after

    catalog_entity_attribute_load_after

    model_load_after

    catalog_entity_attribute_load_after

    catalog_product_collection_load_after

    resource_get_tablename

    resource_get_tablename

    resource_get_tablename

    resource_get_tablename

    resource_get_tablename

    model_load_after

    customer_load_after

    resource_get_tablename

    model_load_after

    core_abstract_load_after

    model_load_after

    core_abstract_load_after

    model_load_after

    core_abstract_load_after

    model_load_after

    core_abstract_load_after

    model_load_after

    core_abstract_load_after

    model_load_after

    core_abstract_load_after

    model_load_after

    core_abstract_load_after

    model_load_after

    core_abstract_load_after

    model_load_after

    core_abstract_load_after

    model_load_after

    core_abstract_load_after

    model_load_after

    core_abstract_load_after

    model_load_after

    core_abstract_load_after

    model_load_after

    core_abstract_load_after

    model_load_after

    core_abstract_load_after

    model_load_after

    core_abstract_load_after

    model_load_after

    core_abstract_load_after

    core_block_abstract_to_html_after

    core_block_abstract_to_html_after

    core_block_abstract_to_html_after

    core_block_abstract_to_html_after

    core_block_abstract_to_html_before

    core_block_abstract_to_html_before

    resource_get_tablename

    resource_get_tablename

    resource_get_tablename

    core_collection_abstract_load_before

    core_collection_abstract_load_after

    core_block_abstract_to_html_after

    core_block_abstract_to_html_before

    resource_get_tablename

    resource_get_tablename

    model_load_after

    core_abstract_load_after

    core_block_abstract_prepare_layout_before

    core_block_abstract_prepare_layout_after

    core_block_abstract_to_html_before

    core_block_abstract_to_html_after

    core_block_abstract_to_html_after

    core_block_abstract_to_html_before

    model_load_after

    core_abstract_load_after

    core_block_abstract_to_html_after

    core_block_abstract_to_html_before

    model_load_after

    core_abstract_load_after

    core_block_abstract_to_html_after

    core_block_abstract_to_html_after

    core_block_abstract_to_html_before

    core_block_abstract_to_html_before

    resource_get_tablename

    model_load_after

    sales_quote_load_after

    resource_get_tablename

    model_load_after

    customer_group_load_after

    resource_get_tablename

    core_collection_abstract_load_before

    core_collection_abstract_load_after

    resource_get_tablename

    core_collection_abstract_load_before

    core_collection_abstract_load_after

    resource_get_tablename

    resource_get_tablename

    eav_collection_abstract_load_before

    catalog_product_collection_load_before

    catalog_product_collection_load_after

    resource_get_tablename

    resource_get_tablename

    resource_get_tablename

    resource_get_tablename

    core_collection_abstract_load_before

    core_collection_abstract_load_after

    resource_get_tablename

    sales_quote_item_collection_products_after_load

    resource_get_tablename

    resource_get_tablename

    resource_get_tablename

    core_collection_abstract_load_before

    core_collection_abstract_load_after

    resource_get_tablename

    resource_get_tablename

    eav_collection_abstract_load_before

    catalog_product_collection_load_before

    catalog_product_collection_load_after

    resource_get_tablename

    resource_get_tablename

    resource_get_tablename

    eav_collection_abstract_load_before

    catalog_product_collection_load_before

    catalog_product_collection_load_after

    resource_get_tablename

    resource_get_tablename

    resource_get_tablename

    eav_collection_abstract_load_before

    catalog_product_collection_load_before

    catalog_product_collection_load_after

    resource_get_tablename

    resource_get_tablename

    resource_get_tablename

    eav_collection_abstract_load_before

    catalog_product_collection_load_before

    catalog_product_collection_load_after

    resource_get_tablename

    resource_get_tablename

    resource_get_tablename

    eav_collection_abstract_load_before

    catalog_product_collection_load_before

    catalog_product_collection_load_after

    resource_get_tablename

    resource_get_tablename

    resource_get_tablename

    eav_collection_abstract_load_before

    catalog_product_collection_load_before

    catalog_product_collection_load_after

    resource_get_tablename

    sales_quote_item_set_product

    sales_quote_item_qty_set_after

    resource_get_tablename

    core_collection_abstract_load_before

    core_collection_abstract_load_after

    resource_get_tablename

    core_block_abstract_to_html_after

    core_block_abstract_to_html_before

    core_block_abstract_to_html_after

    core_block_abstract_to_html_before

    core_block_abstract_to_html_after

    core_block_abstract_to_html_before

    core_block_abstract_to_html_after

    core_block_abstract_to_html_before

    model_load_after

    core_abstract_load_after

    core_block_abstract_to_html_after

    core_block_abstract_to_html_after

    core_block_abstract_to_html_before

    core_block_abstract_to_html_after

    core_block_abstract_to_html_before

    core_block_abstract_to_html_before

    core_block_abstract_to_html_after

    core_block_abstract_to_html_before

    core_block_abstract_to_html_after

    core_block_abstract_to_html_after

    core_block_abstract_to_html_after

    core_block_abstract_to_html_before

    core_block_abstract_to_html_after

    controller_action_postdispatch_cms_index_index

    controller_action_postdispatch_cms

    controller_action_postdispatch

    model_save_before

    core_abstract_save_before

    resource_get_tablename

    resource_get_tablename

    resource_get_tablename

    model_save_after

    core_abstract_save_after

    model_save_commit_after

    core_abstract_save_commit_after

    http_response_send_before

    controller_front_send_response_after

  • My location powered by Google Latitude

    最近一个月被 3G 电到了!3G 很强大,但以前我不知道它可以这么强大,而且它如此轻易地就渗入了生活——仅仅是因为我换了个手机(还不是冲着 3G 去换的)。

    3G 所实现的功能非要在 3G 上运行吗?当然不是。但是,它已经运行地如此完美,何必再想其他招?我现在上 YouTube 都会捧着手机上,更别说 email, instant message, streaming media, etc, etc.

    展示一下我的实时方位吧——只要我的手机开着,你就可以知道我在哪里!你手头不会有精确制导导弹吧?否则我就糟了。

    最后我想说,去买 3G 概念股吧,3G 应用前途无量。只要跟 3G 有关的都可以买,生产 3G 手机的也好,交换机的也好…

  • No way to control inline elements’ height

    今天在 css 里遇上一个以前不曾注意的细节:
    假设<a>和<img>的 border, margin 和 padding均为0,一个被<a> wrapped 的 <img> (<a><img/></a>) 比单独一个 <img/> 在 Firefox 中 render 要高 3px,在 chrome 和 ie 下也会高一些(但我未测量数值)。

    实例代码

    
    <style type="text/css">
    a { text-decoration:none; }
    a, img { border:0; padding:0; margin:0; }
    .col-1 { float:left; text-align:right; width:49%; }
    .col-2 { float:right; text-align:left; width:49%; }
    .line { height:1px; border-top:1px solid orange; }
    </style>
    
    <div class='col-set'>
    <div class='col-1'>
    <a href="#">
    <img src="not-lineup.jpg"/>
    </a>
    <div class='line'>&nbsp;</div>
    </div>
    <div class='col-2'>
    <img src="not-lineup.jpg"/>
    <div class='line'>&nbsp;</div>
    </div>
    </div>
    
    
    Inline elements 不等高实例截图
    Inline elements 不等高实例截图

    我想了很久才知道这都是因为<a>和<img>是inline elements。Inline elements 有一些特性

    • they flow with text.
    • they have line-height.
    • the element height and width is dependent on the content and will not collapse to the borders of the parent element.

    Inline elements 没有 height,在上例中也无法用 line-height 去控制高度:<a>的底部与<img>的底部有 3px 间距,我试遍我能想到的所有 css 属性都无法消除这个间距,除非——

    将<a>设为display:block!Block elements 的 border, margin 和 padding 都是有效的,控制高度就不是问题了。

  • Manage magento catalog images on the local server

    Magento 的 Image / Media / Gallery 模型非常好用,可以迅速在全站范围内调整输出图片的尺寸。如果用户习惯于用上传图片的方式管理图片库,他会觉得 Magento 很方便。Magento 自动把上传的图片保存到 media/catalog/product/(文件名首字母)/(文件名第二字母)/(文件名或拖尾_1, _2, … 以防重名)。

    在产品库初建时,要输入大量的图片路径。虽然 product import dataflow 也很好用,但图片的保存位置规则跟上传时一样,我觉得不够好。因为:

    1. 原始图片是静态文件,可以独立于 Magento,存放在服务器的某个本地路径,也方便共享给其他程序使用;
    2. 如果 Magento 自行保存图片,浪费了服务器空间(对我来说,这倒没什么,服务器上空了好几百 G),而且按 media/catalog/product/(文件名首字母)/(文件名第二字母)/(文件名或拖尾_1, _2, … 以防重名) 去查找图片非常不方便,产品图片理应按 category 归入各个子目录。

    所以,我想把 Magento 的 Image / Media / Gallery 模型改进一下,做到:

    1. 原始图片存放于 static_file_server/catalog/product/category_1/subcategory_1/image_name。
    2. Magento 不保存原始图片,只要记牢原始图片在服务器上的某个位置。
    3. 喜欢 upload 的用户仍可以使用 upload,但为喜欢 ftp / ssh 的用户增加指定 local path 的功能。
    4. import product 接受 local_path。
    5. Magento 缓存图片的机制不变。
  • How magento deducts stock level

    我心里一直有个疑问,收到订单后,Magento 是怎么更新库存数量的?是直接用一个新库存数字去更新,还是用 upadte magento_cataloginventory_stock_item set qty=qty-qty_ordered 之类的办法。

    通过跟踪 sql 语句,我感觉前者的可能性很大。

    UPDATE `magento_cataloginventory_stock_item` SET `item_id` = '125', `product_id` = '125', `stock_id` = '1', `qty` = '93.000000', `min_qty` = '0.000000', `use_config_min_qty` = '1', `is_qty_decimal` = '0', `backorders` = '1', `use_config_backorders` = '0', `min_sale_qty` = '1.000000', `use_config_min_sale_qty` = '1', `max_sale_qty` = '0.000000', `use_config_max_sale_qty` = '1', `is_in_stock` = '1', `low_stock_date` = NULL, `notify_stock_qty` = '0.000000', `use_config_notify_stock_qty` = '1', `manage_stock` = '1', `use_config_manage_stock` = '0', `stock_status_changed_automatically` = '0', `shelf` = '' WHERE (item_id='125')
    

    这样很不好,如果几个人同时买同一个产品,会搞乱库存数。不知道被破坏的几率有多大,有空要搞一个并发下单的测试。

  • I am with Android

    出于对 google 技术的无限喜爱,我就在 android 手机里挑了一款 motorola dext,升级了我的手机。

    但是,我已经老了,新手机刚到手,摆弄了几下,明知道有很多新鲜的功能等我去发掘,已没有了新鲜劲。我只是把联系人、email、wifi 设置了一下,就丢开她了——我是不是老了?

    尽管如此,我已有感觉,这是一款非常非常 open and user friendly 的手机,比 iphone 强多了。电池不经用?跟 android 带来的强烈享受相比,瑕不掩瑜——毕竟电池不是 google 挑的。

  • Tag everything

    在管理文件时,我经常碰到这样一个问题:目前树形结构的文件系统,一个文件只能放在一个地方,决定了它只能被单维度管理。虽然有软连接、硬连接、快捷方式辅助,还是非常不方便:要去多个目录下建立连接就费时费力,而且目标文件移动了位置,这些连接统统都失效。多维度的文件管理,我能想到的办法就是用类似于数据库的技术,具体而言:

    1. 一个文件就是一条记录。
    2. 套用 EAV 模型,让用户可以自定义属性,称之为 attribute 也好,tag 也好,都是为了归类文件。
    3. 用属性的排列组合去过滤出想要找的文件集(inspired by Magento’s Grid),如果文件集过大,一次也不用全都显示出来,免得过度消耗资源,一次显示 20-50 个文件足矣。用户可以选择设置更多的属性进行深度过滤,或翻页浏览。以我的眼力,如果在超过50条记录的一屏里找一条记录,就有烦躁情绪,来回扫描还经常漏过那条记录。这就是“过多的信息就是没有信息”的道理,所以定义适合自己的过滤条件去找文件集才是王道。
    4. 用户浏览传统树形结构的文件系统,但浏览模式在新的文件系统中并不好用,必须配合过滤。其实层层浏览和过滤是异曲同工,只是后者更灵活,但需要更多操作键盘甚于鼠标。如果一个上网用户喜欢浏览多于搜索,他通常觉得鼠标比键盘好用,那么他可以自定义 view,即把常用的过滤条件保存下来,减少键盘操作。搜索模式得以保留,能搜索过滤前或过滤后的结果。

    其实 tag 化的文件管理系统已经有了很多,比如相片管理、视频管理、MP3管理、电子书籍管理等等。但这些系统都自称一套体系,没有可移植性,比如,不能把一组相片连同 tag 信息传输给别人(除非把相片管理系统也传输给别人)。我想要的是在 OS 文件系统层得到支持的 tag 存储,或者是根植于 Nautilus / windows explorer 的 tag 操作。有了她,相片管理系统、视频管理系统、MP3管理系统、电子书籍管理系统统统都没有销路了。

    其实 Google docs 就是这个干的,如果能应用到本地就好了。

    tag2find 基本可以实现我想要功能,但这个软件看上去不够大气,又只支持 windows,也非根植于 windows explorer,所以不足以打动我。