tagged “PHP”
自从用上了PHP5.3,问题还真是多,自上次出现连接MS SQL Server的问题后,这次在安装 Zend Debugger时又出现了问题。按照Zend官方给出的Zend Debugger安装步骤,从 这里 下载了最新的 5.2版本的Studio Web Debugger,从解压出的ZendDebugger-v5.2-cygwin_nt-i386\5_3_x_nts_comp目录中复制ZendDebugger.dll 到PHP安装文件夹下的ext目录,然后编辑php.ini文件,在文件最后加入一下三行:
zend_extension = "d:/php/ext/ZendDebugger.dll"
zend_debugger.allow_hosts= 127.0.0.1
zend_debugger.expose_remotely=always
然后把dummy.php文件复制到apached的 "DocumentRoot"目录(在http.conf文件中设定),可重启Apache服务后 用phpinfo()显示的页面中并没有Zend Debugger,很明显,安装没有成功。
回过头再仔细看Zend的安装步骤介绍,发现zend_extension这项配置有两种,除了zend_extension以外,还有设置为zend_extension_ts的,分别适用于Non-Thread-Safe和Thread-Safe版的PHP,而我安装的PHP是Thread-Safe版的(通过phpinfo() 页面的Thread Safety选项可以查看到),所以应该用zend_extension_ts,但是我下载的Studio Web Debugger 针对php 5.3版的只有nts版的ZendDebugger.dll (从文件夹名称可以看出-5_3_x_nts_comp).
仔细搜了一下,终于找到了答案,在Zend 论坛里一位Zend 员工明确地回复:"目前还没有针对 Thread-Safe 的PHP 5.3发布相应的Zend Debugger的计划",这个帖子 里,另一位Zend员工针对用户在Thread Safe 版PHP 5.3 安装 Zend Debugger失败的原因做了更详细的解释:
Zend stopped supporting the thread safe architecture when Microsoft also decided to implement its PHP engine with the fast-cgi architecture which means non-thread-safe.
他建议用户用安装Zend Server(目前已经支持PHP 5.3)-- Zend Server包含的是Non Thread Safe 版的PHP.
相关链接:
Zend论坛 - 安装Zend Debugger 的非常详细的教程: Zend Forums • View topic - Sticky Notes Setting Up Zend Debugger
针对不同平台的最新Zend Debugger 下载列表
最近做的一个项目需要用PHP连接到MS SQL Server,在公司安装的PHP是5.2版的,Windows平台的PHP Zip安装包解压后的扩展目录(ext)里有自带连接到SQL Server的驱动文件-php_mssql.dll,只需先将PHP目录的ntwdblib.dll拷贝到系统盘下windows/system32,然后修改php.ini,取消;extension=php_mssql.dll 前面的;,重启Apache服务器就可以了。
但是家里用的是WAMP集成安装包,PHP版本是5.3.2,扩展目录里没有php_mssql.dll,而且连ntwdblib.dll也没有,从PHP 5.2分别拷贝这两个文件到扩展目录和系统目录,重启Apache,提示mssql模块和php编译版本不匹配(如下图):
在网上搜索了一下PHP 5.3.X 连接SQL Server的办法,有人也遇到了这个问题 (PHP Unable to Connect to MSSQL),原来PHP 团队在PHP 5.3 中移除了SQL Server的驱动和库,而微软自己开发了针对PHP的SQL驱动(SQL Server Driver for PHP),但是1.0版的不支持 PHP 5.3,1.1版本才支持,但即使用这种办法,也不是官方推荐的原生的支持,如果要用直接支持的办法,可以用ODBC来连接。这位作者对PHP 5.3连接 SQL Server的问题颇有研究,发了一系列的文章来说明问题的来龙去脉(No SQL Server Library for PHP 5.3 Just Yet,Installing PHP 5.3 on Microsoft IIS,Finally a working SQL Server Driver for PHP 5.3,Installing FastCGI and PHP for IIS 6.0)。 Finally a working SQL Server Driver for PHP 5.3 这篇文章的留言中有人给出了 他自己编译的PHP 5.3.0 连接 MS SQL Server所需的 php_mssql.dll 文件,但是这个文件之能用于VC9 PHP(何为VC9 PHP,请看补充内容)。
在SQL Server in PHP 5.3 这篇帖子的回复里,有人提到PHP 5.3.1里面有 php_mssql.dll,于是到PHP 官方网站,却只提供PHP 5.2和最新的PHP 5.3.2下载,最后还是在WAMP网站提供的 PHP Addon中找到了PHP 5.3.1,拷贝mssql扩展文件到WAMP 的PHP扩展目录,问题解决!
补充:关于VC9 和VC6 版本的PHP
If you are using PHP with Apache 1 or Apache2 from apache.org you need to use the VC6 versions of PHP
If you are using PHP with IIS you should use the VC9 versions of PHP
VC6 Versions are compiled with the legacy Visual Studio 6 compiler
VC9 Versions are compiled with the Visual Studio 2008 compiler and have improvements in performance and stability. The VC9 versions require you to have the Microsoft 2008 C++ Runtime (x86) or the Microsoft 2008 C++ Runtime (x64) installed
Do NOT use VC9 version with apache.org binaries
相关链接:
PHP: Installation of extensions on Windows - Manual
登陆验证应该是Web程序员必须掌握的最基本的东西了,乍看起来似乎很简单,但随着学习相关技术的深入,考虑到安全性,用户体验等方面的要求,其实不简单,下面就以我做的一个小项目(回味乐食品网站)后台登陆页面为例来说明。
简单的登陆页面:
<html> <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<link rel="stylesheet" href="../css/stylesheet.css" type="text/css" media="screen,print"> <title>回味乐食品厂-用户登录</title> </head> <body> <form name="login" action="" method="post" style="margin-top:80px">
<table align="center">
<tr>
<td>用户名:</td>
<td><input type="text" name="user" id="user"></td> <td class="resetMsg" id="userMsg" /></td>
</tr>
<tr>
<td>密码:</td>
<td><input type="password" name="password" id="password"></td> <td class="resetMsg" id="psdMsg" /></td>
</tr>
<tr>
<td></td>
<td><input type="submit" name="login" id="login" value="登陆" align="left" style="width:60" onClick="javascript:return CheckTxt();" /></td> </tr>
</table>
</form> </body> </html>
页面的表单有两个输入框,分别输入用户名和密码,id为"login"的提交按钮在提交时触发Javascript方法CheckTxt()验证用户输入。由于Javascript方法是在客户端实现,所以验证仅限于对输入内容是否为空的判断,为了更好的用户体验,出错提示不采用弹出对话框的方式,而是把提示内容输出到输入框右边的<td>内容框当中(id分别为userMsg和psdMsg)。下面是列出了所有可能的情况和出错时输出的提示:
- user为空,password也为空:userMsg和psdMsg分别给出"缺少用户名"和"缺少密码"的提示;
- user为空,password不为空:userMsg给出"缺少用户名"的提示,同时psdMsg的提示为空;
- user不为空,password为空:userMsg的提示为空,psdMsg给出"缺少密码" 的提示;
- user和password均不为空:userMsg和psdMsg的提示都为空。
为了让验证更高效,在程序具体实现的时候要先考虑出错的情况,也就是前面三种,出现错误就立即终止并返回false,这样就不必再往下执行判断了。
Javascript方法CheckTxt():
<script type="text/javascript">
function CheckTxt()
{
var user = document.getElementById("user").value
var password = document.getElementById("password").value
if( user == "") //用户名为空
{
document.getElementById("userMsg").innerHTML ="缺少用户名";
document.getElementById("user").focus();
if(password == "") //用户名为空且密码为空
{
document.getElementById("psdMsg").innerHTML = "缺少密码";
} else //用户名为空,密码不为空
{
document.getElementById("password").value ="";
document.getElementById("psdMsg").innerHTML ="";
}
return false;
} else if(password == "") //用户名不为空,密码为空
{
document.getElementById("userMsg").innerHTML ="";
document.getElementById("psdMsg").innerHTML = "缺少密码";
document.getElementById("password").focus();
return false;
}
else //用户名和密码都不为空
{
return true;
}
}
</script>
上面提到,在出错一旦发生,就需要给出出错提示从方法中返回,再看上面代码,为什么在用户名为空的情况,没有立即返回false,还需要再判断密码是否为空呢?仔细想一下就会清楚,如果在只判断了用户名为空的情况下就立即返回false,那么在用户名和密码都为空的情况下页面只会提示"缺少用户名",不够全面和准确。如果你再仔细看看淘宝网和Gmail的登陆页面,就会更明白了。
还要注意的一个细节是在判断为空后应该设置焦点,以方便用户输入。
完成了客户端的验证,下面就要在服务器端进行验证了。为了更准确地给出出错信息,在查询MySQL数据库中的记录时,查询条件可以只指定用户名,这样就能够判断数据库中是否有用户输入的用户,如果没有,就给出"没有此用户"的提示,如果有,则进一步把用户输入密码和数据库中的记录进行对比。为了防止SQL注入攻击,在查询和比对的时候需要用mysql_real_escape_string()方法对表单提交的字段的内容中的特殊字符进行转义。
PHP验证代码清单:
<?php
//处理未登陆时访问此页面的情况
if(is_null($_SESSION['login'])){
//处理表单提交后的情况
if(isset($_POST["user"])){
$user = $_POST["user"];
$password = $_POST["password"];
require("../include/dbconnect.txt");
db_connect();
//用mysql_real_escape_string() 函数对用户输入进行转义,防止SQL注入攻击
$queryUser = "select * from users where user ='" .mysql_real_escape_string($user)."'";
$result = mysql_query($queryUser);
$row = mysql_fetch_array($result);
if(!$row) { //如果用户名不存在
print '<script type="text/javascript">';
print "document.getElementById('userMsg').innerHTML ='用户名不存在'\n";
print "document.getElementById('user').focus()";
print '</script>';
} else { //如果存在,对比数据库中的密码和用户输入的密码(先进行转义 )
if($row["password"] == mysql_real_escape_string($password)) {
if(is_null($_SESSION["url"])) {
print '<script type="text/javascript">';
print 'self.location.href= "index.php"';
print '</script>';
} else { //未登陆的情况下从"其他页面"redirect到此登陆页面, 登陆成功后页面直接跳转到"其他页面",而不是index.php
print '<script type="text/javascript">';
print "self.location.href='".$_SESSION["url"]."'";
print '</script>';
}
$_SESSION["login"] = 1;
} else {
print '<script type="text/javascript">';
print "document.getElementById('psdMsg').innerHTML = '密码不匹配'\n"
print "document.getElementById('user').value ='".$user."'\n";
print "document.getElementById('password').focus()";
print '</script>';
}
}
mysql_close();
}
} else {
print '<script type="text/javascript">';
print "window.onload = function()\n";
print "{";
print "document.getElementById('user').focus()\n";
print "}";
print '</script>';
//登陆后再访问此页面的情况,清除会话$_SESSION['login']
unset($_SESSION['login']);
unset($_SESSION['url']);
}
?>
这个例子是整个网站的一部分,所以以上这段代码有几处需要注意的地方:is_null($_SESSION['login'])是对SESSION变量$_SESSION['login']进行判断,如果用户在未登陆的情况下访问此页面(听着似乎有些矛盾,呵呵),则值为Null。用户在已登录的情况下再访问登陆页面,会清除会话$_SESSION['login']。
另外,在PHP代码中当中调用Javascript需注意如果Javascript代码语句有多行, 在每行结束时要加上\n,而且要被包含在""中,因为''在PHP不能对\n进行转义。
实例在这里:http://www.zhouhongquan.com/projects/hwlsp/admin/login.php



