Tech memo 分类
最近做的一个项目需要用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
cat: error while loading shared libraries: libc.so.6: cannot open shared object file: No such file or directory/bin/sh: error while loading shared libraries: libdl.so.2: cannot open shared object file: No such file or directoryStarting XAMPP for Linux .../bin/bash: error while loading shared libraries: libdl.so.2: cannot open shared object file: No such file or directory/bin/bash: error while loading shared libraries: libdl.so.2: cannot open shared object file: No such file or directory/bin/bash: error while loading shared libraries: libdl.so.2: cannot open shared object file: No such file or directory/bin/bash: error while loading shared libraries: libdl.so.2: cannot open shared object file: No such file or directory/bin/bash: error while loading shared libraries: libdl.so.2: cannot open shared object file: No such file or directoryXAMPP for Linux started.
vi 编辑器有其特殊的使用方法,这里有比较详尽的介绍,就不再赘述。 事实证明,前面的办法还真行,但具体是什么原因就不清楚了。vi /opt/lampp/lampp
找到:export LD_ASSUME_KERNEL=2.2.5
改为:export LD_ASSUME_KERNEL=2.8.0
现在,就可以通过http://localhost 来访问XAMPP的起始页面了,LAMP系统也就搭建成功了
最近开始熟悉LAMP(即Linux-Apache-MySQL-PHP)WEB开发框架,从安装Fedora开始,先从Fedora Project 下载最新的Fedora 9安装DVD的 ISO镜像文件 。为了方便起见,我选择在虚拟机中安装Fedora,最著名的两大虚拟机软件就是微软的Microsoft Virtual PC (最新版2007,另外SP1补丁竟然比主程序的安装文件还略大,微软的补丁真可谓是补到家了,呵呵)和VMware ,其实Virtual PC 最开始并不是微软自己的项目,而是出自一个叫做Connectix的公司,后来微软收购了它 。以前听微软TechNet的课时经常看到讲师在演示操作的时候用到Virtual PC,看着挺不错的,现在轮到自己尝试,发现简单得有些简陋,在创建虚拟机的时候可以选择安装的客户机操作系统(guest operating system)类型,提供的选项都是微软阵营的,有Win98、Win2000、WinXP、Win2003 等,在虚拟的BIOS中选择从光驱启动,把安装光盘放进光驱,或者在Virtual PC的"CD"菜单的"Capture ISO Image"选择要安装的操作系统的ISO文件,按照提示,就和平时在PC上安装系统一样。可惜的是它对Linux 的支持一点也不好,在安装Unbuntu的过程中,我就遇到了显示的问题,后来在网上搜索,看到有很多人也遇到同样的问题,但解决起来似乎不容易,且版本不同也有细微差别,后来还是放弃了,把目光投向VMware。
和Virtual PC 2007不同,VMware Workstation的安装文件就有300多M,最新版的VMware 6.0.4 build:93057,从官方网站也只能下载到试用版的。VMware对Linux的支持不错,在新建虚拟机的过程中有Microsoft Windows、Linux、Novell Netware、Sun Solaris多个选项可供选择,这些大项下面还有许多更为细致的小项可供选择。对虚拟机占用的内存和硬盘空间应根据实际情况做合理设置,我要安装的Fedora 9 由于是最新版的桌面系统,对内存大小和硬盘空间都有比较高的要求,所以我设置的值分别是512M和10G。在虚拟机的属性中把CD-ROM设置为"Using ISO image",选择要安装的操作系统的ISO文件。安装过程比较顺利,即使以前没用过Linux也能够比较轻松的进行,设置的东西不多,按提示来就可以了。
系统安装好了,不过有两个地方让人感觉不太好:每次从Fedora切换回Windows时都要按Ctrl+Alt,比较麻烦;显示分辨率只能设置为800*600,将虚拟机全屏时内容只占据屏幕正中央的大部分,四边还离屏幕周边还有些距离,就像EeePC的屏幕。原本只是因为在安装好的Fedora客户机和宿主机(WinXP SP3)之间无法复制文件而安装VMware Tools,没想到安装好VMware Tools之后上面两个问题都得到解决,的确是意外的惊喜:鼠标在Fedora用户界面和WindowsXP宿主机之间可以自由"出入",在Fedora中在窗口在最大化后所有界面充满了整个屏幕,就像在本机真实安装的一样。
安装VMware Tools的过程我也是在网上搜到的,具体过程如下:
-
安装虚拟机的时候网卡设置为本机的物理网卡。
-
启动虚拟机,选择VMware Tools的VM菜单的Install VMware Tools选项,注意状态栏的提示。
-
选择VMware Tools的VM菜单的Removable Devices子项中的CD-ROM项,点击Edit,在Use ISO image下点击Browse,在打开的对话框中选择VMware程序文件目录下的Linux.iso。
-
进入Fedora命令行模式(纯命令行模式我也不知道咋进,我是在用户界面下的终端模式里输入命令的,另:一定要用root身份登陆),输入 mount /dev/cdrom /mnt/cdrom,然后输入 cd/mnt/cdrom。
-
打开cdrom文件夹,这时应该可以看到有两个文件,一个是VMwareTools*.rpm(*部分根据VMware的版本不同而有所差异,我用的是VMware 6.0.4 build93057,在这里文件名为VMwareTools-6.0.4-93507.i386.rpm),在终端中输入rpm -ivh VMwareTools*.rpm;还有一个文件是VMwareTools*.tar.gz (和前面的文件名类似),依次输入以下命令 cp VMwareTools*.tar.gz /tmp、 cd /tmp、 tar xzvf VMware-tools*.tar.gz、cd vmware-tools-distrib,打开vmware-tools-distrib文件夹,里面会有一个vmware-install.pl 文件,输入./vmware-install.pl,在接下来安装过程中的提示中一直按回车。
-
在 /mnt文件夹下,会发现此时多了一个hgfs的文件夹,表明VMware Tools安装成功了。
-
最后一步,设置文件夹共享,VM菜单里进行,选择Setting子项,再选择Options,在窗体的左半部分有一个Shared Folders选项,默认情况下是Disabled,选择Always enabled,在下面的Folders中添加要共享的文件夹目录,这样,客户机(Fedora)和宿主机(WinXP)都可以访问共享目录下的文件了,可以用在Windows中拷贝相应文件到Fedora。最后,用umount /mnt/cdrom卸载光驱。
今天在安装Silverlight和微软拼音输入法2007 的时候,出现安装错误的提示,在安装其他使用Windows Installer服务的程序时候也是如此。打开控制面板的事件查看器,在"应用程序"的出错记录是
"产品: 微软拼音输入法2007 -- 安装程序在安装此软件包时遇到一个错误。这可能表示此软件包有错。错误码是 2203。参数是: C:\WINDOWS\Installer\3deaa.ipi, -2147287035,"
"Product: Microsoft Silverlight -- The installer has encountered an unexpected error installing this package. This may indicate a problem with this package. The error code is 2203. The arguments are: C:\WINDOWS\Installer\442279.ipi, -2147287035, "
可以看到,出错原因的描述是类似的,前面部分说程序遇到错误,可能表示软件包有错,后面解释详细情况:"错误码为xxxx。参数是:C:\WINDOWS\Installer\xxxxx.ipi,-xxxxxxxxxx,"。先来分析,安装文件本身是没有问题的,都是完整的,而Windows Installer服务也是正确安装了的,版本是3.1,服务也在运行状态。在网上G了一下Windows Installer出错的解决办法,但大部分是由于Windows Installer服务本身的问题造成的,出错情况和上面也不一样。搜索"C:\WINDOWS\Installer ipi",终于找到了解决办法 ,作者给出了几种可能的原因:
- 当前登录用户的用户环境变量必须包括 TEMP:%USERPROFILE%\Local Settings\Temp 和 TEM:%USERPROFILE%\Local Settings\Temp (其中,%USERPROFILE%是当前登录用户的配置文件路径,如当前登录用户为Admin,则其对应的%USERPROFILE%为C:\Documents and Settings\Admin)
- 当前登录用户应该有管理权限,即,当前用户应该属于Administrator或者Power Users用户组。
- 确保"计算机名\SYSTEM"用户拥有对"C:\Documents and Settings\<当前登录用户名>\Local Settings\Temp"文件夹的绝对控制权。
- 对于某些软件,可能还需要"计算机名\SYSTEM"用户拥有对"C:\Documents and Settings\<当前登录用户名>\Local Settings\Application Data"文件夹的绝对控制权。
经实验,我遇到的问题是上述原因中的第三种造成的,把SYSTEM用户添加到Temp文件夹"属性"-〉"安全"设置里并赋予其完全控制的权限就可以了(必须是NFTS系统才支持文件夹的安全属性)。



