分類彙整: program

php preg_replace bug ??

這個問題在在Zend Framework 中
Zend/Db/Statement.php
裡面
[cc lang=”php” tab_size=”2″ lines=”40″]
protected function _stripQuoted($sql)
{
// get the character for delimited id quotes,
// this is usually ” but in MySQL is `
$d = $this->_adapter->quoteIdentifier(‘a’);
$d = $d[0];

// get the value used as an escaped delimited id quote,
// e.g. ” or “” or `
$de = $this->_adapter->quoteIdentifier($d);
$de = substr($de, 1, 2);
$de = str_replace(‘\’, ‘\\’, $de);

// get the character for value quoting
// this should be ‘
$q = $this->_adapter->quote(‘a’);
$q = $q[0];

// get the value used as an escaped quote,
// e.g. ‘ or ”
$qe = $this->_adapter->quote($q);
$qe = substr($qe, 1, 2);
$qe = str_replace(‘\’, ‘\\’, $qe);

// get a version of the SQL statement with all quoted
// values and delimited identifiers stripped out
// remove “foo”bar”
$sql = preg_replace(“/$q($qe|\\{2}|[^$q])*$q/”, ”, $sql);
// remove ‘foo’bar’
if (!empty($q)) {
$sql = preg_replace(“/$q($qe|[^$q])*$q/”, ”, $sql);
}

return $sql;
}

[/cc]
發現的
我是要執行一段db->query($sql)
sql 是 insert into xxx
有把sql 單純的print 出來到mysql 中執行是可以成功執行的
trace 到最後發現會卡在preg_replace這邊
而看httpd error , access log 都沒有訊息
看message log 就會出現
Nov 12 13:22:33 mail kernel: pid 50728 (httpd), uid 80: exited on signal 4
所以判斷應該是
php 的bug

我的解法是不用preg_replace 換成
ereg_replace, mb_ereg_replace
都可以.

Zend Framework DB Load Balancing (Master/Slave Database)

網路上找來找去……
沒看到有人寫相關的解法….
加上不想用mysql-proxy來解這部份…

所以打算從code 的部份下手
看到最後只能動Zend Framework 的code 了(還沒想到可以不動ZF 的code 而做到DB LB的方法)

我是先從function save 下手去找..

Zend/Table/Row/Abstract.php:    public function save()

[sourcecode language=’php’]
public function save()
{
/**
* If the _cleanData array is empty,
* this is an INSERT of a new row.
* Otherwise it is an UPDATE.
*/
if (empty($this->_cleanData)) {
return $this->_doInsert();
} else {
return $this->_doUpdate();
}
}
[/sourcecode]

ZF會自已做update or insert 的區分

再看
[sourcecode language=’php’]
/**
* @return mixed The primary key value(s), as an associative array if the
* key is compound, or a scalar if the key is single-column.
*/
protected function _doInsert()
{
/**
* A read-only row cannot be saved.
*/
if ($this->_readOnly === true) {
require_once ‘Zend/Db/Table/Row/Exception.php’;
throw new Zend_Db_Table_Row_Exception(‘This row has been marked read-only’);
}

/**
* Run pre-INSERT logic
*/
$this->_insert();

/**
* Execute the INSERT (this may throw an exception)
*/
$data = array_intersect_key($this->_data, $this->_modifiedFields);
$primaryKey = $this->_getTable()->insert($data);

/**
* Normalize the result to an array indexed by primary key column(s).
* The table insert() method may return a scalar.
*/
if (is_array($primaryKey)) {
$newPrimaryKey = $primaryKey;
} else {
$newPrimaryKey = array(current((array) $this->_primary) => $primaryKey);
}

/**
* Save the new primary key value in _data. The primary key may have
* been generated by a sequence or auto-increment mechanism, and this
* merge should be done before the _postInsert() method is run, so the
* new values are available for logging, etc.
*/
$this->_data = array_merge($this->_data, $newPrimaryKey);

/**
* Run post-INSERT logic
*/
$this->_postInsert();

/**
* Update the _cleanData to reflect that the data has been inserted.
*/
$this->_refresh();

return $primaryKey;
}
[/sourcecode]

$primaryKey = $this->_getTable()->insert($data);

程式在
Zend/Adapter/Abstract.php
這邊有
function update()
function insert()

來看
[sourcecode language=’php’]
public function insert($table, array $bind)
{
// extract and quote col names from the array keys
$cols = array();
$vals = array();
foreach ($bind as $col => $val) {
$cols[] = $this->quoteIdentifier($col, true);
if ($val instanceof Zend_Db_Expr) {
$vals[] = $val->__toString();
unset($bind[$col]);
} else {
$vals[] = ‘?’;
}
}

// build the statement
$sql = “INSERT INTO ”
. $this->quoteIdentifier($table, true)
. ‘ (‘ . implode(‘, ‘, $cols) . ‘) ‘
. ‘VALUES (‘ . implode(‘, ‘, $vals) . ‘)’;

// execute the statement and return the number of affected rows
$stmt = $this->query($sql, array_values($bind));
$result = $stmt->rowCount();
return $result;
}
[/sourcecode]

不管insert or update
都是透過query 這個method 去執行sql

所以就在這邊下手吧

[sourcecode language=’php’]
public function query($sql, $bind = array())
{
// connect to the database if needed
if ($sql instanceof Zend_Db_Select) {
if (preg_match(‘/UPDATE|INSERT|REPLACE/i’,$sql->__toString())) {
$this->closeConnection();
$this->_config[‘dbname’] = ‘DB_WRITE’;
}
} else {
if (preg_match(‘/UPDATE|INSERT|REPLACE/i’,$sql)) {
$this->closeConnection();
$this->_config[‘dbname’] = ‘DB_WRITE’;
}
}
$this->_connect();

// is the $sql a Zend_Db_Select object?
if ($sql instanceof Zend_Db_Select) {
$sql = $sql->assemble();
}

// make sure $bind to an array;
// don’t use (array) typecasting because
// because $bind may be a Zend_Db_Expr object
if (!is_array($bind)) {
$bind = array($bind);
}

// prepare and execute the statement with profiling
$stmt = $this->prepare($sql);
$stmt->execute($bind);
// return the results embedded in the prepared statement object
$stmt->setFetchMode($this->_fetchMode);

if ($sql instanceof Zend_Db_Select) {
if (preg_match(‘/UPDATE|INSERT|REPLACE/i’,$sql->__toString())) {
$this->closeConnection();
$this->_config[‘dbname’] = ‘DB_READ’;
$this->_connect();
}
} else {
if (preg_match(‘/UPDATE|INSERT|REPLACE/i’,$sql)) {
$this->closeConnection();
$this->_config[‘dbname’] = ‘DB_READ’;
$this->_connect();
}
}
return $stmt;
}
[/sourcecode]

就是很簡單的去parse $sql 是否有UPDATE,INSERT,REPLACE 之類的寫入語法
若有的話就改config

基本上就是這樣…

如果有人有更好的做法…
拜拖 指教一下小第………..
實在是不想弄到ZF 裡面的code 來達到DB LB的功能..

PHP Universal Feed Generator中文問題..

之前忘了在那看到這個 PHP Universal Feed Generator 感覺還滿好用的…
結果就在這幾天要用的時後…
發現他中文在轉碼的時後有問題…
trace 一下他的code 發現是298 行的
htmlentities($tagContent);這個的問題
把他換成
htmlentities($tagContent, ENT_COMPAT, ‘utf-8’);
應該就可以了
另外看了一下他在header 的部份沒有宣告是UTF8
所以我也修改了一下….
在84 行
header(“Content-type: text/xml”);
改一下
header(“Content-type: text/xml; charset=UTF-8”);

基本上這樣應該就可以了…

php找出日期的差距天數

記得先compile calendar 這個php extension 才會有
gregoriantojd 這個function..

http://roshanbh.com.np/2008/03/finding-days-difference-php.html

PS
之前都是自已硬幹…..
用mktime date轉來轉去才算出來的…

subversion without apache….

#vim /usr/local/etc/ports.conf

devel/subversion: WITHOUT_BDB | WITHOUT_NEON | WITH_APACHE2_APR | WITH_SVNSERVE_RAPPER | WITH_MOD_DAV_SVN

接下來就去/usr/ports/devel/subservion 下裝起來

#vim /etc/rc.conf
svnserve_enable=”YES”
svnserve_flags=”-d –listen-port=3690 –listen-host=0.0.0.0″
svnserve_data=”/home/svnroot”
svnserve_user=”www”
svnserve_group=”www”

svnserver_data 記得設一下…
不然default 會在 / 根目錄下…

mkdir -p /home/svnroot/projectName ; svnadmin create /home/svnroot/projectName

編輯一下權限
先去/home/svnroot/projectName/conf
這個目錄下會有這三個檔案
authz, passwd, svnserve.conf
設定檔案位置
#vim /home/svnroot/projectName/conf/svnserve.conf
設定authd 和passwd
兩個檔案的位置
password-db = passwd
authz-db = authz

#vim authz
[/]
* = r
www = rw
root = rw
[projectName:/]
* = r
www = rw
root = rw

#vim passwd
[users]
# harry = harryssecret
# sally = sallyssecret
www = www(你的密碼)
root = root(你的記密)

就這樣….非常的簡易…. :8-):

找出Table 中 資料相同的Record

因為有遇到這個問題
所以特別寫出來備忘
SELECT *
FROM bb_downloads a
WHERE
(SELECT count( * )
FROM bb_downloads b
WHERE b.post_id = a.post_id
AND b.url = a.url
) >1
ORDER BY `post_id`,`download_times` DESC

reference

UPDATE: 2007/10/14
找出不相同的資料
非常的easy
select r.user_id from rtable r WHERE r.user_id not in (select a.user_id from atable a)
刪除不相同的資料
delete from rtable WHERE user_id not in (select a.user_id from atable a)

smarty rawurldecode plugin …..

因為我在smarty 上不能直接用php的rawurldecode ,所以自已寫了一個smarty 的function 傳回rawurldecode 過的值給smarty 就這樣而已…..

<?php
/**
* Smarty plugin
* @package Smarty
* @subpackage plugins
*/
function smarty_function_rawurldecode ($params, &$smarty) {

if (empty($params[‘lastpage_url’])){
$smarty->_trigger_fatal_error(“[rawurldecode] param lastpage_url cannot be empty”);
return;
}
if (isset($params[‘lastpage_url’])){
$return = $params[‘lastpage_url’];
$return = rawurldecode($return);
}
return $return;
}

?>

reference…
How to write a custom Smarty function in php

:(h):