存档

‘程序开发’ 分类的存档

ZF1.8 DB字符集设定

2009年8月11日

Zend Framework的db 字符集设置,由于ZF的一个bug,以前在设置db的字符集为utf-8时,通常是在bootstrap中设定

 $db = Zend_Db::factory($this->_config->db);
 $db->query("SET NAMES utf8");  //setup encoding

这种做法的一个缺点就是DB的lazy loading机制变得无效,所有不调用数据库的页面也需要去打开一个数据库链接。困难之处在于每种数据库的charset名称并不相同,之前一直有一个提议,将charset做一个db的option来设置,ZF1.7开始将这个建议实施,现在我们可以用如下方法,设置db的option

 <?php
$db = new Zend_Db_Adapter_Pdo_Mysql(array(
'host'     => 'your_host_or_ip',
'username' => 'your_myslq_username0,
'password' => 'mysql_pass',
'dbname'   => 'your_db_name',
'driver_options'  => array(PDO::MYSQL_ATTR_INIT_COMMAND => 'SET NAMES \'utf8\'')
));?>

除此之外,还可以在config中设置,不过由于config文件并不认得常量,因此只能用以下方式来设置:
db.params.driver_options.1002 = “SET NAMES utf8”
其中1002即PDO::MYSQL_ATTR_INIT_COMMAND这个常量的值。

如果想直接修改DB的charset collocation可以参考mysql的charset转化指南

感谢 julian的提醒,自从ZF1.8开始已经可以使用db.param.charset=”UTF-8″来设定; 如果使用的是Zend_Application,可以设定resource.db.params.charset=”UTF-8″.

VN:F [1.9.22_1171]
Rating: 10.0/10 (1 vote cast)
VN:F [1.9.22_1171]
Rating: 0 (from 0 votes)

程序开发

Zend Framework 1.8 中的Model

2009年8月1日

在ZF1.8以后Module的问题得以完善,但是仍然有很多领域需要改进,Model就是其中一个

Model的类型用DbTable<->Mapper<->Model的DataMapper Pattern (同时参照IdentityMapUnitOfWork)来调用,其中对象Model用于导入对象,导入后就由UOW拥有的Identity对象来跟踪,以此来保持数据的同步。比如一个Users表,我们有如下类:

Model_User是业务域模型(domain Model),关于domain design的模式可以参见domain driven design一书

Model_UserMapper来完成Model对象和数据库的映射关系

Model_DbTable_Users extends Zend_Db_Table_Abstract类负责数据库方面的设定

以上pattern的使用在这篇帖子Zend 的proposal中有讨论到。这个Pattern的好处是,如果你将来不用数据库来保存数据,而换用文件或者Memcached,那么你就不用修改你的Controller了;从来引来的一个缺点是几乎每个调用都需要来定义Mapper,从而导致复杂度提高。通常情况下对于不是比较复杂的情况,1:1的应用来说,Table Gatewy, Row, Rowset的Pattern已经足够使用。

关于DataMapper的Model使用模型还在更新过程中,同时还有个datashuffler在ZF上的实现目前也在研究中。

VN:F [1.9.22_1171]
Rating: 8.0/10 (1 vote cast)
VN:F [1.9.22_1171]
Rating: 0 (from 0 votes)

程序开发

ZF1.8 快速上手

2009年7月30日

ZF有段时间没有弄了,自从ZF1.8出来之后改动比较大,把一些东西整理一下,温故而知新。

首先是下载ZendFramework,由于ZF的版本更新很快,一些小版本基本是2周出一次下载最新的ZF,下载后将ZF放到系统类库目录,我们假设是/usr/local/lib/,

其次,将ZF添加到系统目录中去,可以修改php.ini(如果不确定php.ini所在目录,可以通过phpinfo查看),在include_path中增加如下目录:include_path=”.:/path/to/zf:/usr/share/php:/usr/share/pear”,对于以ZF为主的系统,将ZF包含目录放在最前面有助提高效率,详细请看这篇文章。在进行下一步之前,我们需要先确定目录构造,请参见ZF所推荐的Zend Framework的目录结构

开始工作,首先index.php比较简单:

<?php

// Define path to application directory
defined('APPLICATION_PATH')
 || define('APPLICATION_PATH', realpath(dirname(__FILE__) . '/../application'));

// Define application environment
defined('APPLICATION_ENV')
 || define('APPLICATION_ENV', (getenv('APPLICATION_ENV') ? getenv('APPLICATION_ENV') : 'production'));

// Ensure library/ is on include_path
set_include_path(implode(PATH_SEPARATOR, array(
 realpath(APPLICATION_PATH . '/../library'),
 get_include_path(),
)));

/** Zend_Application */
require_once 'Zend/Application.php';  

// Create application, bootstrap, and run
$application = new Zend_Application(
 APPLICATION_ENV,
 APPLICATION_PATH . '/configs/config.ini'
);

$application->bootstrap()
 ->run();

接下来是bootstrap.php我最开始写ZF的时候最麻烦的部分就是bootstrap,花了不少时间调试。Bootstrap,顾名思义就是系鞋带,指出发之前做的准备工作。自从Zend Framework 1.8以后,ZF出了Zend_tool和Zend_Application,因此Bootstrap有了比较大的调整,基本来讲,只需要在index.php中调用Zend_Application,就可以直接免去过去设定config文件,DB,view等。如果需要对这些做特别设置,可以在Bootstrap中扩展Zend_Application_Bootstrap_Bootstrap,用_init*资源函数来设定,BootStrap将依顺序逐个调用这些_init*资源函数,然后执行dispatch。用这里有篇是介绍如何将老的Bootstrap迁移到ZF1.8上。需要注意的有几点,

1.  在initView的时候尽量不要标注Response属性,这样这个Bootstrap不会在layout之前实例化Response;

2.  可以判断ajax的request头,用以去除layout, ViewRender,errorHandler和Exception的输出,这样就免除在ajax页面里面单独进行设定了。

3. ZF1.8之后可以通过设定driver option的方式对ZF的DB charset进行lazy load方式的设定了。

<?php

class Bootstrap extends Zend_Application_Bootstrap_Bootstrap
{
 protected $_config;
 protected $_cache;
 protected $_requesttype;

 public function run() {
 $frontController = Zend_Controller_Front::getInstance();
 $frontController->dispatch();
 }

 protected function _initAutoload(){
 $autoloader = new Zend_Application_Module_Autoloader(array(
 'namespace' => '',
 'basePath'  => APPLICATION_PATH,
 ));
 return $autoloader;
 }

 protected function _initConfig(){
 // config
 $this->_config = new Zend_Config_Ini(APPLICATION_PATH . '/configs/config.ini', APPLICATION_ENV);
 Zend_Registry::set('config', $this->_config);
 Zend_Registry::set('env', APPLICATION_ENV);

 //Load Application Level configure
 $appconf = new Zend_Config_Ini(APPLICATION_PATH . '/configs/app.conf', APPLICATION_ENV);
 Zend_Registry::set('appconf', $appconf);

 if (1 == (int)$this->_config->debug->showpageinfo){
 Zend_Registry::set('PageStartTime', microtime(true));
 }
 }

 protected function _initDB(){
 if($this->_config->db) {
 $db = Zend_Db::factory($this->_config->db);
 if($this->_config->cache->tablemeta && isset($this->_cache)) //setup Metacache to speed up
 Zend_Db_Table::setDefaultMetadataCache($this->_cache);
 Zend_Db_Table_Abstract::setDefaultAdapter($db);
 Zend_Registry::set('db', $db);
 }
 }

 protected function _initView(){
 // view and layout setup
 $view = new Zend_View(array('encoding'=>'UTF-8'));
 $view->addHelperPath(APPLICATION_PATH.'/default/views/helpers/');
 //$viewRendered = new Zend_Controller_Action_Helper_ViewRenderer($view);
 //Zend_Controller_Action_HelperBroker::addHelper($viewRendered);

 Zend_Dojo::enableView($view);
 $view->dojo()->setDjConfigOption('parseOnLoad', true)
 ->requireModule('dijit.form.FilteringSelect')
 ->requireModule('custom.PairedStore');
 //$view->addBasePath(realpath('./templates/default/'));

 //if ajax submit
 if (isset($_SERVER['HTTP_X_REQUESTED_WITH']) && $_SERVER['HTTP_X_REQUESTED_WITH'] == 'XMLHttpRequest'){
 $this->_requesttype="ajax";
 }else{
 $this->_requesttype="html";
 Zend_Layout::startMvc(array(
 'layoutPath'=>APPLICATION_PATH . '/layouts',
 'layout'=>'layout'
 ));
 }
 $view->doctype('XHTML1_STRICT');
 Zend_Controller_Action_HelperBroker::getStaticHelper('viewRenderer')->setView($view);
 }

 protected function _initFrontController(){
 $frontController = Zend_Controller_Front::getInstance();
 $frontController->setControllerDirectory(APPLICATION_PATH .'/controllers');
 $frontController->setParam('env', APPLICATION_ENV);
 if ("ajax" == $this->_requesttype){
 // Disable the ErrorHandler plugin
 $frontController->setParam('noErrorHandler', true);
 // Disable the ViewRenderer helper
 $frontController->setParam('noViewRenderer', true);
 }
 $frontController->throwExceptions(false);
 $frontController->setBaseUrl('/');
 // action helpers
 Zend_Controller_Action_HelperBroker::addPath(APPLICATION_PATH .'/controllers/helpers');
 }

 protected function _initSession(){
 if (isset($this->_config->session)){
 $session = $this->_config->session;
 if (empty($session->save_path))
 $session->save_path = APPLICATION_PATH. "/../data/sessions/";
 }
 Zend_Session::setOptions($this->_config->session->toarray());
 }

 protected function _initCache(){
 /**
 * Setup Core Cache
 */
 if ('true' == $this->_config->cache->caching){
 $CacheFrontendOptions = array(
 'lifeTime' => $this->_config->cache->lifetime,  // cache lifetime of half a minute
 'caching' => $this->_config->cache->caching,
 'automatic_serialization' => $this->_config->cache->automatic_serialization,  // this is default anyway
 'automatic_cleaning_factor'=>$this->_config->cache->automatic_cleaning_factor,
 'logging' => $this->_config->cache->logging,
 );
 switch($this->_config->cache->backend){
 case 'memcached':
 $MemcachedBackendOptions = array(
 'servers'=>array(array(
 'host' => $this->_config->cache->memcached->host,
 'port' => $this->_config->cache->memcached->port,
 'persistent' => $this->_config->cache->memcached->persistent
 )));
 $this->_cache = Zend_Cache::factory('Core', 'Memcached', $CacheFrontendOptions, $MemcachedBackendOptions);
 break;
 case 'file':
 default:
 $FileBackendOptions = array(
 'cache_dir' => APPLICATION_PATH.'/../data/cache/',
 'read_control'=>true,
 'read_control_type'=>'md5',
 'hashed_directory_level'=>'1'
 );
 $this->_cache = Zend_Cache::factory('Core', 'File', $CacheFrontendOptions, $FileBackendOptions);
 break;
 }//End of switch
 Zend_Registry::set('cache', $this->_cache);
 }
 /**
 * Setup Page cache
 */
 if($this->_config->cache->page->caching){
 $pageCacheRegexpsConfig = array(
 'cache_with_get_variables'=>true,
 'cache_with_post_variables'=>true,
 'cache_with_session_variables'=>true,
 'cache_with_files_variables'=>true,
 'cache_with_cookie_variables'=>true,);
 $pageCacheFrontendOptions = array(
 'lifetime' => $this->_config->cache->lifetime,
 'debug_header' => $this->_config->cache->page->debug, // for debugging
 'regexps' => array(
 // cache the whole IndexController
 '^(.+)-lc-(.*).html' => array_merge($pageCacheRegexpsConfig,array('tags'=>array('lc'))),
 )
 );

 if (empty($FileBackendOptions)){
 $FileBackendOptions = array(
 'cache_dir' => APPLICATION_PATH.'/../data/cache/',
 'read_control'=>true,
 'read_control_type'=>'md5',
 'hashed_directory_level'=>'1'
 );
 }

 // getting a Zend_Cache_Frontend_Page object
 $page_cache = Zend_Cache::factory('Page',
 'File',
 $pageCacheFrontendOptions,
 $FileBackendOptions);
 $page_cache->start();
 }
 }

 protected function _initTranslation(){
 //Setup Locale
 Zend_Locale::setDefault('en');   //fallback locale
 $locale = new Zend_Locale('auto'); //auto detection for user locale
 if (isset($this->_cache)) Zend_Locale::setCache($this->_cache); //cache locale to speed up
 Zend_Registry::set('Zend_Locale', $locale); //set up application-wide locale
 //Setup Zend Translate

 //$this->_cache = Zend_Cache::factory('Page','File',$frontendOptions,$backendOptions);
 //Zend_Translate::setCache($this->_cache);
 $translate = new Zend_Translate('gettext','../data/locales/',NULL,array(
 'scan' =>Zend_Translate::LOCALE_DIRECTORY,
 'disableNotices' => true
 ));
 Zend_Registry::set('Zend_Translate', $translate);
 //Zend_Validate_Abstract::setDefaultTranslator($translate);
 Zend_Form::setDefaultTranslator($translate);
 }

 protected function _initRoutes(){
 //$router = new Zend_Controller_Router_Rewrite();
 //$router->addConfig($appconf, 'routes');
 }
}
VN:F [1.9.22_1171]
Rating: 0.0/10 (0 votes cast)
VN:F [1.9.22_1171]
Rating: 0 (from 0 votes)

程序开发

XSS攻击防范

2009年4月22日

最近一个朋友找我帮忙修复一个XSS注入漏洞,其实网站也是某上市互联网公司的中国站。现在XSS和CSRF攻击成为一个WEB软件工作者不得不重视的一个问题,很有必要深入研究下。

XSS漏洞很容易在大型网站中发现,在黑客圈内它非常流行。最著名的是2005年黑客Sammy Kamkar在myspace网站发布蠕虫病毒后,XSS就开始大行其道。FBI.gov、CNN.com、Time.com、Ebay、 Yahoo、Apple、Microsoft、Zdnet、Wired、Newsbytes,twitter都有这样那样的XSS漏洞。国内出现过XSS漏洞的网站有sohu,网易邮箱,校内网等,百度和著名电商网站淘宝也曾出现过XSS漏洞。

在商业产品中,平均每个月能够发现10-25个XSS漏洞。

假设你已经了解XSS的基本概念和类型,这里看看如何进行防范。先总结一下常见的XSS攻击手法:

依赖跨站漏洞,需要在被攻击网站的页面种入XSS脚本的手法

Cookie 盗取,通过javascript 获取被攻击网站种下的cookie,并发送给攻击者。
1.从cookie 中提取密码等隐私
2. 利用cookie 伪造session,发起重放攻击
Ajex 信息盗取,通过javascript 发起ajex 请求。
1. 从ajex 结果中获取隐私。
2. 模拟用户完成多页表单。

不依赖跨站漏洞的XSS攻击手法

1. 单向HTTP 动作,通过img.src 等方法发起跨站访问,冒充被攻击者执行特权操作。但是很难拿到服务器的返回值。
2. 双向HTTP 动作,如果服务器产生一段动态的script,那么可以用script.src 的方法发起跨站访问并拿到服务器的返回值。

XSS防范方法

XSS攻击防范主要是有程序漏洞造成的,要完全防止XSS安全漏洞主要依靠程序员较高的编程能力和安全意识,当然一些编程安全原则可以帮助大大减少XSS安全漏洞:

  1. 不信任用户提交的任何内容,对所有用户提交内容进行可靠的输入验证,包括对URL、查询关键字、HTTP头、REFER、POST数据等,仅接受指定长度范围内、采用适当格式、采用所预期的字符的内容提交,对其他的一律过滤。尽量采用POST 而非GET 提交表单;对”<”,”>”,”;”,”’”等字符做过滤;任何内容输出到页面之前都必须加以encode,避免不小心把html tag 弄出来。
  2. 实现Session标记(session tokens)、CAPTCHA系统或者HTTP引用头检查,以防功能被第三方网站所执行,对于用户提交信息的中的img 等link,检查是否有重定向回本站、不是真的图片等可疑操作。
  3. Cookie 防盗。避免直接在cookie 中泄露用户隐私,例如email、密码等等;通过使cookie 和系统ip 绑定来降低cookie 泄露后的危险。这样攻击者得到的cookie 没有实际价值,不可能拿来重放。
  4. 确认接收的的内容被妥善的规范化,仅包含最小的、安全的Tag(没有javascript),去掉任何对远程内容的引用(尤其是样式表和javascript),使用HTTP only的cookie。

PHP方面请参见PHP的安全防范工作

ASP.Net的可以用VS自带的XSSDetect来检测。

要更好的防范XSS和CSRF攻击等,除了加强程序开发的严谨度之外,还需要重视测试工作,通过专业的测试来减少问题发生的可能性,我们看到淘宝QA也重视XSS攻击测试了。

VN:F [1.9.22_1171]
Rating: 6.0/10 (4 votes cast)
VN:F [1.9.22_1171]
Rating: 0 (from 0 votes)

程序开发

用php控制你的MSN消息

2009年1月21日

从Facebook到开心网,很多SNS应用都使用了msn服务,关于MSN的协议的详细信息可以看半官方网站MSNPiki。使用MSN的php类也不少,这里介绍两个,第一个是PHP MSN Class,这个类比较简单,可以用来发送MSN消息,支持MSNP9 (MSN 6.2)和最新的MSNP15 (WLM 8.1)协议(MSNP15协议支持离线消息),可以作为MSN机器人使用,或者给MSN、雅虎通发消息。

<?php
include_once(‘msn.class.php’);
$msn_username = “username@hotmail.com”;//发送者MSN帐号
$msn_password = “12341234”;//发送者MSN密码
$msn_list = array(“user1@hotmail.com”,”user2@live.cn”);//消息接收者MSN帐号
$msn = new MSN(‘MSNP15’);//采用MSNP15协议,支持离线消息
if ($msn->connect($msn_username, $msn_password)) {
    $msn->sendMessage(“UTF-8编码的中文和英文”, $msn_list);
}
?>

使用MSNP15协议,PHP需要支持mhash;使用msnbot机器人功能,PHP需要支持pcntl。

phpMSN:基于PHP的MSN Messenger客户端连接接口。
MSN Messenger Class:这是一个支持MSNP协议的简单易用的PHP类库,它通过php_curl模块来实现对SSL的支持,目前,支持MSN9协议。

Blobsy:一个基于PHP开发的开源MSN Messager机器人。它设计灵活易用,便于安装,而且可定制,功能强大,内建模块包括让MSN上google帮你查资料等,这篇中文博客有不少介绍。

Naneau MSN:另一个用ZF开发的MSN类, 包括消息发送,获取联系人清单等。

Contact Grabber: 可以抓取MSN,GMAIL,Yahoo Messenger等联系人信息。

这里还有些介绍付费的contact抓取类,还支持aol,icq等:http://script.wareseeker.com/free-contact-importer-address-book-grabber-for-hotmail-gmail-yahoo-msn-aol/

VN:F [1.9.22_1171]
Rating: 0.0/10 (0 votes cast)
VN:F [1.9.22_1171]
Rating: 0 (from 0 votes)

程序开发

PHP下处理Excel文件总结

2009年1月13日

参照这篇总结,貌似php excel比较好:http://xinsync.xju.edu.cn/index.php/archives/3858

VN:F [1.9.22_1171]
Rating: 0.0/10 (0 votes cast)
VN:F [1.9.22_1171]
Rating: 0 (from 0 votes)

程序开发

EAV表建模探索

2008年12月11日

EAV模型代表Entity-Attribute-Value,最早用于医学用途,医生在就诊时需要记录很多病人的参数,如体温,年龄,过敏药等情况,而这些参数并不是每个病人都需要记录的。

由于商品的多样性,用EAV表来描述商品的各种属性也很合适。老牌电子商务应用oscommerce的表设计(为了简洁,我将商品属性名和属性值的关系表略去):

 

 

 

 

 

 

-- 商品表
CREATE TABLE `products` (
`id` int(11) NOT NULL auto_increment,
`products_name` varchar(50) default NULL,
PRIMARY KEY (`id`)
);

-- 商品属性表

 

 

 

 

 

CREATE TABLE `products_attributes` (
`id` int(11) NOT NULL auto_increment,
`products_id` int(11) NOT NULL default '0',
`attribute_name` varchar(50) default NULL,
PRIMARY KEY (`id`),
KEY `products_id_attribute_name` (`products_id`,`attribute_name`)

);

-- 属性值

CREATE TABLE `attribute_values` (

`attribute_id` int(11) NOT NULL default '0',

`attribute_value` varchar(100) default NULL,

UNIQUE KEY `attribute_id` (`attribute_id`,`attribute_value`)

);

 

 

 

 

 

 

EAV表模型带来了数据的灵活性,是的增加对象的属性不需要用增加数据库的字段,有很高的灵活性。但是EAV表也有较大的性能问题。通常,EAV表带来的一个问题是当查找多个字段时,需要进行关联查询join,这样的查询效率比较低。为了提高查询效率,我们可以对商品属性表进行矩阵转积处理(pivoting),

 

 

 

 

 

 

"SELECT
items.item_name,
ia.attribute_name,
av.attribute_value
FROM
attribute_values AS av

JOIN item_attributes AS ia

ON (ia.id = av.attribute_id)

JOIN items AS items

ON (items.id = ia.item_id);

";

 

 

 

 

 

一种方式是在php代码中读出后存入memcache, 当修改attributes表后php触发更新memcache或用cron定期更新;另一种方法是将关联信息组成一张大的临时表,或者view(mysql 5), 利于warehouse的查询,数据的更新可以用数据库的触发器触发更新。由于大量数据在php中进行处理带来了DB的额外IO和服务器性能问题,比较建议用后一种方式更新。

著名的ecommerce软件magento就采用了EAV表作为核心架构,下面看一下通常的表设计:
这里是EAV表的设计:

EAV表设计

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

magento的做法是遵循php|architect的一些建议,通常有如下表等:

CREATE TABLE field_names (
fid INT UNSIGNED PRIMARY KEY AUTO_INCREMENT,
field_name VARCHAR(50) NOT NULL DEFAULT '',
field_type ENUM('VARCHAR', 'INTEGER', 'DOUBLE',
'DATE', 'TEXT') NOT NULL DEFAULT 'VARCHAR',
UNIQUE KEY (field_name)

);

CREATE TABLE varchar_values (

vid INT UNSIGNED PRIMARY KEY AUTO_INCREMENT,

value VARCHAR(255) NOT NULL DEFAULT '',

UNIQUE KEY (value)

);

CREATE TABLE integer_values (

vid INT UNSIGNED PRIMARY KEY AUTO_INCREMENT,

value INT(11) NOT NULL DEFAULT 0,

UNIQUE KEY (value)

);

CREATE TABLE double_values (

vid INT UNSIGNED PRIMARY KEY AUTO_INCREMENT,

value DOUBLE NOT NULL DEFAULT 0,

UNIQUE KEY (value)

);

CREATE TABLE date_values (

vid INT UNSIGNED PRIMARY KEY AUTO_INCREMENT,

value DATE NOT NULL DEFAULT '0000-00-00',

UNIQUE KEY (value)

);

CREATE TABLE text_values (

vid INT UNSIGNED PRIMARY KEY AUTO_INCREMENT,

value TEXT NOT NULL DEFAULT '',

UNIQUE KEY (value(100))

);

 

 

 

 

 

可以定义一些mysql函数,方便数据类型到具体表的转换

CREATE FUNCTION `value_display` (`type` enum('NUMBER', 'ENUM', 'DATE', 'TIME', 'TEXT'), `value` INT, `option` VARCHAR(255), `text` TEXT, `precision` INT, `date_format` VARCHAR(50)) RETURNS VARCHAR(255) CHARACTER SET latin1 NO SQL
BEGIN
  CASE type
    WHEN 'NUMBER' THEN RETURN `value` / POW(10, `precision`);
    WHEN 'ENUM' THEN RETURN `option`;
    WHEN 'DATE' THEN RETURN DATE_FORMAT(FROM_DAYS(`value`), `date_format`);

    WHEN 'TIME' THEN RETURN FROM_UNIXTIME(`value`, `date_format`);

    WHEN 'TEXT' THEN RETURN `text`;

    ELSE RETURN NULL;

  END CASE;

 

  RETURN NULL;

END;

 

 

 

 

 

当使用EAV表模型时,InnoDB比MYISAM的性能要好不少。

VN:F [1.9.22_1171]
Rating: 9.0/10 (2 votes cast)
VN:F [1.9.22_1171]
Rating: 0 (from 0 votes)

程序开发

Zend Session使用要点

2008年10月16日

在Zend_Session使用中需要注意以下几点

1. 关闭PHP的 session.auto_start setting. 在php.ini, 或者 .htaccess中写:
php_value session.auto_start 0

2.不要直接使用session_start() 和Zend_Session_Namespace有冲突。

3.简单方法:可以直接new一个Zend_Session_Namespace,但是这种方法需要注意不要在此代码之前输出header.

4.麻烦但是不容易出问题的方法:使用Zend_Session::setOptions() 设置为strict, 防止自动自动zend session;在bootstrap中根据具体的action的需要,启动Zend_Session::start(),然后在action中new Zend_Session_Namespace。

VN:F [1.9.22_1171]
Rating: 5.7/10 (3 votes cast)
VN:F [1.9.22_1171]
Rating: +1 (from 1 vote)

程序开发

强制使用https的apache设置

2008年10月11日
强制使用https的apache设置已关闭评论

如果我们有一个域,比如login.abc.com, 这个域我们同时接受http和https协议,但是我们希望将http协议的用户重定向到https,可以有两种做法,一种是在代码中进行重定向,zf的代码如下:

class Common_Helper_ForceHTTPS extends Zend_Controller_Action_Helper_Abstract {
  public function direct() {
    if (! isset ( $_SERVER['HTTPS'] ) && $_SERVER['HTTPS']) {
      $request = $this->getRequest ();
      $url = 'https://' . $_SERVER ['HTTP_HOST'] . $request->getRequestUri ();
      $redirector = Zend_Controller_Action_HelperBroker::getStaticHelper ( 'redirector' );
      $redirector->gotoUrl ( $url );
    }
  }
}

还有一种是进行apache配置,由于apache的配置是c代码,效率较高,我们建议用apache的配置来实现。
<IfModule mod_rewrite.c>
    RewriteEngine on
    Options +FollowSymLinks
    RewriteBase /   
RewriteCond %{REQUEST_FILENAME} !-f
    RewriteCond %{REQUEST_FILENAME} !-d   
    RewriteRule ^(.*)$ index.php/$1
   
    RewriteCond $1 !^(index.php|img|css|js|secure_checkout|common_funcs.js|robots.txt)
    RewriteCond %{SERVER_PORT} 80
    RewriteRule /secure_checkout(.*)$ https://www.myURL.com/secure_checkout/$1
</IfModule>
RewriteCond %{REQUEST_FILENAME} !-f
    RewriteCond %{REQUEST_FILENAME} !-d   
    RewriteRule ^(.*)$ index.php/$1
   
    RewriteCond $1 !^(index.php|img|css|js|secure_checkout|common_funcs.js|robots.txt)
    RewriteCond %{SERVER_PORT} 80
    RewriteRule /secure_checkout(.*)$ https://www.myURL.com/secure_checkout/$1
</IfModule>

VN:F [1.9.22_1171]
Rating: 9.5/10 (2 votes cast)
VN:F [1.9.22_1171]
Rating: 0 (from 0 votes)

程序开发 , ,

PHP安全防范

2008年10月7日

PHP代码安全和XSS,SQL注入等对于各类网站的安全非常中用,尤其是UGC(User Generated Content)网站,论坛和电子商务网站,常常是XSS和SQL注入的重灾区。这里简单介绍一些基本编程要点, 相对系统安全来说,php安全防范更多要求编程人员对用户输入的各种参数能更细心.

php编译过程中的安全

建议安装Suhosin补丁,必装安全补丁

php.ini安全设置

register_global = off
magic_quotes_gpc = off
display_error = off
log_error = on
# allow_url_fopen = off
expose_php = off
open_basedir =
safe_mode = on
disable_function = exec,system,passthru,shell_exec,escapeshellarg,escapeshellcmd,proc_close,proc_open,dl,popen,show_source,get_cfg_var
safe_mode_include_dir =

DB SQL预处理

mysql_real_escape_string (很多PHPer仍在依靠addslashes防止SQL注入,但是这种方式对中文编码仍然是有问题的。addslashes的问题在于黑客可以用0xbf27来代替单引号,GBK编码中0xbf27不是一个合法字符,因此addslashes只是将0xbf5c27,成为一个有效的多字节字符,其中的0xbf5c仍会被看作是单引号,具体见这篇文章)。用mysql_real_escape_string函数也需要指定正确的字符集,否则依然可能有问题。
prepare + execute(PDO)
ZendFramework可以用DB类的quote或者quoteInto, 这两个方法是根据各种数据库实施不用方法的,不会像mysql_real_escape_string只能用于mysql

用户输入的处理

无需保留HTML标签的可以用以下方法

strip_tags, 删除string中所有html标签
htmlspecialchars,只对”<”,”>”,”;”,”’”字符进行转义
htmlentities,对所有html进行转义

必须保留HTML标签情况下可以考虑以下工具:
HTML Purifier: HTML Purifier is a standards-compliant HTML filter library written in PHP.
PHP HTML Sanitizer: Remove unsafe tags and attributes from HTML code
htmLawed: PHP code to purify & filter HTML

上传文件

用is_uploaded_file和move_uploaded_file函数,使用HTTP_POST_FILES[]数组。并通过去掉上传目录的PHP解释功能来防止用户上传php脚本。
ZF框架下可以考虑使用File_upload模块

Session,Cookie和Form的安全处理

不要依赖Cookie进行核心验证,重要信息需要加密, Form Post之前对传输数据进行哈希, 例如你发出去的form元素如下:

<pre lang="php">&lt;input type="hidden" name="H[name]" value="&lt;?php echo $Oname?&gt;"/&gt;
&lt;input type="hidden" name="H[age]" value="&lt;?php echo $Oage?&gt;"/&gt;
&lt;?php $sign = md5('name'.$Oname.'age'.$Oage.$secret); ?&gt;
&lt;input type="hidden" name="hash" value="&lt;?php echo $sign?&gt;"" /&gt;

POST回来之后对参数进行验证

$str = "";
foreach($_POST['H'] as $key=&gt;$value) {
  $str .= $key.$value;
}
if($_POST['hash'] != md5($str.$secret)) {
  echo "Hidden form data modified"; exit;
}

PHP安全检测工具(XSS和SQL Insertion)

Wapiti – Web application security auditor(Wapiti – 小巧的站点漏洞检测工具) (SQL injection/XSS攻击检查工具)
安裝/使用方法:
apt-get install libtidy-0.99-0 python-ctypes python-utidylib
python wapiti.py http://Your Website URL/ -m GET_XSS

Pixy: XSS and SQLI Scanner for PHP( Pixy – PHP 源码缺陷分析工具)
安裝: apt-get install default-jdk
Remote PHP Vulnerability Scanner(自动化 PHP页面缺陷分析, XSS检测功能较强)
PHPIDS – PHP 入侵检测系統

VN:F [1.9.22_1171]
Rating: 0.0/10 (0 votes cast)
VN:F [1.9.22_1171]
Rating: 0 (from 0 votes)

程序开发 ,