May 03
之前给学院弄的两个站都需要数据迁移,一个是Access to Mysql,一个是Excel to Mysql。后者可以把Excel转成Access,所以说到底还是Access to Mysql。
Access to Mysql主要途径有二:工具法和脚本法。前者可以用Navicat等Mysql批量转换,简单又快但不灵活;后者虽然比较麻烦,但效果好,且灵活,这里用到的是第二种。
由于远程服务器不能在PHP上使用Access,所以我是在本机上使用APM Express,把数据导入到本地数据库,再用Navicat迁移到远程数据库,现实使用的效果还不错。
我的目录设置为
根目录为/site
FleaPHP程序目录为/site/APP
迁移数据的原理基本上就是,同时打开ADODB(连接Access)和FleaPHP下的TDG(连接Mysql),再同时读数据和写数据。
先建立一个/site/inc/_common.php文件,由于用不上MVC,所以要用这个来启动非MVC模式的FleaPHP。
<?php
/**
* 将FleaPHP以non-MVC模式启动,用于传统开发方式
*
* @author Hicrokee hicrokee@gmail.com
* @version 1.0
* @date Thu Mar 13 15:33:02 CST 2008
*/
define('DEPLOY_MODE', true);
define('LIB_DIR', realpath(dirname(__FILE__) . '/../APP'));
require('../FLEA/FLEA.php');
FLEA::loadAppInf(LIB_DIR.'/Config/common.php');
FLEA::import(LIB_DIR);
FLEA::init();
再建立/site/TOOLS/db.php文件,把ACCESS数据库放在同一目录,这个示例代码包含了编码转换,时间STAMP转换,文本替换等常用功能。$rs->Fields($field)的$field值是从0开始,从左到右数的字段序号。
<?php
include('../inc/_common.php');
//初始化mdb数据库
$conn = new com("ADODB.Connection");
$connstr = "DRIVER={Microsoft Access Driver (*.mdb)}; DBQ=". realpath("ncms.mdb");
$conn->Open($connstr);
$rs = new com("ADODB.RecordSet");
//初始化Mysql数据库
$tblArticles = FLEA::getSingleton('Table_Articles');
/* @var $tblArticles Table_Articles */
$rs->Open("select * from NCMS_news",$conn,1,1);
$rows = array();
while(! $rs->eof) {
$row = array();
$row['title'] = iconv('GB2312','UTF-8',$rs->Fields(2));//新数据库所有的字段比原数据库长,所以都不用截
$row['content'] = iconv('GB2312','UTF-8',str_replace('new/tools/loadimg.asp?FileName=','site/upload/news/oldimg/',$rs->Fields(3)));
$row['author'] = iconv('GB2312','UTF-8',$rs->Fields(4));
$row['source'] = iconv('GB2312','UTF-8',$rs->Fields(5));
$row['created'] = iconv('GB2312','UTF-8',strtotime($rs->Fields(16)));//时间STAMP转换
$row['updated'] = $row['created'];
$row['class_id'] = 58;//因为迁移时分类改变了,干脆重置为同一个数字
$rows[] = $row;
$rs->MoveNext();
}
$tblArticles->saveRowset($rows,false);
echo '数据转换成功,为了安全,请删除或重命名本文件。';
?>
转换后记得检查是否正确,这里演示用的数据量很少,所以直接用数组缓存了再导入Mysql,如果数据多的话,可以不用TDG而用回原生的PHP代码,另外也要读一部分数据写一部分数据。本例仅适用于少数据的情况。
Apr 24
最近给学院弄的那个院网,真的把我囧死了,在本地调试很正常很安全的站,一上学校服务器就一大堆问题,而且都很隐蔽,服务器用的是IIS+PHP插件,版本很新,可惜真不明白它怎么配置的,老是跟我的网站过不去。
跟以往一样,由于服务器支持PHP+Mysql,所以选择了FleaPHP+Smarty的搭配,前台不用自己弄,所以什么jQuery呀Mootools呀就不用理了。
网站一传上去第一眼就让我傻了眼,全空白,无论前台后台都一样,一片白茫茫,开始以为是文件编码问题,但检查了一遍也找不到。于是上网问同行,被告之FLEA这个目录如果传输不完整的话也有这个可能,觉得有道理,于是重传了一遍,依然不行。后来用phpinfo查了一下,才知道这网站关了display_error的,后来逐行加echo(本地可以用ZDE调试,但远程就……),发现停在FLEA::runMVC,由于是在某人机子上调试的,东西用起来很麻烦,就没继续下去。
当时觉得是因为服务器用了中文目录,导致的问题,但没有显错,什么都做不了。于是找技术中心那边的某老师改成英文目录名,下午一早下班就回来调试,却发现,依然有问题。
于是有自己的机器用ZDE连上去,依然是用echo法,发现停在预载入文件里,在载入Lib_Core时出错了,这是我写的一个核心库,一直用都没问题,再跟踪,发现问题出在这一句
/**
* 修正时差 当前时区为 中华人民共和国
*/
date_default_timezone_set('PRC');
服务器本身已经有时区设定了,但在一般来说这句都不会有问题,汗一个校服务器先。
搞定这个之后就能显示了,用Navicat上传了Mysql数据库后(汗,我最以为会出问题的地方,居然成功运行了),就做点小改动,把文件整理好,把权限设置好,本以为搞定了,想不到恶梦又来了。
因为前台有点改动,于是就动了一下TPL目录,这是我放Smarty和非Smarty模板的目录,更新了里面的文件后发现更新不能,自然就想到是编译目录的问题,删了一大堆tmp、php、ini文件后(注意了,有tmp),居然出问题了,再度白屏。
这次的白屏是所有涉及Smarty的地方,开始以为是Smarty的目录权限不够,一查发现全是0777,重传了一次Smarty Libs,问题依然,重传了一次整站,问题依然,于是好奇地把本地调试时弄的旧的TPL和TPL_C(编译目录)的文件覆盖回去,居然又能动了??!!
再对比一下本地的TPL_C和服务器上的TPL_C,可以发现本地的文件全是php和ini格式的编译文件,而服务器上的全是tmp,上Smarty的官网查了一下,终于找到答案:
Smarty的编译文件是先生成tmp格式的临时文件再重命名回php和ini格式的编译文件的,使用的文件是:
internals/core.write_file.php,
官网上谈到这种情况,都围绕着一个问题:目录权限,但明显的,我的全是0777,并不是权限问题。
其他的谈及的情况如禁了tempnam(),目录不完整等,通过Debug,发现也没有这类问题。
那只好自己找问题了。
参考链接:
http://www.phpinsider.com/smarty-forum/viewtopic.php?t=1519
http://www.phpinsider.com/smarty-forum/viewtopic.php?t=4500
http://www.phpinsider.com/smarty-forum/viewtopic.php?t=5575
服务器上只有tmp而没有php和ini,明显的,我上传到服务器上的程序,能生成tmp但不能被重命名为目标文件名,通过调试,发现问题果然出现在rename上。
既然rename不能,那就只有用其他折衷的方法,我的方法是,不生成临时文件,直接生成新文件。
修改的文件是internals/core.write_file.php
旧的代码是:
function smarty_core_write_file($params, &$smarty)
{
$_dirname = dirname($params['filename']);
if ($params['create_dirs']) {
$_params = array('dir' => $_dirname);
require_once(SMARTY_CORE_DIR . 'core.create_dir_structure.php');
smarty_core_create_dir_structure($_params, $smarty);
}
// write to tmp file, then rename it to avoid file locking race condition
$_tmp_file = tempnam($_dirname, 'wrt');
if (!($fd = @fopen($_tmp_file, 'wb'))) {
$_tmp_file = $_dirname . DIRECTORY_SEPARATOR . uniqid('wrt');
if (!($fd = @fopen($_tmp_file, 'wb'))) {
$smarty->trigger_error("problem writing temporary file '$_tmp_file'");
return false;
}
}
fwrite($fd, $params['contents']);
fclose($fd);
if (DIRECTORY_SEPARATOR == '\\' || !@rename($_tmp_file, $params['filename'])) {
// On platforms and filesystems that cannot overwrite with rename()
// delete the file before renaming it -- because windows always suffers
// this, it is short-circuited to avoid the initial rename() attempt
@unlink($params['filename']);
@rename($_tmp_file, $params['filename']);
}
@chmod($params['filename'], $smarty->_file_perms);
return true;
}
新修改成的代码为:
function smarty_core_write_file($params, &$smarty)
{
$_dirname = dirname($params['filename']);
if ($params['create_dirs']) {
$_params = array('dir' => $_dirname);
require_once(SMARTY_CORE_DIR . 'core.create_dir_structure.php');
smarty_core_create_dir_structure($_params, $smarty);
}
$fd = @fopen( $params['filename'], 'wb');
if(!$fd) return false;
fwrite($fd, $params['contents']);
fclose($fd);
@chmod($params['filename'], $smarty->_file_perms);
return true;
}
但如代码中注释所述,这个机制是为了解决文件死锁如写冲突一类的问题的,所以这种处理方法会有一定的可能出错,但学院网站的TPL不多,也不常改,这个可能可忽略不计,能用就好,折衷的处理也是无奈的事。
Recent Comments