分类 PHP 下的文章

php读取ms sql server数据的方法和注意事项

在windows平台,php5.3+读取sql server里面的数据,其实用php_pdo_odbc.dll扩展是最好的选择,SQL语句的兼容性很高,比ms自家出品的sqlsrv(Microsoft Drivers for PHP for SQL Server)扩展强太多了。

一、下面先吐槽一下sqlsrv一些不爽的地方:

1、获取的数据编码默认是UTF-8的,想改为其它编码的数据有点麻烦,虽说它可以设为用系统的编码,但是这里有个很大的问题, 假如你的系统是gbk的,但是获取到的数据有些还是会变为UTF-8的。尽管可以用iconv转换编码,但这个iconv本来就不能转换全部的中文,说不定某些中文就被忽略掉了,不敢用iconv转换成GBK的。

2、某些字段的类型不能自动映射,会出现映射错误,提示数据类型不正确。

3、一些复杂点的SQL语句居然查询不到结果,这个相当无语了,我的SQL语句中出现了中文,居然都返回不了查询结果,不知道是不是编码问题,我也不想测试了。还有个非常奇怪的地方,SQL语句里面用到了ISNULL这个函数,它居然也不执行,取不到任何结果。

总的来说这个东西只能用来处理下英文类的数据,简单点的SQL语句。复杂点的它根本就不行,兼容性太差。

二、用php_pdo_odbc.dll可以很轻松的处理复杂SQL语句及编码问题。当然用pdo_odbc也出现了一点应该注意的问题,不然我也不会在这里吐槽了。读取nvarchar或者nchar字段的数据时,可能会把该字段后面部分的中文给弄成乱码。因为nvarchar字段是按字符存储的,而odbc是按字节读取的,它好像不能处理多字节字符。当它读取到字段长度那么多个字节的时候,后面的字节就被它搞成乱码了,一开始这个问题百思不得其解。有什么办法可以让它不乱码呢,其实你只需要用convert转换一下数据类型为varchar就行了。如:select convert(varchar(两倍的nvarchar字段的长度), nvarchar字段名) from table1。varchar一定要带长度,最好是这个nvarchar字段长度的两倍,这样转换一下后,你获取的数据就不会出现乱码了。

nginx里面codeigniter的重写规则

有下面几种方法

一、使用QUERY_STRING,这个最简单了,nginx里面配置少,性能也应该最好

修改codeinniter里面的application/config/config.php文件,改为如下:

$config['uri_protocol'] = 'QUERY_STRING';

nginx里面这样配置一下就行了

if  (!-f $request_filename) {
rewrite (.+) /index.php?$1 last;
}

二、使用PATH_INFO,由于nginx里面默认是不识别PATH_INFO这个php变量的,它会把PATH_INFO作为一个路径,这样就出现了404错误

修改codeinniter里面的application/config/config.php文件,改为如下:

$config['uri_protocol'] = 'PATH_INFO';

nginx里面加两段代码:

location ~ \.php($|/) {
fastcgi_pass 127.0.0.1:9000;
include fastcgi.conf;
#下面3行让nginx正确识别文件路径和PATH_INFO
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_split_path_info ^(.+\.php)(.*)$;
fastcgi_param PATH_INFO $fastcgi_path_info;
}

if  (!-f $request_filename) {
rewrite (.+) /index.php$1 last;
}

三、使用REQUEST_URI,这个个人觉得没有使用QUERY_STRING来的方便,不利于二次URL重写,毕竟某些时候你想把CodeIgniter默认重写的URL再次重写为比较短点的,这个时候你就必须用CI的config里面enable_query_strings这个地方配置的查询字符串来rewrite了,感觉有点麻烦,如果你不用二次重写,使用这个方法也很简单的。

修改codeinniter里面的application/config/config.php文件,改为如下:

$config['uri_protocol'] = 'REQUEST_URI';

nginx里面这样配置一下就行了

if  (!-f $request_filename) {
rewrite .+ /index.php last;
}

PHP字符串加密解密函数

[code language="php"]
function encrypt( $string, $operation = 'DECODE', $key = '', $expiry = 3600 ){

$ckey_length = 4;
// 随机密钥长度 取值 0-32;
// 加入随机密钥,可以令密文无任何规律,即便是原文和密钥完全相同,加密结果也会每次不同,增大破解难度。
// 取值越大,密文变动规律越大,密文变化 = 16 的 $ckey_length 次方
// 当此值为 0 时,则不产生随机密钥
$key = md5( $key ? $key : 'default_key' ); //这里可以填写默认key值
$keya = md5( substr( $key, 0, 16 ) );
$keyb = md5( substr( $key, 16, 16 ) );
$keyc = $ckey_length ? ( $operation == 'DECODE' ? substr( $string, 0, $ckey_length ): substr( md5( microtime() ), - $ckey_length ) ) : '';

$cryptkey = $keya . md5( $keya . $keyc );
$key_length = strlen( $cryptkey );

$string = $operation == 'DECODE' ? base64_decode( substr( $string, $ckey_length ) ) : sprintf( '%010d', $expiry ? $expiry + time() : 0 ) . substr( md5( $string . $keyb ), 0, 16 ) . $string;
$string_length = strlen( $string );

$result = '';
$box = range( 0, 255 );

$rndkey = array();
for( $i = 0; $i <= 255; $i++ ){
$rndkey[$i] = ord( $cryptkey[$i % $key_length] );
}

for( $j = $i = 0; $i < 256; $i++ ){
$j = ( $j + $box[$i] + $rndkey[$i] ) % 256;
$tmp = $box[$i];
$box[$i] = $box[$j];
$box[$j] = $tmp;
}

for( $a = $j = $i = 0; $i < $string_length; $i++ ){
$a = ( $a + 1 ) % 256;
$j = ( $j + $box[$a] ) % 256;
$tmp = $box[$a];
$box[$a] = $box[$j];
$box[$j] = $tmp;
$result .= chr( ord( $string[$i] ) ^ ( $box[( $box[$a] + $box[$j] ) % 256] ) );
}

if( $operation == 'DECODE' ){
if( ( substr( $result, 0, 10 ) == 0 || substr( $result, 0, 10 ) - time() > 0 ) && substr( $result, 10, 16 ) == substr( md5( substr( $result, 26 ) . $keyb ), 0, 16 ) ){
return substr( $result, 26 );
}else{
return '';
}
}else{
return $keyc . str_replace( '=', '', base64_encode( $result ) );
}
}
[/code]

fsockopen返回gzip内容无法gzdecode解压的问题

#1.返回头Transfer-Encoding: chunked表明是chunked的传输编码
这个意思是,服务器分批把http body返回给你,比如http body如下
2 --表示下一个chunked的长度为2,这个数字是16进制,不是10进制
ab -- 长度为2的串
3 -- 同上
abc -- 长度为3的串
1 -- 同上
a -- 长度为1的串
0 -- 长度为0,这个是结束标识

所以最终的http body应该是ababca ,长度标识是不需要的。

- 阅读剩余部分 -

php中flush()在iis7下无效的解决方法

在一个比较费时的操作中,想把操作记录在浏览器上实时显示出来,用到了flush(),把缓冲中的内容发送到浏览器。但在iis7里面用fastcgi模式配置的php怎么都实现不了,结果总是一起显示出来。

[code language="php"]
for ($i=10; $i>0; $i--)
{
echo $i.'<br />';
@ob_flush();
flush();
sleep(1);
}
[/code]

- 阅读剩余部分 -

PHP线程安全与非线程安全的区别

Windows版的PHP从版本5.2.1开始有Thread Safe(线程安全)和None Thread Safe(NTS,非线程安全)之分,这两者不同在于何处?到底应该用哪种?这里做一个简单的介绍。

从2000年10月20日发布的第一个Windows版的PHP3.0.17开始的都是线程安全的版本,这是由于与Linux/Unix系统是采用多进程的工作方式不同的是Windows系统是采用多线程的工作方式。如果在IIS下以CGI方式运行PHP会非常慢,这是由于CGI模式是建立在多进程的基础之上的,而非多线程。一般我们会把PHP配置成以ISAPI的方式来运行,ISAPI是多线程的方式,这样就快多了。但存在一个问题,很多常用的PHP扩展是以Linux/Unix的多进程思想来开发的,这些扩展在ISAPI的方式运行时就会出错搞垮IIS。因此在IIS下CGI模式才是 PHP运行的最安全方式,但CGI模式对于每个HTTP请求都需要重新加载和卸载整个PHP环境,其消耗是巨大的。

为了兼顾IIS下PHP的效率和安全,微软给出了FastCGI的解决方案。FastCGI可以让PHP的进程重复利用而不是每一个新的请求就重开一个进程。同时FastCGI也可以允许几个进程同时执行。这样既解决了CGI进程模式消耗太大的问题,又利用上了CGI进程模式不存在线程安全问题的优势。

因此,如果是使用ISAPI的方式来运行PHP就必须用Thread Safe(线程安全)的版本;而用FastCGI模式运行PHP的话就没有必要用线程安全检查了,用None Thread Safe(NTS,非线程安全)的版本能够更好的提高效率。

TS是线程安全(Thread Safe ),一般Apache模块、IIS的ISAPI需要使用。
NTS是无线程安全的(Non Thread Safe ),因为php-cgi不需要。
此外还分VC6和VC9,vc6是给Apache用的,vc9是给IIS用的。VC9需要安装 c++2008运行库。

curl获取的header中出现HTTP/1.1 100 continue的问题

用curl获取返回结果的头的第一行出现了“

HTTP/1.1 100 continue

”,之后才是HTTP/1.1 200 OK之类的真实状态。出现这个问题是因为curl默认发送了这样的一个header:“Expect: 100-continue”,我们只需要把这个header重写下就可以了。

curl_setopt( $curl_handle, CURLOPT_HTTPHEADER, array( 'Expect:' ) );

加一个Expect:后面为空,这样就把curl默认发送的那个header覆盖了,ok,问题解决。

json_encode转换中文为null的问题

把要转换的数组先urlencode一下就好了,json化后再urldecode下。

[code language="php"]
<?php

$data = array(
'game' => '冰火国度',
'name' => '刺之灵',
'country' => '冰霜国',
'level' => 45
);

/**
* 处理json_encode乱码
*/
$newData = array();
foreach( $data as $key => $value )
{
$newData[ $key ] = urlencode( $value );
}
echo urldecode( json_encode( $newData ) );

?>
[/code]

PHP中的sprintf()函数的格式说明

sprintf

将字串格式化。

语法: string sprintf(string format, mixed [args]...);

传回值: 字串

函式种类: 资料处理

内容说明

本函式用来将字串格式化。参数 format 是转换的格式,以百分比符号 % 开始到转换字符为止。而在转换的格式间依序包括了

1. 填空字元。0 的话表示空格填 0;空格是内定值,表示空格就放着。

2. 对齐方式。内定值为向右对齐,负号表向左对齐。

3. 栏位宽度。为最小宽度。

4. 精确度。指在小数点后的浮点数位数。

型态,见下表

=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
转换字符=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
% 印出百分比符号,不转换。
b 整数转成二进位。
c 整数转成对应的 ASCII 字元。
d 整数转成十进位。
f 倍精确度数字转成浮点数。
o 整数转成八进位。
s 整数转成字串。
x 整数转成小写十六进位。
X 整数转成大写十六进位。

使用范例

[code language="php"]
<?php
$money1 = 68.75;
$money2 = 54.35;
$money = $money1 + $money2;
// 此时变数 $money 值为 "123.1";
$formatted = sprintf ("%01.2f", $money);
// 此时变数 $ formatted 值为 "123.10"
?>
[/code]

这个 %01.2f 是什么意思呢?

首先 这个 % 符号是开始的意思,他写在最前面表示指定格式要开始了。 也就是 "起始字符", 直到出现 "转换字符" 为止,就算格式终止。

然后 跟在 % 符号 后面的是 0 这个零是 "填空字元" 表示,如果位置空着 就用0来填满。

在 0 后面的是 1 这个 1 是规定,小数点前面的数字占位要有1位以上。

如果把 1 改成 2 如果 $money 的值为 1.23 ,则 $formatted 的值将为 01.23

因为,在小数点前面的数字只占了1位,按照上面所规定的格式,小数点前数字应该占2位,现在只有1位,所以,用0来填满。

到目前,在 %01 后面的 .2 (点2) 就很好理解了,它的意思是,规定,小数点后的数字,必需占2位. 如果这时候,$money 的值为 1.234,则 $formatted 的值将为 1.23。

为什么 4 不见了呢? 因为,在小数点后面 按照上面的规定,必需且仅能占2位。 可是 $money 的值中,小数点占了3位,所以,4 被去掉了,只剩下 23。

最后,以 f "转换字符" 结尾,其他转换字符请自行参考上面的转换字符列表。

关于对齐

如果在 % 起始符号后面 加上 - (负号) 则,将会把数字以向右对齐的方式进行处理。

[code language="php"]
<?php
$money = 1.4;
$formatted = sprintf ("%-02.2f", $money);
echo $formatted;
?>
[/code]

php效率优化

Part1

  • 1.在可以用file_get_contents替代file、fopen、feof、fgets等系列方法的情况下,尽量用file_get_contents,因为他的效率高得多!但是要注意file_get_contents在打开一个URL文件时候的PHP版本问题。
  • 2.尽量的少进行文件操作,虽然PHP的文件操作效率也不低的。
  • 3.优化Select SQL语句,在可能的情况下尽量少的进行Insert、Update操作。
  • 4.尽可能的使用PHP内部函数(但是我却为了找个PHP里面不存在的函数,浪费了本可以写出一个自定义函数的时间,经验问题啊!)。
  • 5.循环内部不要声明变量,尤其是大变量:对象(这好像不只是PHP里面要注意的问题吧?)。
  • 6.多维数组尽量不要循环嵌套赋值。
  • 7.在可以用PHP内部字符串操作函数的情况下,不要用正则表达式。
  • 8.foreach效率更高,尽量用foreach代替while和for循环。
  • 9.用单引号替代双引号引用字符串。
  • 10.“用i+=1代替i=i+1。符合c/c++的习惯,效率还高”。
  • 11.对global变量,应该用完就unset()掉。

- 阅读剩余部分 -