• Zend Translate的使用和设置

    Posted on 九月 30th, 2008 inetdemon No comments

    Zend Translate的功能不错, 我们使用gettext格式作为我们翻译文件的标准格式,使用POEditor维护翻译文件,处理后的gettext文件是二进制的mo文件. 我们使用ZF的根据目录名(LOCALE_DIRECTORY)自动搜索相关译文功能,同时使用根据mo文件更新的cache提高速度,为了设置translate功能,我们在bootstrap文件有如下代码
    $cache = Zend_Cache::factory('Page','File',$frontendOptions,$backendOptions);
    Zend_Translate::setCache($cache);
    $translate = new Zend_Translate('gettext','../data/locales/','zh',array(
        'scan' =>Zend_Translate::LOCALE_DIRECTORY
    ));
    $translate->setLocale('auto');
    Zend_Registry::set('Zend_Translate', $adapter);
    Zend_Form::setDefaultTranslator($translate);

    注意:在保存到 Zend_Registry 中时,键值必须是 Zend_Translate,否则,得不到应有的结果。

    其中,‘scan’ =>Zend_Translate::LOCALE_DIRECTORY设定ZF在指定目录下搜索翻译mo文件。我们的目录结构为:
    application
    ...
    data
      ...
      locales
        en
        de
        fr
        zh
    ...

    在ZF的Document中有一个Example,要求设置’auto’格式:
    $translate = new Zend_Translate('gettext','path','auto',array('scan' =>Zend_Translate::LOCALE_DIRECTORY));

    但是事实上根据我在ZF1.52, 1.6, 1.61中测试,这个代码是有bug的, ‘auto’并不能正确将用户浏览器语言设置为当前语言,而是将最后一个读到的文件设置为默认Locale, 这点从ZF1.61的代码中Zend_Translate_Adapter::addTranslation函数中可以看到。

    我们是怎么解决的呢,很简单,第一次读取时设置语言为’zh’, 然后立即设定默认locale为’auto’

  • PO Editor的使用和配置

    Posted on 九月 30th, 2008 inetdemon No comments

    Zend Framework 的translate支持多种格式的翻译文件,从小型项目使用的ini文件,到专业项目使用的tmx, gettext等。google了一下,似乎linux下的gettext速度最快,编译的结果是binary格式的,于是选择了gettext格式。有个很多工具可以用来维护gettext格式,比较有名的有免费的PO Editor下载。这个PO Editor的好处是可以自动搜索某一目录下代码中所有的代码文件中需要翻译的字符串。PHP下如何设置POEditor,对于我们的项目,在”类目”->”设置”下

    1. 选择”路径”,将基本路径(basedir)设为d:/xampp/audit/,新建路径”application”;

    2. 选择”关键字”,我设置两个,一个是zf默认的translate函数关键字,一个是setlabel用于form的翻译;

    3. 还有很关键的一点,修改配置抓取phtml中的关键字:文件->首选->解析器->选择php后->编辑,将扩展名改为:”*.php;*.phtml”,将解析器命令改为:”xgettext –force-po -o %o %C %K %F -L php”;

    4. 现在开始可以自动搜索代码中的翻译文件了。

  • 关于BOM头

    Posted on 九月 26th, 2008 inetdemon No comments

    要命的BOM头让我吃了两次亏,每次都是莫名奇妙地花了1,2天才找出问题。
    第一次是:写ZF的errorControler设置404返回值的时候报错:
    Cannot modify header information - headers already sent
    检查了那个有名的ZF最后一个结束符不写的问题和setRawHeader的代码,都找不出症结所在,后来发现是BOM头捣鬼。
    今天又碰到这个问题,导入系统一个excel文件,老有错,仔细检查是第一行含有bom头,所以数据老是读错,害我花了半天的时间找问题。

    在Windows下用记事本之类的程序将文本文件保存为UTF-8格式时,记事本会在文件头前面加上几个不可见的字符(EF BB BF),就是所谓的BOM(Byte order Mark)。

    php4/5会视BOM为一般字符输出(这是一个不可见字符),因此会出现这个header already sent的问题。应该说这是一个php的bug(22108, 42312),可喜的是,php6宣传已经没有这个问题,而在php4/5下,有两个方法可以解决这一问题:
    方法一,可以在保存文件的时候设置不使用BOM头格式的UTF8文件。
    dreamweaver设置如下:

    UltraEdit可以设置(Configuration-> File Handling -> Save -> Write UTF-8 BOM header),
    也可以直接修改C:\Windows\UEdit32.ini,增加以下两行设置
    Write UTF-8 BOM=0
    Write UTF-8 BOM NF=0

    此外HTML代码中的codepage及charset也必须要设定,以保证编码方式正确。

    方法二,以上方式可以解决自己写的代码,却不能解决用户上传的文件。这种情况下,需要在服务器端判断文件头,并截取相应的三个字符(0xEF 0xBB 0xBF),以下代码是FCKeditor的一段代码,由于考虑到可能要处理的文件较大,所以将传值函数改成传递引用:
    //strip UTF8 BOM if any
    function StripUtf8Bom( &$data ){
      if ( substr( $data, 0, 3 ) == "\xEF\xBB\xBF" ){
       $data=substr_replace( $data, '', 0, 3 ) ;
       return TRUE;
      }
      return FALSE;
    }

    关于为何能提高性能,见风雪之隅的博客介绍的php传递引用的实现

  • XAMPP设置和使用

    Posted on 九月 25th, 2008 inetdemon 2 comments

    我们使用XAMPP作为本地开发环境,主要的原因还是非常方便地安装了我们所需要的开发环境,几乎是不需要什么设置,目前支持windows,linux,macOS和solaris,几乎涵盖了绝大多数主流开发者使用的操作系统。下面介绍windowsXP下的设置,vista的设置类似。
    首先在XAMPP官方网站下载XAMPP,下载后在D盘根目录创建XAMPP目录,将解压缩后的xampp拷贝进去,执行setup-xampp.bat即可。

    要启动apache,可以运行xampp目录喜爱的xampp-control.exe,也可以执行xampp-start.exe,启动apache和mysql。

    配置为系统服务,使得系统重启之后自动运行。在 NT4、2000 和 XP 平台中将特定的服务器配置为系统服务。可以以下脚本:

    安装 Apache 服务器为系统服务:.\xampp\apache\apache_installservice.bat
    卸载 Apache 服务器的系统服务:.\xampp\apache\apache_uninstallservice.bat
    安装 MySQL 服务器为系统服务:.\xampp\mysql\mysql_installservice.bat
    卸载 MySQL 服务器的系统服务:.\xampp\mysql\mysql_uninstallservice.bat
    安装及卸载 FileZilla FTP 服务器为系统服务:.\xampp\filezilla_setup.bat
    Mercury 邮件服务器:目前还不能配置为系统服务!

    PEAR的设置:

    /xampp/php/go-pear,一直回车,到设置php.ini时注意使用/xampp/apache/bin/php.in而不是/xampp/php/php.ini回车,就安装好pear了
    现在先检查下配置:
    d:/xampp/php/pear config-show

    然后按需要安装phpunit和一些重要的模块
    d:/xampp/php/pear channel-discover pear.phpunit.de
    d:/xampp/php/pear install log
    d:/xampp/php/pecl install pdo_sqlite
    d:/xampp/php/pear install xdebug
    d:/xampp/php/pear install php/PHPUnit
    d:/xampp/php/pear config

  • Zend Framework的项目目录结构

    Posted on 九月 25th, 2008 inetdemon No comments

    参考ZF1.6版本之前建议的通用目录结构 ,或许你能找到你现在的代码所使用的目录结构。目前我们开发使用的文件结构
    框架遵循Zend Framework 1.6 Proposal Project Structure如下:

    <project name>/
      application/
        apis/
        config/
        controllers/
            helpers/
        layouts/
            filters/
            helpers/
            scripts/
        models/
        modules/
        views/
            filters/
            helpers/
            scripts/
        bootstrap.php
      data/
        cache/
        indexes/
        locales/
        logs/
        sessions/
        uploads/
      docs/
      library/
      public/
        css/
        js/
        images/
        .htaccess
        index.php
      scripts/
        jobs/
        build/
      temp/
      tests/

    2009/7/30更新:ZF1.8的推荐项目目录结构:

    根据项目的复杂度不同和需要不同,可以有不同的目录构造,Zend Framework所推荐的目录结构如这篇proposal所示。我所使用的目录结构图和ZF的规范相同,可以用zend tool直接生成:

    dev:~# cd /var/www/jefflei
    dev:~# zf create project .
    Creating project at /var/www/jefflei

    目录结构大致如示意图所示,因为比较懒,借用了别人的结构图。我们使用的有如下几点不同:

    1. .htaccess, index.php是放在public目录下的,这样方便将document root设置到public目录下,增强安全性。

    2. library。如果不是需要同时在多个项目中使用不同版本的Zend Framework类库,建议将ZendFramework类库放在项目目录的外面,这样减少主项目的size。

    3. Modules目录下通常是application目录结构的迭代,比如:

    `-- application
    |  `-- controllers
    |  `-- models
    |  `-- views
    |  `-- modules
    |  |   `-- foo
    |  |       `-- controllers
    |  |       `-- models
    |  |       `-- views
    |  |       `-- Bootstrap.php  ⇐ class Foo_Bootstrap extends Zend_Application_Module_Bootstrap
    |  `-- Bootstrap.php ⇐ class Bootstrap extends Zend_Application_Bootstrap_Bootstrap
    `-- public

    以上部分也可以用Zend Tool来生成:

    dev:~# zf create module foo
    Creating the following module and artifacts:
    /var/www/jefflei/application/modules/foo/controllers
    /var/www/jefflei/application/modules/foo/models
    /var/www/jefflei/application/modules/foo/views
    /var/www/jefflei/application/modules/foo/views/scripts
    /var/www/jefflei/application/modules/foo/views/helpers
    /var/www/jefflei/application/modules/foo/views/filters
    Updating project profile '/var/www/jefflei/.zfproject.xml'
    
    dev:~# zf create controller index index-action-included=1 foo

    另外一些大型项目一般都会另外单独建立extension目录,运行项目之间共享common的代码,大致结构如下:

    ;;;;extensions?;;;;
    ;   extensions/
    ;       <extension_name>
    ;           application/
    ;               configs/
    ;                   ownroute.ini
    ;                   extension.ini
    ;               controllers/
    ;                   helpers/
    ;               views/
    ;                   filters/
    ;                   helpers/
    ;                   scripts/
    ;               layouts/
    ;                   filters/
    ;                   helpers/
    ;                   scripts/
    ;               models/
    ;           docs/
    ;           data/
    ;               indexes/
    ;               locales/
    ;               logs/
    ;               uploads/
    ;           library/
    ;           override_public/
    ;               scripts/
    ;               styles/
    ;               images/
    ;;;;extensions?;;;;
  • Nginx下zend framework的设置

    Posted on 九月 25th, 2008 inetdemon 4 comments

    在Linux环境下增加一段虚拟服务器的设置,设置nginx.conf如下

       server {
            listen 80;
            server_name audit.local;
            root /app/audit/public;
            access_log  /app/audit/logs/audit.access.log main;
            error_log   /app/audit/logs/audit.error.log;
            location / {
                index  index.php;
            # If file not found, redirect to Zend handling, we can remove the (if) here and go directly rewrite
                if (!-f $request_filename){
                    rewrite ^/(.+)$ /index.php?$1& last;
                }
            }
            location ~* ^.+\.(js|ico|gif|jpg|jpeg|pdf|png|css)$ {
              access_log   off;
              expires      7d;
            }
            location ~ .*\.php?$ {
                fastcgi_pass   127.0.0.1:36;
                fastcgi_index  index.php;
                fastcgi_param  SCRIPT_FILENAME  $document_root$fastcgi_script_name;
                include        fastcgi_params;
            }
            error_page  404             http://audit.local/error;
       }

    你也可以参考apache下zend framework的设置

  • Zend Framework的设置(apache)

    Posted on 九月 24th, 2008 inetdemon No comments
    1. 编辑C:WINDOWSSystem32driversetchosts文件,增加一个域,如127.0.0.1  audit.local
    2. 修改apache的configure文件,在xampp环境下就是在d:/xampp/apache/conf目录下,首先编辑httpd.conf,开启rewrite模块:将这行的注释去掉:LoadModule rewrite_module modules/mod_rewrite.so然后编辑extra/http-vhosts.conf文件,增加如下行:
      <VirtualHost *:80>
          DocumentRoot "D:/xampp/htdocs/"
          ServerName localhost
          ErrorLog logs/localhost.error_log
          CustomLog logs/localhost.access_log common
      </VirtualHost>
      <VirtualHost *:80>
          DocumentRoot "D:/xampp/audit/public/"
          ServerName audit.local
          ErrorLog logs/audit.error_log
          CustomLog logs/audit.access_log common
         
          RewriteEngine off
          <Location />
              RewriteEngine on
              RewriteCond %{REQUEST_FILENAME} !-f
              RewriteRule !.(js|ico|gif|jpg|jpeg|pdf|png|css)$ /index.php
          </Location>
          <directory "D:/xampp/audit/public">
      #Allow server side include,cgi, disable directory index
            Options FollowSymLinks Includes ExecCGI
            Order allow,deny
            Allow from all
          </directory>
      </VirtualHost>
      然后去掉NameVirtualHost这行的注释,重新启动apache,就可以开始使用了更多关于apache rewrite rule的写法和说明。
      如果在nginx服务器上,参考nginx下的zend framework的设置
    3. 下载zend framework并安装到php/lib目录下
    4. 建立项目的文件目录,你可以用最基本的zend framework quick start中推荐的结构,也可以直接使用我们项目使用的ZF1.6标准目录结构

    此文发布时ZF的版本为1.6.1

  • mysql的备份

    Posted on 九月 23rd, 2008 inetdemon No comments
    1. 使用mysqldump

    2. mysqldump -u root -p your-new-password databasename [tablename] > db.sql

      比较大的表需要用优化的dump以节省内存:
      mysqldump --opt database > backup-file.sql

      mysqldump支持下列选项:

      –add-locks
      在每个表导出之前增加LOCK TABLES并且之后UNLOCK TABLE。(为了使得更快地插入到MySQL)。
      –add-drop-table
      在每个create语句之前增加一个drop table。
      –allow-keywords
      允许创建是关键词的列名字。这由在列名前面加表名的方法做到。
      -c, –complete-insert
      使用完整的insert语句(用列名字)。
      -C, –compress
      如果客户和服务器均支持压缩,压缩两者间所有的信息。
      –delayed
      用INSERT DELAYED命令插入行。
      -e, –extended-insert
      使用全新多行INSERT语法。(给出更紧缩并且更快的插入语句)
      -#, –debug[=option_string]
      跟踪程序的使用(为了调试)。
      –help
      显示一条帮助消息并且退出。
      –fields-terminated-by=…
      –fields-enclosed-by=…
      –fields-optionally-enclosed-by=…
      –fields-escaped-by=…
      –fields-terminated-by=…
      这些选择与-T选择一起使用,并且有相应的LOAD DATA INFILE子句相同的含义。
      LOAD DATA INFILE语法。
      -F, –flush-logs
      在开始导出前,洗掉在MySQL服务器中的日志文件。
      -f, –force,
      即使我们在一个表导出期间得到一个SQL错误,继续。
      -h, –host=..
      从命名的主机上的MySQL服务器导出数据。缺省主机是localhost。
      -l, –lock-tables.
      为开始导出锁定所有表。
      -t, –no-create-info
      不写入表创建信息(CREATE TABLE语句)
      -d, –no-data
      不写入表的任何行信息。如果你只想得到一个表的结构的导出,这是很有用的!
      –opt
      同–quick –add-drop-table –add-locks –extended-insert –lock-tables。
      应该给你为读入一个MySQL服务器的尽可能最快的导出。
      -pyour_pass, –password[=your_pass]
      与服务器连接时使用的口令。如果你不指定“=your_pass”部分,mysqldump需要来自终端的口令。
      -P port_num, –port=port_num
      与一台主机连接时使用的TCP/IP端口号。(这用于连接到localhost以外的主机,因为它使用 Unix套接字。)
      -q, –quick
      不缓冲查询,直接导出至stdout;使用mysql_use_result()做它。
      -S /path/to/socket, –socket=/path/to/socket
      与localhost连接时(它是缺省主机)使用的套接字文件。
      -T, –tab=path-to-some-directory
      对于每个给定的表,创建一个table_name.sql文件,它包含SQL CREATE 命令,和一个table_name.txt文件,它包含数据。 注意:这只有在mysqldump运行在mysqld守护进程运行的同一台机器上的时候才工作。.txt文件的格式根据–fields-xxx和–lines–xxx选项来定。
      -u user_name, –user=user_name
      与服务器连接时,MySQL使用的用户名。缺省值是你的Unix登录名。
      -O var=option, –set-variable var=option
      设置一个变量的值。可能的变量被列在下面。
      -v, –verbose
      冗长模式。打印出程序所做的更多的信息。
      -V, –version
      打印版本信息并且退出。
      -w, –where=’where-condition’
      只导出被选择了的记录;注意引号是强制的!
      “–where=user=’jimf’” “-wuserid>1″ “-wuserid<1″

      最常见的mysqldump使用可能制作整个数据库的一个备份:
      mysqldump --opt database > backup-file.sql

      但是它对用来自于一个数据库的信息充实另外一个MySQL数据库也是有用的:
      mysqldump --opt database | mysql --host=remote-host -C database

      由于mysqldump导出的是完整的SQL语句,所以用mysql客户程序很容易就能把数据导入了:
      mysqladmin create target_db_name
      mysql target_db_name < backup-file.sql

    3. 启用二进制日志(binlog)

    4. 采用 binlog 的方法相对来说更灵活,省心省力,而且还可以支持增量备份。

      启用 binlog 时必须要重启 mysqld。首先,关闭 mysqld,打开 my.cnf,加入以下几行:
      server-id = 1
      log-bin = binlog
      log-bin-index = binlog.index

      然后启动 mysqld 就可以了。运行过程中会产生 binlog.000001 以及 binlog.index,前面的文件是 mysqld 记录所有对数据的更新操作,后面的文件则是所有 binlog 的索引,都不能轻易删除。关于 binlog 的信息请查看手册。
      需要备份时,可以先执行一下 SQL 语句,让 mysqld 终止对当前 binlog的写入,就可以把文件直接备份,这样的话就能达到增量备份的目的了:
      FLUSH LOGS;
      如果是备份复制系统中的从服务器,还应该备份 master.inforelay-log.info 文件。
      备份出来的 binlog 文件可以用 MySQL 提供的工具 mysqlbinlog 来查看,如:/usr/local/mysql/bin/mysqlbinlog /tmp/binlog.000001
      该工具允许你显示指定的数据库下的所有 SQL 语句,并且还可以限定时间范围,相当的方便,详细的请查看手册。
      恢复时,可以采用类似以下语句来做到:
      /usr/local/mysql/bin/mysqlbinlog /tmp/binlog.000001 | mysql -uyejr -pyejr db_name
      mysqlbinlog 输出的 SQL 语句直接作为输入来执行它。
      如果你有空闲的机器,不妨采用这种方式来备份。由于作为 slave 的机器性能要求相对不是那么高,因此成本低,用低成本就能实现增量备份而且还能分担一部分数据查询压力,何乐而不为呢?

    5. 直接备份数据文件

    6. 相较前几种方法,备份数据文件最为直接、快速、方便,缺点是基本上不能实现增量备份。为了保证数据的一致性,需要在靠背文件前,执行以下 SQL 语句:
      FLUSH TABLES WITH READ LOCK;
      也就是把内存中的数据都刷新到磁盘中,同时锁定数据表,以保证拷贝过程中不会有新的数据写入。这种方法备份出来的数据恢复也很简单,直接拷贝回原来的数据库目录下即可。
      注意,对于 Innodb 类型表来说,还需要备份其日志文件,即 ib_logfile* 文件。因为当 Innodb 表损坏时,就可以依靠这些日志文件来恢复。

    7. 备份策略

    8. 对于中等级别业务量的系统来说,备份策略可以这么定:第一次全量备份,每天一次增量备份,每周再做一次全量备份,如此一直重复。而对于重要的且繁忙的系统来说,则可能需要每天一次全量备份,每小时一次增量备份,甚至更频繁。为了不影响线上业务,实现在线备份,并且能增量备份,最好的办法就是采用主从复制机制(replication),在 slave 机器上做备份。

    9. 数据维护和灾难恢复

    10. DBA最重要的工作内容之一是保证数据表能安全、稳定、高速使用。因此,需要定期维护你的数据表。以下 SQL 语句就很有用:
      CHECK TABLE 或 REPAIR TABLE,检查或维护 MyISAM 表
      OPTIMIZE TABLE,优化 MyISAM 表
      ANALYZE TABLE,分析 MyISAM 表

      当然了,上面这些命令起始都可以通过工具 myisamchk 来完成,在这里不作详述。
      Innodb 表则可以通过执行以下语句来整理碎片,提高索引速度:
      ALTER TABLE tbl_name ENGINE = Innodb;
      这其实是一个 NULL 操作,表面上看什么也不做,实际上重新整理碎片了。
      通常使用的 MyISAM 表可以用上面提到的恢复方法来完成。如果是索引坏了,可以用 myisamchk 工具来重建索引。而对于 Innodb 表来说,就没这么直接了,因为它把所有的表都保存在一个表空间了。不过 Innodb 有一个检查机制叫 模糊检查点,只要保存了日志文件,就能根据日志文件来修复错误。可以在 my.cnf 文件中,增加以下参数,让 mysqld 在启动时自动检查日志文件:
      innodb_force_recovery = 4
      关于该参数的信息请查看手册。