php cookie用法之 setcookie()函数

setcookie(PHP 3, PHP 4, PHP 5)
setcookie — 发送一个 cookie 信息

说明bool setcookie ( string name [, string value [, int expire [, string path [, string domain [, bool secure]]]]] )

setcookie() 定义一个和其余的 HTTP 标头一起发送的 cookie。和其它标头一样,cookie 必须在脚本的任何其它输出之前发送(这是协议限制)。

这需要将本函数的调用放到任何输出之前,包括 <html> 和 <head> 标签以及任何空格。如果在调用 setcookie() 之前有任何输出,本函数将失败并返回 FALSE。

如果 setcookie() 函数成功运行,将返回 TRUE。这并不说明用户是否接受了 cookie。

注: 自 PHP 4 起,可以用输出缓存来在调用本函数前输出内容,代价是把所有向浏览器的输出都缓存在服务器,直到下命令发送它们。

可以在代码中使用 ob_start() 及 ob_end_flush() 来实现这样的功能,或者通过修改 php.ini 中的 output_buffering 配置选项来实现,也可以通过修改服务器配置文件来实现。

除了 name 外,其它所有参数都是可选的。可以用空字符串(””)替换某参数以跳过该参数。因为参数 expire 是整型,不能用空字符串掉过,可以用零(0)来代替 。

下面的表格对 setcookie() 的每一个参数都进行了解释。可以对照 Netscape cookie 规范以了解 setcookie() 的每一个参数的细节以及通过阅读 RFC 2965 了解 HTTP cookie 的工作方式。

表格 1. setcookie() 参数详解
[参数说明举例]

name Cookie 的名字  使用 $_COOKIE[‘cookiename’] 调用名为 cookiename 的 cookie
value  Cookie 的值 此值保存在客户端,不要用来保存敏感数据。    假定 name 是 ‘cookiename’,可以通过 $_COOKIE[‘cookiename’] 取得其值
expire Cookie 过期的时间 Cookie 过期的时间。这是个 Unix 时间戳,即从 Unix 纪元开始的秒数。换而言之,通常用 time() 函数再加上秒数来设定
cookie 的失效期。或者用 mktime()来实现。    time()+60*60*24*30 将设定 cookie 30
天后失效。如果未设定,cookie 将会在会话结束后(一般是浏览器关闭)失效
path Cookie 在服务器端的有效路径  如果该参数设为 ‘/’ 的话,cookie 就在整个 domain 内有效,如果设为 ‘/foo/’,cookie 就只在 domain 下的 /foo/ 目录及其子目录内有效,例如 /foo/bar/。默认值为设定 cookie 的当前目录
domain  该 cookie 有效的域名 要使 cookie 能在如 example.com 域名下的所有子域都有效的话,该参数应该设为 ‘.example.com’。虽然 . 并不必须的,但加上它会兼容更多的浏览器。如果该参数设为 www.example.com 的话,就只在 www 子域内有效
secure  指明 cookie 是否仅通过安全的 HTTPS 连接传送 指明 cookie 是否仅通过安全的 HTTPS 连接传送。当设成 TRUE 时,cookie 仅在安全的连接中被设置。默认值为 FALSE。    0 或 1

当 cookie 被设置后,便可以在其它页面通过 $_COOKIE 或 $HTTP_COOKIE_VARS 数组取得其值。

需要注意的是,autoglobals 的 $_COOKIE 形式适用于 PHP 4.1.0 或更高版本。而 $HTTP_COOKIE_VARS 则从 PHP 3 起就可以使用。Cookie 的值也会被保存到 $_REQUEST 数组中。

注:

如果 PHP 的选项 register_globals 被设为 on 的话,cookie 的值仍然会被斌到变量内。在下面的例子中,$TestCookie 会被注册,但是仍然推荐使用 $_COOKIE 数组。

常见缺陷:

    Cookies 不会在设置它的本页生效,要测试一个 cookie 是否被成功的设定,可以在其到期之前通过另外一个页面来访问其值。过期时间是通过参数 expire 来设置的。可以简单地使用 print_r($_COOKIE); 来调试现有的 cookies。
    Cookie 必须用和设定时的同样的参数才能删除。如果其值一个空字符串,或者是 FALSE,并且其它的参数都和前一次调用 setcookie 时相同,那么所指定名称的 cookie 将会在远程客户端被删除。
    由于把 cookie 的值设为 FALSE 会使客户端尝试删除这个 cookie,所以要在 cookie 上保存 TRUE 或 FALSE 时不应该直接使用 boolean 值,而应该用 0 来表示 FALSE,用 1 来表示 TRUE
    可以把 cookie 的名称设置成一个数组,但是数组 cookie 中的每个元素的值将会被单独保存在用户的系统中。考虑使用 explode() 函数用多个名称和值设定一个 cookie。不推荐将 serialize() 用于此目的,因为它可能会导致一个安全漏洞。

在 PHP 3 中,在同一个 PHP 脚本中多次使用 setcookie() 来设置 cookie,将会按照倒序的方式来分别执行,如果想要在插入另外一个 cookie 之前删除一个 cookie,要把插入放到删除之前。自 PHP 4 起,多次调用 setcookie() 则是按照顺序来执行的。
下面一些例子说明了如何发送 cookie:
例子 1. setcookie() 发送例子
$value = ‘something from somewhere’;
setcookie(“TestCookie”, $value);
setcookie(“TestCookie”, $value,time()+3600); /* expire in 1 hour */
setcookie(“TestCookie”, $value,time()+3600, “/~rasmus/”, “.utoronto.ca”, 1);

注意 cookie 中值的部分在发送的时候会被自动用 urlencode 编码并在接收到的时候被自动解码并把值赋给与自己同名的 cookie 变量。如果不想这样并且在使用 PHP 5 的话,可以用 setrawcookie() 来代替。下面这个简单的例子可以得到刚才所设定的 cookie 的值:
<?php
// 输出单独的 cookie
echo $_COOKIE[“TestCookie”;
echo $HTTP_COOKIE_VARS[“TestCookie”;

// 另一个调试的方法就是输出所有的 cookie
print_r($_COOKIE);
?>

要删除 cookie 需要确保它的失效期是在过去,才能触发浏览器的删除机制。下面的例子说明了如何删除刚才设置的 cookie:
例子 2. setcookie() 删除例子
// 将过期时间设为一小时前
setcookie(“TestCookie”, “”, time() – 3600);
setcookie(“TestCookie”, “”, time() – 3600, “/~rasmus/”, “.utoronto.ca”, 1);

也可以通过在 cookie 名称中使用数组符号来设定数组 cookie,可以设定多个 cookie 作为数组单元,在脚本提取 cookie 时所有的值都放在一个数组种:
例子 3. setcookie() 中使用数组的例子
<?php
// 设定 cookie
setcookie(“cookie[three]”, “cookiethree”);
setcookie(“cookie[two]”, “cookietwo”);
setcookie(“cookie[one]”, “cookieone”);

// 刷新页面后,显示出来
if (isset($_COOKIE[‘cookie’)) {
foreach ($_COOKIE[‘cookie’] as $name => $value) {
echo “$name : $value <br />\n”;
}
}
?>
上例将输出: three : cookiethreetwo : cookietwoone : cookieone

PHP编程效率的20个要点

用单引号代替双引号来包含字符串,这样做会更快一些。因为PHP会在双引号包围的字符串中搜寻变量,单引号则
不会,注意:只有echo能这么做,它是一种可以把多个字符串当作参数的“函数”(译注:PHP手册中说echo是语言结构,不是真正的函数,故把函数加
上了双引号)。

1、如果能将类的方法定义成static,就尽量定义成static,它的速度会提升将近4倍。

2、$row[’id’] 的速度是$row[id]的7倍。

3、echo 比 print 快,并且使用echo的多重参数(译注:指用逗号而不是句点)代替字符串连接,比如echo $str1,$str2。

4、在执行for循环之前确定最大循环数,不要每循环一次都计算最大值,最好运用foreach代替。

5、注销那些不用的变量尤其是大数组,以便释放内存。

6、尽量避免使用__get,__set,__autoload。

7、require_once()代价昂贵。

8、include文件时尽量使用绝对路径,因为它避免了PHP去include_path里查找文件的速度,解析操作系统路径所需的时间会更少。

9、如果你想知道脚本开始执行(译注:即服务器端收到客户端请求)的时刻,使用$_SERVER[‘REQUEST_TIME’]要好于time()。

10、函数代替正则表达式完成相同功能。

11、str_replace函数比preg_replace函数快,但strtr函数的效率是str_replace函数的四倍。

12、如果一个字符串替换函数,可接受数组或字符作为参数,并且参数长度不太长,那么可以考虑额外写一段替换代码,使得每次传递参数是一个字符,而不是只写一行代码接受数组作为查询和替换的参数。

13、使用选择分支语句(译注:即switch case)好于使用多个if,else if语句。

14、用@屏蔽错误消息的做法非常低效,极其低效。

15、打开apache的mod_deflate模块,可以提高网页的浏览速度。

16、数据库连接当使用完毕时应关掉,不要用长连接。

17、错误消息代价昂贵。

18、在方法中递增局部变量,速度是最快的。几乎与在函数中调用局部变量的速度相当。

19、递增一个全局变量要比递增一个局部变量慢2倍。

20、递增一个对象属性(如:$this->prop++)要比递增一个局部变量慢3倍。

在windows上安装redis并设置密码

安装redis的方式有两种:

  1. 下载 源码 ,使用vs编译,由于redis是c写的,所以需要安装c++才能正常编译
  2. 直接下载安装包,下载地址 https://github.com/MSOpenTech/redis/releases

从下载页面下载到最新的安装包,后缀名为msi

双击运行,然后一路Next就行了,当然有几个地方可以根据自己的喜好修改,下面我会贴出几个选项的说明。

点击两次“Next”后,出现如下图片

redis1

标注1:安装的地址

标注2:将redis安装的文件夹加入系统环境变量中,我会把这个勾上,免得使用“控制台”管理redis的时候,需要输入长长的路径

继续点击“Next”,出现如下图片

redis2

上面的介绍通俗易懂,文本框内是redis监听的端口,复选框勾选的是把让端口可以通过防火墙。

再按下一步设置的是“Max Memory”和“Max Heap”,这两个配置以后研究Redis的各种配置的时候再详细介绍,有兴趣的朋友可以打开安装目录下面的redis.windows-service.conf文件看

继续“Next”直到安装完成。安装完成后,在window服务里面就添加了一个名为“redis”的服务了

设置密码

默认安装后的redis是没有密码的,这明显有很大的安全隐患,所以我再讲讲设置密码。我知道设置密码的方式有两种:

  1. 使用“控制台”
  2. 修改配置文件“redis.windows-service.conf”

第1种方式,需要知道如何在“控制台”里操作redis,而且重启后就无效了,不推荐这种方式。

第2种方式,在安装的目录下找到并打开“redis.windows-service.conf”文件你可以找到如下的文字:

################################## SECURITY ###################################

# Require clients to issue AUTH <PASSWORD> before processing any other
# commands.  This might be useful in environments in which you do not trust
# others with access to the host running redis-server.
#
# This should stay commented out for backward compatibility and because most
# people do not need auth (e.g. they run their own servers).
#
# Warning: since Redis is pretty fast an outside user can try up to # 150k passwords per second against a good box. This means that you should
# use a very strong password otherwise it will be very easy to break.
#
# requirepass foobared

设置密码的方式就是加入一行

requirepass 你的密码

比如我要设置密码为:wwwwwwqqqqqq3323r 的话,就加入一行下面的文字

requirepass wwwwwwqqqqqq3323r

 

CI中的脚手架

CodeIgniter 的脚手架功能使您可以在开发过程中方便快速的在数据库总添加、删除、修改数据。

非常重要: 脚手架(Scaffolding)只可以在开发过程中使用。因为它提供了非常少的安全保护,所以可以访问到您的 CodeIgniter 站点的任何人都可

以添加删除或修改您数据库中的数据。如果您使用脚手架,那么请确认您在使用完之后一定要立刻禁止它。千万不要在上线的站点中激活它,并且一

定要在使用前给它设置一个密匙(secret word)。

为什么要使用脚手架?
这是一个经典场景:开发过程中,你创建了一个数据表并且希望快速地插入一些数据。没有“脚手架”时,你要么写些插入命令,要么就使用如

phpMyAdmin之类的数据库管理工具。用CodeIgniter的脚手架特性,你可以快捷地通过浏览器添加数据。当你用完时,也可以轻易删除掉这些数据。

设置一个密匙(Secret Word)
激活脚手架之前,要先设置一个密匙。我们将通过这个密匙来启动脚手架,所以要用一些不常见的词防止被人猜到。

设置密匙,打开文件 application/config/routes.php 找到下面字段:

$route[‘scaffolding_trigger’] = ”;

把值替换成你的密匙

注意: 脚手架密匙 不能 以下划线开头。

激活脚手架
注意:本页信息假设你已经知道 控制器 是怎么工作的了, 并且你已经有一个正在运行的控制器。同时,我们假设你已经设置好CodeIgniter使之能

自动连上 数据库。如果不是,此页的信息不会很有价值,所以我们建议你先阅读相关内容。最后,我们假设你已经知道什么叫类的构造函数。否则

,请阅读 控制器 的最后一节。

激活脚手架,你的控制器构造函数应该有像这样的代码:

<?php
class Blog extends Controller{
function Blog(){
 parent::Controller();

 $this->load->scaffolding(‘table_name’);
}
}
?>

此处的 table_name 为你想操作的数据表名 (表名,不是数据库名)

一旦初始化脚手架,你可以以这样的URL来访问它:

example.com/index.php/class/secret_word/

比如,控制器名为 Blog ,密匙为 abracadabra , 你可以这样访问脚手架:

example.com/index.php/blog/abracadabra/

脚手架界面是简单明了的。你可以添加,修改或删除数据。

最后需要注意的地方:
脚手架特性只能操作有主键的表,因为这是各种数据库函数所必需的信息。

php获取WIN/LINUX系统 MAC地址

获取网卡的MAC地址原码;目前支持WIN/LINUX系统 获取机器网卡的物理(MAC)地址

<?php
    /**
    获取网卡的MAC地址原码;目前支持WIN/LINUX系统
    获取机器网卡的物理(MAC)地址
    **/
         
    class GetMacAddr{
         
            var $return_array = array(); // 返回带有MAC地址的字串数组
            var $mac_addr;
         
            function GetMacAddr($os_type){
                 switch ( strtolower($os_type) ){
                          case "linux":
                                    $this->forLinux();
                                    break;
                          case "solaris":
                                    break;
                          case "unix":
                                     break;
                           case "aix":
                                     break;
                           default:
                                     $this->forWindows();
                                     break;
          
                  }
          
                     
                  $temp_array = array();
                  foreach ( $this->return_array as $value ){
          
                            if (
    preg_match("/[0-9a-f][0-9a-f][:-]"."[0-9a-f][0-9a-f][:-]"."[0-9a-f][0-9a-f][:-]"."[0-9a-f][0-9a-f][:-]"."[0-9a-f][0-9a-f][:-]"."[0-9a-f][0-9a-f]/i",$value,
    $temp_array ) ){
                                     $this->mac_addr = $temp_array[0];
                                     break;
                           }
          
                  }
                  unset($temp_array);
                  return $this->mac_addr;
             }
          
          
             function forWindows(){
                  @exec("ipconfig /all", $this->return_array);
                  if ( $this->return_array )
                           return $this->return_array;
                  else{
                           $ipconfig = $_SERVER["WINDIR"]."\system32\ipconfig.exe";
                           if ( is_file($ipconfig) )
                              @exec($ipconfig." /all", $this->return_array);
                           else
                              @exec($_SERVER["WINDIR"]."\system\ipconfig.exe /all", $this->return_array);
                           return $this->return_array;
                  }
             }
          
             function forLinux(){
                  @exec("ifconfig -a", $this->return_array);
                  return $this->return_array;
             }
          
    }
//方法使用
$mac = new GetMacAddr(PHP_OS);
echo $mac->mac_addr;
?>

PHP一键去除网页BOM头

在网站开发或者是前端开发中,有时候我们在小改动的情况下,习惯的使用windows系统自带的编辑器进行编辑,这就会导致页面出现bom签名(只针对utf8文件,gbk编码不会出现此问题)这个时候如何解决这个问题呢?

首先你要熟悉几个常出现的问题:

1.网站打开空白

2.页面头部出现多余的空白

3.网站出现乱码,如“锘�”

解决方法可以是:

1.选用专业的编辑器,例如notepad++,sublime,editplus这样不会自动签名。

2.sublime通过如下操作File -> Save with Encoding -> UTF-8保存后即可去除bom

3.notepad++选中格式 -> 以UTF-8格式编码 选项即可去除

泪雪这次最为苦恼的就是遇见了网页出现的乱码“锘�”,这个就是因为转码后多余出来的,仔细检测也并不是PHP文件的BOM属性,经过不断的摸索和 发现,是整个网站中有些文件存在BOM属性,所以导致调用输出时就出现了“锘�”这样的乱码,由于网站程序的庞大,所以并不可能手动挨个检查排除修复,所 以就发现了一个极为好用的PHP程序。

这是执行效果:

php1

下面就贴出整理的代码吧!

<?php
if (isset($_GET[‘dir’])){ //设置文件目录
$basedir=$_GET[‘dir’];
}else{
$basedir = ‘.’;
}
$auto = 1;
checkdir($basedir);
function checkdir($basedir){
if ($dh = opendir($basedir)) {
while (($file = readdir($dh)) !== false) {
if ($file != ‘.’ &amp;&amp; $file != ‘..’){
if (!is_dir($basedir.”/”.$file)) {
echo “filename: $basedir/$file “.checkBOM(“$basedir/$file”).” &lt;br&gt;”;
}else{
$dirname = $basedir.”/”.$file;
checkdir($dirname);
}
}
}
closedir($dh);
}
}
function checkBOM ($filename) {
global $auto;
$contents = file_get_contents($filename);
$charset[1] = substr($contents, 0, 1);
$charset[2] = substr($contents, 1, 1);
$charset[3] = substr($contents, 2, 1);
if (ord($charset[1]) == 239 &amp;&amp; ord($charset[2]) == 187 &amp;&amp; ord($charset[3]) == 191) {
if ($auto == 1) {
$rest = substr($contents, 3);
rewrite ($filename, $rest);
return (“&lt;font color=red&gt;BOM found, automatically removed.&lt;/font&gt;”);
} else {
return (“&lt;font color=red&gt;BOM found.&lt;/font&gt;”);
}
}
else return (“BOM Not Found.”);
}
function rewrite ($filename, $data) {
$filenum = fopen($filename, “w”);
flock($filenum, LOCK_EX);
fwrite($filenum, $data);
fclose($filenum);
}
?>

使用方法:复制上面代码到一个新建的delbom.txt的文件中,上传到网站根目录,然后将delbom.txt改为delbom.php,最后直接前台访问该文件即可。

json_encode不支持中文

今天头一回用json_encode,发现它不支持中文,

在json_encode之前,把所有数组内所有内容都用urlencode()处理一下,然用json_encode()转换成json字符串,最后再用urldecode()将编码过的中文转回来。

写了个函数JSON来代替json_encode,这种方法在我的程序中测试是成功的:

/**************************************************************
 *
 *	使用特定function对数组中所有元素做处理
 *	@param	string	&$array		要处理的字符串
 *	@param	string	$function	要执行的函数
 *	@return boolean	$apply_to_keys_also		是否也应用到key上
 *	@access public
 *
 *************************************************************/
function arrayRecursive(&$array, $function, $apply_to_keys_also = false)
{
    static $recursive_counter = 0;
    if (++$recursive_counter > 1000) {
        die('possible deep recursion attack');
    }
    foreach ($array as $key => $value) {
        if (is_array($value)) {
            arrayRecursive($array[$key], $function, $apply_to_keys_also);
        } else {
            $array[$key] = $function($value);
        }

        if ($apply_to_keys_also && is_string($key)) {
            $new_key = $function($key);
            if ($new_key != $key) {
                $array[$new_key] = $array[$key];
                unset($array[$key]);
            }
        }
    }
    $recursive_counter--;
}

/**************************************************************
 *
 *	将数组转换为JSON字符串(兼容中文)
 *	@param	array	$array		要转换的数组
 *	@return string		转换得到的json字符串
 *	@access public
 *
 *************************************************************/
function JSON($array) {
	arrayRecursive($array, 'urlencode', true);
	$json = json_encode($array);
	return urldecode($json);
}

PHP:Fatal error: Class ‘COM’ not found in … 的处理办法

PHP:Fatal error: Class ‘COM’ not found in … 的处理办法
1、首先在windows的“服务”里面检查COM+服务是否已经启动。如果未启动,请启动它。
大概是该服务:Windows Management Instrumentation

2、检查php目录ext文件夹下面php_com_dotnet.dll是否存在。(顺便说一下,ext通常作为php程序的扩展目录,在安装php的时候一般已经设置好。否则就应该不仅仅报主题所说的错咯。)

3、如果没问题,在php.ini里面加入以下语句:

[PHP_COM_DOTNET]
extension=php_com_dotnet.dll

4、php.ini中设置
com.allow_dcom = true

5.PHP版本
PHP 5.4.5以前的版本,只需要在php.ini中把com.allow_dcom = true打开就可以了,但是5.4.5版本以后,PHP把com/dotnet 模块集成到了一个单独的扩展中,所以需要在php.ini中加一行扩展extension=php_com_dotnet.dll,是加一行,不是打开,默认配置文件中没有这一行的,然后重启IIS或Apache,再次运行就正常了!

PHP字符编码问题

一,php编码转换

        1.通过iconv()函数实现编码转换
语法:iconv(string in_charset,string out_charset,string str)
将指定字符串str由in_charset编码格式转换成out_charset编码格式,返回bool值。
2.通过mb_convert_encoding()函数实现编码转换
语法:mb_convert_encoding(string str,string to_encoding[,mixed from_encoding])
将字符串str的编码由from_encoding转换为to_encoding。
二,检测php字符串的编码
通过mb_detect_encoding()函数来检测字符串使用的是何种字符编码。
三,字符编码优先级
由高—>低
1.http消息报头的Content-Type字段中的charset参数。
2.通过meta元素声明,将http-equiv设置成Content-Type。
3.一些元素的charset属性设置。
四,解决页面中的php乱码问题
数据库中数据的输入和输出产生的乱码,可以通过PHP的mysql_query()函数设置来解决,而页面中如果出现乱码,则可以使用下面的两种方法解决。
(1)使用meta标签设置页面编码

meta标签的作用是声明客户端的浏览器用什么字符编码显示该页面。
(2)通过header()函数设置页面的编码格式
header(“content-type;text/html;charset=gb2312”);
header()函数的作用是把括号内的信息发到HTTP标头。

五、如果浏览器不能选择你在页面中默认的字符编码来显示页面

可以设置php中的php.ini文件中的default_charset = “编码”, 例如:default_charset = “gb2312”

这里决定了浏览器选择的默认编码。

PHP error_reporting() 函数功能详解

定义和用法:
error_reporting() 设置 PHP 的报错级别并返回当前级别。

函数语法:
error_reporting(report_level)

如果参数 level 未指定,当前报错级别将被返回。下面几项是 level 可能的值:
值 常量 描述
1 E_ERROR 致命的运行错误。错误无法恢复,暂停执行脚本。
2 E_WARNING 运行时警告(非致命性错误)。非致命的运行错误,脚本执行不会停止。
4 E_PARSE 编译时解析错误。解析错误只由分析器产生。
8 E_NOTICE 运行时提醒(这些经常是你代码中的bug引起的,也可能是有意的行为造成的。)
16 E_CORE_ERROR PHP启动时初始化过程中的致命错误。
32 E_CORE_WARNING PHP启动时初始化过程中的警告(非致命性错)。
64 E_COMPILE_ERROR 编译时致命性错。这就像由Zend脚本引擎生成了一个E_ERROR。
128 E_COMPILE_WARNING 编译时警告(非致命性错)。这就像由Zend脚本引擎生成了一个E_WARNING警告。
256 E_USER_ERROR 用户自定义的错误消息。这就像由使用PHP函数trigger_error(程序员设置E_ERROR)
512 E_USER_WARNING 用户自定义的警告消息。这就像由使用PHP函数trigger_error(程序员设定的一个E_WARNING警告)
1024 E_USER_NOTICE 用户自定义的提醒消息。这就像一个由使用PHP函数trigger_error(程序员一个E_NOTICE集)
2048 E_STRICT 编码标准化警告。允许PHP建议如何修改代码以确保最佳的互操作性向前兼容性。
4096 E_RECOVERABLE_ERROR 开捕致命错误。这就像一个E_ERROR,但可以通过用户定义的处理捕获(又见set_error_handler())
8191 E_ALL 所有的错误和警告(不包括 E_STRICT) (E_STRICT will be part of E_ALL as of PHP 6.0)
例子:
任意数目的以上选项都可以用“或”来连接(用 OR 或 |),这样可以报告所有需要的各级别错误。
例如,下面的代码关闭了用户自定义的错误和警告,执行了某些操作,然后恢复到原始的报错级别:
<?php
//禁用错误报告
error_reporting(0);

//报告运行时错误
error_reporting(E_ERROR | E_WARNING | E_PARSE);

//报告所有错误
error_reporting(E_ALL);
?>

php引用(&)详解及注意事项

php的引用(就是在变量或者函数、对象等前面加上&符号)

在PHP 中引用的意思是:不同的名字访问同一个变量内容。
与C语言中的指针是有差别的.C语言中的指针里面存储的是变量的内容,在内存中存放的地址。

1.变量的引用

PHP 的引用允许你用两个变量来指向同一个内容

<?
$a=”ABC”;
$b =&$a;
echo $a;//这里输出:ABC
echo $b;//这里输出:ABC
$b=”EFG”;
echo $a;//这里$a的值变为EFG 所以输出EFG
echo $b;//这里输出EFG
?>

2.函数的引用传递(传址调用

<?php
function test(&$a)
{
$a=$a+100;
}
$b=1;
echo $b;//输出1
test($b);   //这里$b传递给函数的其实是$b的变量内容所处的内存地址,通过在函数里改变$a的值 就可以改变$b的值了
echo “<br>”;
echo $b;//输出101
?>

要注意的是,在这里test(1);的话就会出错。

 

注意:

上面的“ test($b); ” 中的$b前面不要加 & 符号,但是在函数“call_user_func_array”中,若要引用传参,就得需要 & 符号,如下代码所示:

<?php

function a(&$b){
$b++;
}
$c=0;

call_user_func_array(‘a’,array(&$c));

echo $c;

//输出 1

?>

3.函数的引用返回

 

先看代码

<?php
function &test()
{
static $b=0;//申明一个静态变量
$b=$b+1;
echo $b;
return $b;
}

$a=test();//这条语句会输出 $b的值 为1
$a=5;
$a=test();//这条语句会输出 $b的值 为2

$a=&test();//这条语句会输出 $b的值 为3
$a=5;
$a=test();//这条语句会输出 $b的值 为6
?>

下面解释下:
通过这种方式$a=test();得到的其实不是函数的引用返回,这跟普通的函数调用没有区别 至于原因: 这是PHP的规定
PHP规定通过$a=&test(); 方式得到的才是函数的引用返回

用上面的例子来解释就是
$a=test()方式调用函数,只是将函数的值赋给$a而已, 而$a做任何改变 都不会影响到函数中的$b
而通过$a=&test()方式调用函数呢, 他的作用是 将return $b中的 $b变量的内存地址与$a变量的内存地址 指向了同一个地方
即产生了相当于这样的效果($a=&$b;) 所以改变$a的值 也同时改变了$b的值 所以在执行了
$a=&test();
$a=5;
以后,$b的值变为了5

这里是为了让大家理解函数的引用返回才使用静态变量的,其实函数的引用返回多用在对象中
4.对象的引用

<?php
class a{
var $abc=”ABC”;
}
$b=new a;
$c=$b;
echo $b->abc;//这里输出ABC
echo $c->abc;//这里输出ABC
$b->abc=”DEF”;
echo $c->abc;//这里输出DEF
?>

以上代码是在PHP5中的运行效果

 

在PHP5中 对象的赋值是个引用的过程。上列中$b=new a; $c=$b; 其实等效于$b=new a; $c=&$b;
PHP5中默认就是通过引用来调用对象, 但有时你可能想建立一个对象的副本,并希望原来的对象的改变不影响到副本 . 为了这样的目的,PHP5定义了一个特殊的方法,称为__clone。

自 PHP 5 起,new 自动返回引用,因此在此使用 =& 已经过时了并且会产生 E_STRICT 级别的消息。

 

 

在php4中,对象的赋值是个拷贝过程,

如:$b=new a,其中new a产生的是一个匿名的a对象实例,而此时的$b是对这个匿名对象的拷贝。同理$c=$b,也是对$b内容的一个拷贝。所以在php4中,为了节省内存空间,$b=new a 一般会改成引用的模式,即 $b=& new a。

 

下面再来个 官方 提供的例子:

在php5中,你不需要额外添加什么东西就可到达“对象引用”的功能:

 

<?php
class foo{
protected $name;
function __construct($str){
$this->name = $str;
}
function __toString(){
return  ‘my name is “‘. $this->name .'” and I live in “‘ . __CLASS__ . ‘”.’ . “\n”;
}
function setName($str){
$this->name = $str;
}
}

class MasterOne{
protected $foo;
function __construct($f){
$this->foo = $f;
}
function __toString(){
return ‘Master: ‘ . __CLASS__ . ‘ | foo: ‘ . $this->foo . “\n”;
}
function setFooName($str){
$this->foo->setName( $str );
}
}

class MasterTwo{
protected $foo;
function __construct($f){
$this->foo = $f;
}
function __toString(){
return ‘Master: ‘ . __CLASS__ . ‘ | foo: ‘ . $this->foo . “\n”;
}
function setFooName($str){
$this->foo->setName( $str );
}
}

$bar = new foo(‘bar’);

print(“\n”);
print(“Only Created \$bar and printing \$bar\n”);
print( $bar );

print(“\n”);
print(“Now \$baz is referenced to \$bar and printing \$bar and \$baz\n”);
$baz =& $bar;
print( $bar );

print(“\n”);
print(“Now Creating MasterOne and Two and passing \$bar to both constructors\n”);
$m1 = new MasterOne( $bar );
$m2 = new MasterTwo( $bar );
print( $m1 );
print( $m2 );

print(“\n”);
print(“Now changing value of \$bar and printing \$bar and \$baz\n”);
$bar->setName(‘baz’);
print( $bar );
print( $baz );

print(“\n”);
print(“Now printing again MasterOne and Two\n”);
print( $m1 );
print( $m2 );

print(“\n”);
print(“Now changing MasterTwo’s foo name and printing again MasterOne and Two\n”);
$m2->setFooName( ‘MasterTwo\’s Foo’ );
print( $m1 );
print( $m2 );

print(“Also printing \$bar and \$baz\n”);
print( $bar );
print( $baz );
?>

 

输出:

Only Created $bar and printing $bar
my name is “bar” and I live in “foo”.

Now $baz is referenced to $bar and printing $bar and $baz
my name is “bar” and I live in “foo”.

Now Creating MasterOne and Two and passing $bar to both constructors
Master: MasterOne | foo: my name is “bar” and I live in “foo”.

Master: MasterTwo | foo: my name is “bar” and I live in “foo”.

Now changing value of $bar and printing $bar and $baz
my name is “baz” and I live in “foo”.
my name is “baz” and I live in “foo”.

Now printing again MasterOne and Two
Master: MasterOne | foo: my name is “baz” and I live in “foo”.

Master: MasterTwo | foo: my name is “baz” and I live in “foo”.

Now changing MasterTwo’s foo name and printing again MasterOne and Two
Master: MasterOne | foo: my name is “MasterTwo’s Foo” and I live in “foo”.

Master: MasterTwo | foo: my name is “MasterTwo’s Foo” and I live in “foo”.

Also printing $bar and $baz
my name is “MasterTwo’s Foo” and I live in “foo”.
my name is “MasterTwo’s Foo” and I live in “foo”.

 

上个例子解析:

$bar = new foo(‘bar’);
$m1 = new MasterOne( $bar );
$m2 = new MasterTwo( $bar );

实例对象$m1与$m2中的$bar是对实例$bar的引用,而非拷贝,这是php5中,对象引用的特点,也就是说
1.$m1或$m2内部,任何对$bar的操作都会影响外部对象实例$bar的相关值。
2.外部对象实例$bar的改变也会影响$m1和$m2内部的$bar的引用相关值。

 

在php4中,要实现如上述的 用一个对象实例去当着另外一个对象的属性时,其等价代码(即引用调用)类似如下:

class foo{
var $bar;
function setBar(&$newBar){
$this->bar =& newBar;
}
}

 

 

 

 

5.引用的作用
如果程序比较大,引用同一个对象的变量比较多,并且希望用完该对象后手工清除它,个人建议用 “&” 方式,然后用$var=null的方式清除. 其它时候还是用php5的默认方式吧. 另外, php5中对于大数组的传递,建议用 “&” 方式, 毕竟节省内存空间使用。

6.取消引用
当你 unset 一个引用,只是断开了变量名和变量内容之间的绑定。这并不意味着变量内容被销毁了。例如:

<?php
$a = 1;
$b =& $a;
unset ($a);
?>

不会 unset $b,只是 $a。

7.global 引用
当用 global $var 声明一个变量时实际上建立了一个到全局变量的引用。也就是说和这样做是相同的:

<?php
$var =& $GLOBALS[“var”];
?>

这意味着,例如,unset $var 不会 unset 全局变量。

如果在一个函数内部给一个声明为 global 的变量赋于一个引用,该引用只在函数内部可见。可以通过使用 $GLOBALS 数组避免这一点。

Example  在函数内引用全局变量

<?php
$var1 = “Example variable”;
$var2 = “”;

function global_references($use_globals)
{
global $var1, $var2;
if (!$use_globals) {
$var2 =& $var1; // visible only inside the function
} else {
$GLOBALS[“var2”] =& $var1; // visible also in global context
}
}

global_references(false);
echo “var2 is set to ‘$var2’\n”; // var2 is set to ”
global_references(true);
echo “var2 is set to ‘$var2’\n”; // var2 is set to ‘Example variable’
?>

global $var; 当成是 $var =& $GLOBALS[‘var’]; 的简写。从而将其它引用赋给 $var 只改变了本地变量的引用。

8.$this
在一个对象的方法中,$this 永远是调用它的对象的引用。

//下面再来个小插曲
php中对于地址的指向(类似指针)功能不是由用户自己来实现的,是由Zend核心实现的,php中引用采用的是“写时拷贝”的原理,就是除非发生写操作,指向同一个地址的变量或者对象是不会被拷贝的。

通俗的讲
1:如果有下面的代码

<?
$a=”ABC”;
$b=&$a;
?>

其实此时 $a与$b都是指向同一内存地址 而并不是$a与$b占用不同的内存

2:如果在上面的代码基础上再加上如下代码

<?php
$a=”EFG”;
?>

由于$a与$b所指向的内存的数据要重新写一次了,此时Zend核心会自动判断 自动为$b生产一个$a的数据拷贝,重新申请一块内存进行存储
php的引用(就是在变量或者函数、对象等前面加上&符号)是个高级话题,新手多注意,正确的理解php的引用很重要,对性能有较大影响,而且理解错误可能导致程序错误!

很 多人误解php中的引用跟C当中的指针一样,事实上并非如此,而且很大差别。C语言中的指针除了在数组传递过程中不用显式申明外,其他都需要使用*进行定 义,而php中对于地址的指向(类似指针)功能不是由用户自己来实现的,是由Zend核心实现的,php中引用采用的是“写时拷贝”的原理,就是除非发生 写操作,指向同一个地址的变量或者对象是不会被拷贝的,比如下面的代码:

 

$a = array(‘a’,’c’…’n’);
$b = $a;

如 果程序仅执行到这里,$a和$b是相同的,但是并没有像C那样,$a和$b占用不同的内存空间,而是指向了同一块内存,这就是php和c的差别,并不需要 写成$b=&$a才表示$b指向$a的内存,zend就已经帮你实现了引用,并且zend会非常智能的帮你去判断什么时候该这样处理,什么时候不 该这样处理。

如果在后面继续写如下代码,增加一个函数,通过引用的方式传递参数,并打印输出数组大小。

 

function printArray(&$arr) //引用传递
{
print(count($arr));

}
printArray($a);

上面的代码中,我们通过引用把$a数组传入printArray()函数,zend引擎会认为printArray()可能会导致对$a的改变,此时就会自动为$b生产一个$a的数据拷贝,重新申请一块内存进行存储。这就是前面提到的“写时拷贝”概念。

如果我们把上面的代码改成下面这样:

 

function printArray($arr)   //值传递
{
print(count($arr));
}
printArray($a);
上面的代码直接传递$a值到printArray()中,此时并不存在引用传递,所以没有出现写时拷贝。

php json_encode()问题

前2天碰到一个问题,折腾了好久才解决,应该是自己道行太浅,这里还是给大家分享一下。

php服务端返回给客户端数据,用json_encode()将array的数据通过json格式返回给页面。

页面通过ajax请求后台,dataType为json,结果在success中不能正确解析json,不过在ie下是ok的,在Firefox和Chromes不行。

后台代码

$returnarray = array(“code”=>100);
echo json_encode($returnarray);
return;

前台代码

$.ajax({
url:’?app=default&act=drop’,
dataType:’json’,
type:’POST’,
data:{cid:id},
success:function(res, textStatus){
if(res.code == 100){
alert(“删除成功”);
} else {
alert(“删除失败”);
}
}

});

在firefox中res返回的结果是

php_code2

最后解决办法是,在服务端加上头部声明

header(“Content-Type:application/json”);

 

 

PHP与MYSQL事务处理

MYSQL的事务处理主要有两种方法。
1、用begin,rollback,commit来实现
begin 开始一个事务
rollback 事务回滚
commit 事务确认
2、直接用set来改变mysql的自动提交模式
MYSQL默认是自动提交的,也就是你提交一个QUERY,它就直接执行!我们可以通过
set autocommit=0 禁止自动提交
set autocommit=1 开启自动提交
来实现事务的处理。
当你用 set autocommit=0 的时候,你以后所有的SQL都将做为事务处理,直到你用commit确认或rollback结束。
注意当你结束这个事务的同时也开启了个新的事务!按第一种方法只将当前的作为一个事务!
个人推荐使用第一种方法!
MYSQL中只有INNODB和BDB类型的数据表才能支持事务处理!其他的类型是不支持的!
***:一般MYSQL数据库默认的引擎是MyISAM,这种引擎不支持事务!如果要让MYSQL支持事务,可以自己手动修改:
方法如下:1.修改c:\appserv\mysql\my.ini文件,找到skip-InnoDB,在前面加上#,后保存文件。
2.在运行中输入:services.msc,重启mysql服务。
3.到phpmyadmin中,mysql->show engines;(或执行mysql->show variables like ‘have_%’; ),查看InnoDB为YES,即表示数据库支持InnoDB了。
也就说明支持事务transaction了。
4.在创建表时,就可以为Storage Engine选择InnoDB引擎了。如果是以前创建的表,可以使用mysql->alter table table_name type=InnoDB;
或 mysql->alter table table_name engine=InnoDB;来改变数据表的引擎以支持事务。
*/
/*************** transaction–1 ***************/
$conn = mysql_connect(‘localhost’,’root’,’root’) or die (“数据连接错误!!!”);
mysql_select_db(‘test’,$conn);
mysql_query(“set names ‘GBK'”); //使用GBK中文编码;
//开始一个事务
mysql_query(“BEGIN”); //或者mysql_query(“START TRANSACTION”);
$sql = “INSERT INTO `user` (`id`, `username`, `sex`) VALUES (NULL, ‘test1’, ‘0’)”;
$sql2 = “INSERT INTO `user` (`did`, `username`, `sex`) VALUES (NULL, ‘test1’, ‘0’)”;//这条我故意写错
$res = mysql_query($sql);
$res1 = mysql_query($sql2);
if($res && $res1){
mysql_query(“COMMIT”);
echo ‘提交成功。’;
}else{
mysql_query(“ROLLBACK”);
echo ‘数据回滚。’;
}
mysql_query(“END”);
/**************** transaction–2 *******************/
/*方法二*/
mysql_query(“SET AUTOCOMMIT=0”); //设置mysql不自动提交,需自行用commit语句提交
$sql = “INSERT INTO `user` (`id`, `username`, `sex`) VALUES (NULL, ‘test1’, ‘0’)”;
$sql2 = “INSERT INTO `user` (`did`, `username`, `sex`) VALUES (NULL, ‘test1’, ‘0’)”;//这条我故意写错
$res = mysql_query($sql);
$res1 = mysql_query($sql2);
if($res && $res1){
mysql_query(“COMMIT”);
echo ‘提交成功。’;
}else{
mysql_query(“ROLLBACK”);
echo ‘数据回滚。’;
}
mysql_query(“END”); //事务处理完时别忘记mysql_query(“SET AUTOCOMMIT=1”);自动提交


/******************对于不支持事务的MyISAM引擎数据库可以使用表锁定的方法:********************/

//MyISAM & InnoDB 都支持,
/*
LOCK TABLES可以锁定用于当前线程的表。如果表被其它线程锁定,则造成堵塞,直到可以获取所有锁定为止。
UNLOCK TABLES可以释放被当前线程保持的任何锁定。当线程发布另一个LOCK TABLES时,或当与服务器的连接被关闭时,所有由当前线程锁定的表被隐含地解锁。
*/

mysql_query(“LOCK TABLES `user` WRITE”);//锁住`user`表
$sql = “INSERT INTO `user` (`id`, `username`, `sex`) VALUES (NULL, ‘test1’, ‘0’)”;
$res = mysql_query($sql);
if($res){
echo ‘提交成功。!’;
}else{
echo ‘失败!’;
}
mysql_query(“UNLOCK TABLES”);//解除锁定

MyISAM 是MySQL中默认的存储引擎,一般来说不是有太多人关心这个东西。决定使用什么样的存储引擎是一个很tricky的事情,但是还是值我们去研究一下,这里的文章只考虑 MyISAM 和InnoDB这两个,因为这两个是最常见的。

下面先让我们回答一些问题:
◆你的数据库有外键吗?
◆你需要事务支持吗?
◆你需要全文索引吗?
◆你经常使用什么样的查询模式?
◆你的数据有多大?

myisam只有索引缓存

innodb不分索引文件数据文件 innodb buffer

myisam只能管理索引,在索引数据大于分配的资源时,会由操作系统来cache;数据文件依赖于操作系统的cache。innodb不管是索引还是数据,都是自己来管理

思考上面这些问题可以让你找到合适的方向,但那并不是绝对的。如果你需要事务处理或是外键,那么InnoDB 可能是比较好的方式。如果你需要全文索引,那么通常来说 MyISAM是好的选择,因为这是系统内建的,然而,我们其实并不会经常地去测试两百万行记录。所以,就算是慢一点,我们可以通过使用Sphinx从 InnoDB中获得全文索引。

数据的大小,是一个影响你选择什么样存储引擎的重要因素,大尺寸的数据集趋向于选择InnoDB方式,因为其支持事务处理和故障恢复。数据库的在小决定了 故障恢复的时间长短,InnoDB可以利用事务日志进行数据恢复,这会比较快。而MyISAM可能会需要几个小时甚至几天来干这些事,InnoDB只需要 几分钟。

您操作数据库表的习惯可能也会是一个对性能影响很大的因素。比如: COUNT() 在 MyISAM 表中会非常快,而在InnoDB 表下可能会很痛苦。而主键查询则在InnoDB下会相当相当的快,但需要小心的是如果我们的主键太长了也会导致性能问题。大批的inserts 语句在 MyISAM下会快一些,但是updates 在InnoDB 下会更快一些——尤其在并发量大的时候。

所以,到底你检使用哪一个呢?根据经验来看,如果是一些小型的应用或项目,那么MyISAM 也许会更适合。当然,在大型的环境下使用 MyISAM 也会有很大成功的时候,但却不总是这样的。如果你正在计划使用一个超大数据量的项目,而且需要事务处理或外键支持,那么你真的应该直接使用 InnoDB方式。但需要记住InnoDB 的表需要更多的内存和存储,转换100GB 的MyISAM 表到InnoDB 表可能会让你有非常坏的体验。

===========================================================

MyISAM:这个是默认类型,它是基于传统的ISAM类型,ISAM是 Indexed Sequential Access Method (有索引的顺序访问方法) 的缩写,它是存储记录和文件的标准方法.与其他存储引擎比较,MyISAM具有检查和修复表格的大多数工具. MyISAM表格可以被压缩,而且它们支持全文搜索.它们不是事务安全的,而且也不支持外键。如果事物回滚将造成不完全回滚,不具有原子性。如果执行大量 的SELECT,MyISAM是更好的选择。

InnoDB:这种类型是事务安全的.它与BDB类型具有相同的特性,它们还支持外键.InnoDB表格速度很快.具有比BDB还丰富的特性,因此如果需 要一个事务安全的存储引擎,建议使用它.如果你的数据执行大量的INSERT或UPDATE,出于性能方面的考虑,应该使用InnoDB表,

对于支持事物的InnoDB类型的标,影响速度的主要原因是AUTOCOMMIT默认设置是打开的,而且程序没有显式调用BEGIN 开始事务,导致每插入一条都自动Commit,严重影响了速度。可以在执行sql前调用begin,多条sql形成一个事物(即使autocommit打 开也可以),将大大提高性能。

===============================================================

InnoDB和MyISAM是在使用MySQL最常用的两个表类型,各有优缺点,视具体应用而定。下面是已知的两者之间的差别,仅供参考。

innodb
InnoDB 给 MySQL 提供了具有事务(commit)、回滚(rollback)和崩溃修复能力 (crash recovery capabilities)的事务安全(transaction-safe (ACID compliant))型表。 InnoDB 提供了行锁(locking on row level),提供与 Oracle 类型一致的不加锁读取(non- locking read in SELECTs)。这些特性均提高了多用户并发操作的性能表现。在InnoDB表中不需要扩大锁定 (lock escalation),因为 InnoDB 的列锁定(row level locks)适宜非常小的空间。 InnoDB 是 MySQL 上第一个提供外键约束(FOREIGN KEY constraints)的表引擎。

InnoDB 的设计目标是处理大容量数据库系统,它的 CPU 利用率是其它基于磁盘的关系数据库引擎所不能比的。在技术上,InnoDB 是一套放在 MySQL 后台的完整数据库系统,InnoDB 在主内存中建立其专用的缓冲池用于高速缓冲数据和索引。 InnoDB 把数据和索引存放在表空间里,可能包含多个文件,这与其它的不一样,举例来说,在 MyISAM 中,表被存放在单独的文件中。InnoDB 表的大小只受限于操作系统的文件大小,一般为 2 GB。
InnoDB所有的表都保存在同一个数据文件 ibdata1 中(也可能是多个文件,或者是独立的表空间文件),相对来说比较不好备份,免费的方案可以是拷贝数据文件、备份 binlog,或者用 mysqldump。

MyISAM
MyISAM 是MySQL缺省存贮引擎 .

每张MyISAM 表被存放在三个文件 。frm 文件存放表格定义。 数据文件是MYD (MYData) 。 索引文件是 MYI (MYIndex) 引伸。

因为MyISAM相对简单所以在效率上要优于InnoDB..小型应用使用MyISAM是不错的选择.

MyISAM表是保存成文件的形式,在跨平台的数据转移中使用MyISAM存储会省去不少的麻烦

以下是一些细节和具体实现的差别:

1.InnoDB不支持FULLTEXT类型的索引。
2.InnoDB 中不保存表的具体行数,也就是说,执行select count(*) from table时,InnoDB要扫描一遍整个表来计算有多少行,但是MyISAM只要简单的读出保存好的行数即可。注意的是,当count(*)语句包含 where条件时,两种表的操作是一样的。
3.对于AUTO_INCREMENT类型的字段,InnoDB中必须包含只有该字段的索引,但是在MyISAM表中,可以和其他字段一起建立联合索引。
4.DELETE FROM table时,InnoDB不会重新建立表,而是一行一行的删除。
5.LOAD TABLE FROM MASTER操作对InnoDB是不起作用的,解决方法是首先把InnoDB表改成MyISAM表,导入数据后再改成InnoDB表,但是对于使用的额外的InnoDB特性(例如外键)的表不适用。

另外,InnoDB表的行锁也不是绝对的,如果在执行一个SQL语句时MySQL不能确定要扫描的范围,InnoDB表同样会锁全表,例如 update table set num=1 where name like “%aaa%”

任何一种表都不是万能的,只用恰当的针对业务类型来选择合适的表类型,才能最大的发挥MySQL的性能优势。

===============================================================

以下是InnoDB和MyISAM的一些联系和区别!

1. 4.0以上mysqld都支持事务,包括非max版本。3.23的需要max版本mysqld才能支持事务。

2. 创建表时如果不指定type则默认为myisam,不支持事务。
可以用 show create table tablename 命令看表的类型。

2.1 对不支持事务的表做start/commit操作没有任何效果,在执行commit前已经提交,测试:
执行一个msyql:
use test;
drop table if exists tn;
create table tn (a varchar(10)) type=myisam;
drop table if exists ty;
create table ty (a varchar(10)) type=innodb;

begin;
insert into tn values(‘a’);
insert into ty values(‘a’);
select * from tn;
select * from ty;
都能看到一条记录

执行另一个mysql:
use test;
select * from tn;
select * from ty;
只有tn能看到一条记录
然后在另一边
commit;
才都能看到记录。

3. 可以执行以下命令来切换非事务表到事务(数据不会丢失),innodb表比myisam表更安全:
alter table tablename type=innodb;

3.1 innodb表不能用repair table命令和myisamchk -r table_name
但可以用check table,以及mysqlcheck [OPTIONS] database [tables]

==============================================================

mysql中使用select for update的必须针对InnoDb,并且是在一个事务中,才能起作用。

select的条件不一样,采用的是行级锁还是表级锁也不一样。
http://www.neo.com.tw/archives/900 的说明

由于InnoDB 预设是Row-Level Lock,所以只有「明确」的指定主键,MySQL 才会执行Row lock (只锁住被选取的资料例) ,否则MySQL 将会执行Table Lock (将整个资料表单给锁住)。

举个例子:

假设有个表单products ,里面有id 跟name 二个栏位,id 是主键。

例1: (明确指定主键,并且有此笔资料,row lock)

SELECT * FROM products WHERE id=’3′ FOR UPDATE;

例2: (明确指定主键,若查无此笔资料,无lock)

SELECT * FROM products WHERE id=’-1′ FOR UPDATE;

例2: (无主键,table lock)

SELECT * FROM products WHERE name=’Mouse’ FOR UPDATE;

例3: (主键不明确,table lock)

SELECT * FROM products WHERE id<>’3′ FOR UPDATE;

例4: (主键不明确,table lock)

SELECT * FROM products WHERE id LIKE ’3′ FOR UPDATE;

注1:
FOR UPDATE 仅适用于InnoDB,且必须在交易区块(BEGIN/COMMIT)中才能生效

PHP防盗链

盗链是指服务提供商自己不提供服务的内容,通过技术手段绕过其它有利益的最终用户界面(如广告),直接在自己的 网站上向最终用户提供其它服务提供商的服务内容,骗取最终用户的浏览和点击率。受益者不提供资源或提供很少的资源,而真正的服务提供商却得不到任何的收 益。做好防止盗链的工作,是每个网站开发者的重要工作。

做好防盗链工作能给网站服务器减少不少压力,这里我们分享一种php防盗链的实现方法:

一般的下载的步骤:查找->输出查找结果列表->进入软件详细页面->点击下载按钮->打开下载页面->点击下载,开始下载

我的方法就是在下载页面做文章

首先在网站的公共文件里定义一个$key=sdkfjwojf32413这相当于一个密钥一样

在下载页面生成一个随机数:$certcode = ‘84615354’ (每次打开生成的都不一样)

然后用以上两个变量和软件的ID生成一个md5()加密串

然后生成软件的真实下载地址:file.php?id=5&codekey=ksfjwofsdkfsf

这里的id是软件的编号可以根据他从数据库找到软件地址 $codekey=md5($id.$certcode.$key)
然后把certcode保存到session里,

在file.php的参数里面得到的codekey和id再从公共文件里得到$key 再从session里得到$certcode

对codekey进么验证,看是否正确,如果不正确就退出,否则就进行如下操作

1、删除session(再次打开这个地址就无效了)

2、从数据库里读取软件地址,然后读取软件内容,并输出(用PHP的文件读取方法输出要下载的软件内容而不是直接把地址给他下载)

这样如果要下载,就必须打开你自己的下载页面,从你的下载页面打开地址才能进行下载,而且下载地址每次都不一样,因为生成的随机数不一样

别的地方就算连到你的下载地址,也是下载不了的。

拓展阅读(具体实现):

1.简单防盗链

  1. $ADMIN[defaulturl] = “http://www.vvschool.cn/404.htm”;//盗链返回的地址
  2. $okaysites = array(“http://www.vvschool.cn/”,“http://www.siyizhu.com”); //白名单
  3. $ADMIN[url_1] = “http://www.vvschool.cn/temp/download/”;//下载地点1
  4. $ADMIN[url_2] = “”;//下载地点2,以此类推
  5. $reffer = $HTTP_REFERER;
  6. if($reffer) {
  7. $yes = 0;
  8. while(list($domain$subarray) = each($okaysites)) {
  9. if (ereg($subarray,“$reffer”)) {
  10. $yes = 1;
  11. }
  12. }
  13. $theu = “url”.“_”.“$site”;
  14. if ($ADMIN[$theu] AND $yes == 1) {
  15. header(“Location: $ADMIN[$theu]/$file”);
  16. else {
  17. header(“Location: $ADMIN[defaulturl]”);
  18. }
  19. else {
  20. header(“Location: $ADMIN[defaulturl]”);
  21. }?>

使用方法:将上述代码保存为dao4.php,比如我测试用的validatecode.rar在我的站点http://vvschool.cn/temp/download里面,则用以下代码表示下载连接.

文件名?site=1&file=文件

2.服务器防盗链

3.软件下载的防盗链方法

  1. //放置下载软件的根目录相对于当前脚本目录的相对目录
  2. $fileRelPath = “../../software”;
  3. //例外允许连接的网址,注意:自身域名不需要填入,设定为肯定可以下载,
  4. // 空字符串(“”)表示直接输入网址下载的情况
  5. $excludeReferArr = array(“www.wreny.com”“wreny.com”);
  6. chdir($fileRelPath);
  7. $fileRootPath = getcwd() .“/”;
  8. $filePath=$HTTP_GET_VARS[“file”];
  9. $url=parse_url($_SERVER[“HTTP_REFERER”]);
  10. if($url[host]!=$_SERVER[“HTTP_HOST”] && !in_array($referHost$excludeReferArr)){
  11. ?>

其实,反盗链方式也有不少, 这里只列出一个大概思想作为参考:⑴ IIS 反盗链, 利用ISAPI_Rewrite,可作为Windows下反盗链的一个解决方案;⑵ 图片反盗链,在图片中加入水印,虽然盗链者可以达到目的,但是却也在为自己的网站做宣传。

CodeIgniter 防止XSS攻击

odeIgniter 包含了跨站脚本攻击的防御机制,它可以自动地对所有POST以及COOKIE数据进行过滤,或者您也可以针对单个项目来运行它。默认情况下,它 不会 全局运行,因为这样也需要一些执行开销,况且您也不一定在所有情况下都用得到它.

XSS过滤器会查找那些常被用来触发JavaScript或者其他类型的企图劫持cookie或进行其它恶意行为的代码. 如果发现任何不允许的内容,它将把那些内容转换为字符实体,以确保安全.

注意: 此函数只应该用来处理那些提交过来的数据. 它不适合在常规运行时使用,因为它执行时的开销也是不容忽视的.

1、要使用XSS过滤器对数据进行过滤,请使用此函数:

$this->security->xss_clean()

使用示例:

$data = $this->security->xss_clean($data);

2、如果你希望过滤器能自动过滤所有被访问到的POST或者COOKIE数据,请打开你的 application/config/config.php 文件,进行如下设置即可启用自动过滤:

$config['global_xss_filtering'] = TRUE;

说明: 如果你使用表单验证类,同样也有XSS过滤的选项.

如果开启了全局xss过滤,则获取表单数据时可以直接使用:

$this->input->post('name')

如果,没有开启全局设置,只是希望对单一的数据进行xss过滤,我们可以这样使用:

$this->input->post('name',TRUE)

3、第二个可选的参数, is_image, 允许此函数对 图片进行检测以发现那些潜在的 XSS 攻击, 这对于保证文件上传的安全非常有用. 当此参数被设置为 TRUE 时, 此函数的返回值不是一个修改过的字符串而是一个布尔值, 如果图片是安全的则返回 TRUE, 相反, 如果图片中包含有潜在的、可能会被浏览器尝试运行的恶意信息, 函数将返回FALSE.

if ($this->security->xss_clean($file, TRUE) === FALSE)
{
    // file failed the XSS test
}

redis mongodb memcache三者的性能比較

memcache  用于键值对关系的服务器端缓存,用于存储一些常用的不是很大,但需要快速反应的数据redis 其实用法和memcache基本一样,可能就是几个参数有所不 同。当然 它们缓存的效果也不一样,具体的哪里不一样,以下就是一些资料,和自己的总结

1、 Redis和Memcache都是将数据存放在内存中,都是内存数据库。不过memcache还可用于缓存其他东西,例如图片、视频等等。
2、 数据类型–Memcache在添加数据时就要指定数据的字节长度,例如:
set key3 0 0 8
lxsymcto
STORED
而redis不需要,如:redis 127.0.0.1:6379>set key2 “lxsymblog”
OK
redis 127.0.0.1:6379>get key2
“lxsymblog”
3、虚拟内存–Redis当物理内存用完时,可以将一些很久没用到的value 交换到磁盘
4、过期策略–memcache在set时就指定,例如set key1 0 0 8,即永不过期。Redis可以通过例如expire 设定,例如expire name 10
5、分布式–设定memcache集群,利用magent做一主多从;redis可以做一主多从。都可以一主一从
6、存储数据安全–memcache挂掉后,数据没了;redis可以定期保存到磁盘(持久化)
7、灾难恢复–memcache挂掉后,数据不可恢复; redis数据丢失后可以通过aof恢复

 

从以下几个维度,对redis、memcache、mongoDB 做了对比,欢迎拍砖

1、性能

都比较高,性能对我们来说应该都不是瓶颈

总体来讲,TPS方面redis和memcache差不多,要大于mongodb

2、操作的便利性

      memcache数据结构单一

      redis丰富一些,数据操作方面,redis更好一些,较少的网络IO次数

       mongodb支持丰富的数据表达,索引,最类似关系型数据库,支持的查询语言非常丰富

3、内存空间的大小和数据量的大小

       redis在2.0版本后增加了自己的VM特性,突破物理内存的限制;可以对key value设置过期时间(类似memcache)

       memcache可以修改最大可用内存,采用LRU算法

       mongoDB适合大数据量的存储,依赖操作系统VM做内存管理,吃内存也比较厉害,服务不要和别的服务在一起

4、可用性(单点问题)

对于单点问题,

             redis,依赖客户端来实现分布式读写;主从复制时,每次从节点重新连接主节点都要依赖整个快照,无增量复制,因性能和效率问题,

所以单点问题比较复杂;不支持自动sharding,需要依赖程序设定一致hash 机制。

一种替代方案是,不用redis本身的复制机制,采用自己做主动复制(多份存储),或者改成增量复制的方式(需要自己实现),一致性问题和性能的权衡

             Memcache本身没有数据冗余机制,也没必要;对于故障预防,采用依赖成熟的hash或者环状的算法,解决单点故障引起的抖动问题。

             mongoDB支持master-slave,replicaset(内部采用paxos选举算法,自动故障恢复),auto sharding机制,对客户端屏蔽了故障转移和切分机制。

5、可靠性(持久化)

对于数据持久化和数据恢复,

         redis支持(快照、AOF):依赖快照进行持久化,aof增强了可靠性的同时,对性能有所影响

          memcache不支持,通常用在做缓存,提升性能;

          MongoDB从1.8版本开始采用binlog方式支持持久化的可靠性

6、数据一致性(事务支持)

         Memcache 在并发场景下,用cas保证一致性

        redis事务支持比较弱,只能保证事务中的每个操作连续执行

        mongoDB不支持事务

7、数据分析

         mongoDB内置了数据分析的功能(mapreduce),其他不支持

8、应用场景

        redis:数据量较小的更性能操作和运算上

        memcache:用于在动态系统中减少数据库负载,提升性能;做缓存,提高性能(适合读多写少,对于数据量比较大,可以采用sharding)

        MongoDB:主要解决海量数据的访问效率问题

 

最近一直在研究key-value的存储,简单记一下感受。。一些memcache和redis的安装和使用就不赘述啦。只简单说说两种方案的差别。一些 感想和测试结果未必足够能说明问题,有什么不妥请大家指正。因为这两天在学习的过程发现一直在更正自己认识的缺陷,每天都会否定前一天的想法。。好了,费 话少说。

经过对50万个数据存储的研究发现:

每秒单条指令执行量

memcache  约3万次

redis     约1万次

而且,memcache的一大优点是可以通过一个函数直接设置过期时间,而redis需要两个函数才可以既设置了键值对又设置过期时间,也就是redis在这点上效率变成了原来的一半,即5千次,这对于大部分需求来说,有点太慢了。

memcache的测试代码如下:

<?php

$mem = new Memcache;

$mem->connect(“127.0.0.1”, 11211);

$time_start = microtime_float();

//保存数据

for($i = 0; $i < 100000; $i ++){

$mem->set(“key$i”,$i,0,3);

}

$time_end = microtime_float();

$run_time = $time_end – $time_start;

echo “用时 $run_time 秒\n”;

function microtime_float()

{

list($usec, $sec) = explode(” “, microtime());

return ((float)$usec + (float)$sec);

}

?>

redis的测试代码如下:redis1.php 此代码大概需要10秒左右

<?php

//连接

$redis = new Redis();

$redis->connect(‘127.0.0.1’, 6379);

$time_start = microtime_float();

//保存数据

for($i = 0; $i < 100000; $i ++){

$redis->sadd(“key$i”,$i);

}

$time_end = microtime_float();

$run_time = $time_end – $time_start;

echo “用时 $run_time 秒\n”;

//关闭连接

$redis->close();

 

function microtime_float()

{

list($usec, $sec) = explode(” “, microtime());

return ((float)$usec + (float)$sec);

}

?>

如果需要在设置键值的同时设置过期时间,大概执行需要20秒左右,测试代码如下:redis2.php

<?php

//连接

$redis = new Redis();

$redis->connect(‘127.0.0.1’, 6379);

$time_start = microtime_float();

//保存数据

for($i = 0; $i < 100000; $i ++){

$redis->sadd(“key$i”,$i);

$redis->expire(“key$i”,3);

}

$time_end = microtime_float();

$run_time = $time_end – $time_start;

echo “用时 $run_time 秒\n”;

//关闭连接

$redis->close();

 

function microtime_float()

{

list($usec, $sec) = explode(” “, microtime());

return ((float)$usec + (float)$sec);

}

?>

后来在网上发现redis有一个神奇的功能叫事务,通过multi原子性的将一段代码块依次执行,从而达到一个完整功能模块的执行。不幸的是,通过测 试发现,采用multi方式执行代码时并没有减少请求次数,相反在执行multi指令和exec指令时都要发送请求,从而将运行时间变成了原来的四倍,即 四条指令的运行时间。测试代码如下:redis3.php

<?php

//连接

$redis = new Redis();

$redis->connect(‘127.0.0.1’, 6379);

$time_start = microtime_float();

//保存数据

for($i = 0; $i < 100000; $i ++){

$redis->multi();

$redis->sadd(“key$i”,$i);

$redis->expire(“key$i”,3);

$redis->exec();

}

$time_end = microtime_float();

$run_time = $time_end – $time_start;

echo “用时 $run_time 秒\n”;

//关闭连接

$redis->close();

 

function microtime_float()

{

list($usec, $sec) = explode(” “, microtime());

return ((float)$usec + (float)$sec);

}

?>

问题出现了瓶颈,有好多公司需要海量数据处理,每秒5000次远不能满足需求,然后由于redis主从服务器上比memcache有更大的优势, 为了将来数据的着想,不得不使用redis,这时候出现了一种新的方式,即phpredis提供的pipline功能,该功能能够真正的将几条代码封装成 一次请求,从而大大提高了运行速度,50万次的数据执行只有了58秒。测试代码如下:redis4.php

<?php

//连接

$redis = new Redis();

$redis->connect(‘127.0.0.1’, 6379);

$time_start = microtime_float();

//保存数据

for($i = 0; $i < 100000; $i ++){

$pipe=$redis->pipeline();

$pipe->sadd(“key$i”,$i);

$pipe->expire(“key$i”,3);

$replies=$pipe->execute();

}

$time_end = microtime_float();

$run_time = $time_end – $time_start;

echo “用时 $run_time 秒\n”;

//关闭连接

$redis->close();

 

function microtime_float()

{

list($usec, $sec) = explode(” “, microtime());

return ((float)$usec + (float)$sec);

}

?>

运用这个操作可以非常完美的将赋值操作和设置过期时间操作打包到一个请求去执行,大大提高了运行效率。

redis安装:http://mwt198668.blog.163.com/blog/static/48803692201132141755962/

memcache安装:http://blog.csdn.net/barrydiu/article/details/3936270

redis设置主从服务器:http://www.jzxue.com/fuwuqi/fuwuqijiqunyuanquan/201104/15-7117.html

memcache设置主从服务器:http://www.cnblogs.com/yuanermen/archive/2011/05/19/2051153.html

Cannot assign requested address

今天用php连接最近新开发的一个服务做测试,发现命令行打印出:Cannot assign requested address

网上找了下原因,大致上是由于客户端频繁的连服务器,由于每次连接都在很短的时间内结束,导致很多的TIME_WAIT,以至于用光了 可用的端 口号,所以新的连接没办法绑定端口,即“Cannot assign requested address”。是客户端的问题不是服务器端的问题。通过netstat,的确看到很多TIME_WAIT状态的连接。

client端频繁建立连接,而端口释放较慢,导致建立新连接时无可用端口。

网上的解决方法:

执行命令修改如下2个内核参数 (需要root权限)
sysctl -w net.ipv4.tcp_timestamps=1  开启对于TCP时间戳的支持,若该项设置为0,则下面一项设置不起作用
sysctl -w net.ipv4.tcp_tw_recycle=1  表示开启TCP连接中TIME-WAIT sockets的快速回收

2015年度最流行PHP框架Laravel居首

一个月前,编程开发教学资源平台SitePoint启动了2015年度最流行PHP框架调查。此次调查收到的回复数量远远超过SitePoint迄今为止的所有调查。Bruno Skvorc是SitePoint PHP栏目的编辑。近日,他发布了此次调查的结果,并做了相关分析。

不出所料,Laravel再次优势胜出,如下图所示:

phptop

Bruno观察到,在投票数超过50的国家中,大部分英语国家的开发人员都青睐Laravel,法国开发人员则忠于自己的产品Symfony,捷克开发人员偏爱在西方世界鲜有人知的Nette,而乌克兰开发人员更爱PHPixie。在年龄方面,除了未成年组(PHPixie居首)外,Laravel在所有年龄段的开发人员中都是最受欢迎的,Symfony紧随其后,而CodeIgniter仍然有许多忠实的用户。还有一点非常有趣,就是Phalcon的流行程度较去年大幅下滑,这可能与样本数量有关。

Bruno认为,Laravel的成功,除了得益于良好的代码外,还离不开大力的宣传。框架创建者Taylor Otwell不仅确保Laravel拥有几近完美的文档,还围绕它创建商业服务及发展合作伙伴。Laracasts覆盖了所有缺失的文档和应用场景。在ForgeEnvoyer发布之前,Taylor会与众多博主探讨即将发布的功能,这样,它们就能在发布时获得最大的曝光率。该框架还有自己的subredditPackalystPackagist类似,但只面向Laravel,此外还有Larajobs.com。Laravel甚至还有自己的T恤。

因此,在Bruno看来,一个框架要想长远发展,就要在宣传上下一些功夫。比如,请专业人士设计一个好的logo。文档发布之前可以请不相关的人帮助审查,因为正规的英语对于获得良好的第一印象至关重要。要乐于同潜在的开发者布道师交 流,通过询问他们不喜欢什么来提升他们对于产品的信心。在构建产品的过程中,听取其他人的意见和建议,其中可能会有更好的解决方案。让开发者布道师进行与 你的框架相关的写作,这种关系可能会成长为像Laravel和Laracasts一样的互惠关系。在产品未成熟之前,不要公开进行alpha和beta测 试。

Bruno承认,Laravel确实简单易用,但他不喜欢Laravel近乎垄断的地位。他希望能够联系并邀请框架维护者和那些使用这些项目的人,一起构建一个跨框架的知识库,比较各种方案,不是为了证明一个框架比另一个框架好,而是为了相互学习。

对于(图一)所示的结果,网友akmnahid提出了质疑:

这里提到的大部分框架,每个版本都是单列的,但Laravel合并到了一起。

对此,Bruno解释说:

即使将其它框架的每个版本合并,Laravel仍然会胜出。

……除了目录结构和语法的一些变化外,Laravel 4和5几乎完全相同,而Yii1和Yii2差别非常大……

有多名网友也表达了类似的观点。而网友Hall_of_Famer对CodeIgniter获得如此多的票数表示不解。Bruno认为这与开发人员的习惯有关。许多人宁可花20天的时间在遗留代码中“重新造个轮子”,也不愿意花2天的时间学习一个更好的框架。

完整调查结果已经发布在Github上,感兴趣的读者可以下载分析,并从中发现其它一些有趣的现象。

PHP乱码问题,UTF-8乱码常见问题小结

PHP乱码问题,UTF-8乱码问题比较常见,通过下面的方法基本上就可以解决php乱码问题了。

一.HTML页面转UTF-8编码问题
1.在head后,title前加入一行:

<meta http-equiv=’Content-Type’ content=’text/html; charset=utf-8′ />
顺序不能错,一定要在

显示的标题有可能是乱码!

2.html文件编码问题:

点击编辑器的菜单:“文件”->“另存为”,可以看到当前文件的编码,确保文件编码为:UTF-8,
如果是ANSI,需要将编码改成:UTF-8。
3.HTML文件头BOM问题:
将文件从其他的编码转换成UTF-8编码时,有时候会在文件的最开始加上一个BOM标签,
在个BOM标签可能会导致浏览器在显示中文的时候出现乱码。
删除这个BOM标签的方法:
1.可以用Dreamweaver打开文件,并重新保存,即可以去除BOM标签!
2.可以用EditPlus打开文件,并在菜单“首选项”->“文件”->”UTF-8标识”,设置为:“总是删除签名”,
然后保存文件,即可以去除BOM标签!
4.WEB服务器UTF-8编码问题:
如果你按以上所列的步骤做了,还是有中文乱码问题,
请检查你的所使用的WEB服务器的编码问题
如果你使用的是Apache,请将配置文件里的:charset 设成:utf-8(这里仅列出方法,具体格式请参考apache的配置文件)
如果你使用的是Nginx,请将nginx.conf里的:charset 设成 utf-8,
具体找到 “charset gb2312;”或者类似的语句,改成:“charset utf-8;”。
二.PHP页面转UTF-8编码问题
1.在代码开始出加入一行:
header(“Content-Type: text/html;charset=utf-8”);

2.PHP文件编码问题

点击编辑器的菜单:“文件”->“另存为”,可以看到当前文件的编码,确保文件编码为:UTF-8,
如果是ANSI,需要将编码改成:UTF-8。
3.PHP文件头BOM问题:
PHP文件一定不可以有BOM标签
否则,会出现session不能使用的情况,并有类似的提示:
Warning: session_start() [function.session-start]: Cannot send session cache limiter – headers already sent
这是因为,在执行session_start() 的时候,整个页面不能有输出,但是当由于前PHP页面存在BOM标签,
PHP把这个BOM标签当成是输出了,所以就出错了!
所以PHP页面一定要删除BOM标签
删除这个BOM标签的方法:
1.可以用Dreamweaver打开文件,并重新保存,即可以去除BOM标签!
2.可以用EditPlus打开文件,并在菜单“首选项”->“文件”->”UTF-8标识”,设置为:“总是删除签名”,
然后保存文件,即可以去除BOM标签!
4.PHP以附件形式保存文件的时候,UTF-8编码问题:
PHP以附件形式保存文件,文件名必须是GB2312编码,
否则,如果文件名中有中文的话,将是显示乱码:
如果你的PHP本身是UTF-8编码格式的文件,
需要将文件名变量由UTF-8转成GB2312:
iconv(“UTF-8”, “GB2312”, “$filename”);

5.截断显示文章标题时,出现乱码或者“?”问号的问题:
一般文章标题很长的时候,会显示一部分标题,会对文章标题进行截断,
由于一个UTF-8编码格式的中文字符会占用3个字符宽度,
截取标题的时候,有时会只截取到一个中文字符的1个字符或2字符宽度,
没截取完整,将出现乱码或“?”问号的情况,
用下面的函数截取标题,就不会有问题:

代码如下:
function get_brief_str($str, $max_length)
{
echo strlen($str) .”<br>”;
if(strlen($str) > $max_length)
{
$check_num = 0;
for($i=0; $i < $max_length; $i++)
{
if (ord($str[$i]) > 128)
$check_num++;
}

if($check_num % 3 == 0)
$str = substr($str, 0, $max_length).”…”;
else if($check_num % 3 == 1)
$str = substr($str, 0, $max_length + 2).”…”;
else if($check_num % 3 == 2)
$str = substr($str, 0, $max_length + 1).”…”;
}
return $str;
}

三.MYSQL数据库使用UTF-8编码的问题

1.用phpmyadmin创建数据库和数据表
创建数据库的时候,请将“整理”设置为:“utf8_general_ci”
或执行语句:

CREATE DATABASE `dbname` DEFAULT CHARACTER SET utf8 COLLATE utf8_general_ci;
创建数据表的时候:如果是该字段是存放中文的话,则需要将“整理”设置为:“utf8_general_ci”,

如果该字段是存放英文或数字的话,默认就可以了。

相应的SQL语句,例如:

代码如下:
CREATE TABLE `test` (
`id` INT NOT NULL ,
`name` VARCHAR( 10 ) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL ,
PRIMARY KEY ( `id` )
) ENGINE = MYISAM ;

2.用PHP读写数据库

在连接数据库之后:

[hide]$connection = mysql_connect($host_name, $host_user, $host_pass);

加入两行:

代码如下:
mysql_query(“set character set ‘utf8′”);//读库
mysql_query(“set names ‘utf8′”);//写库

就可以正常的读写MYSQL数据库了。

四.JS相关的UTF-8编码问题
1.JS读Cookie的中文乱码问题

PHP写cookie的时候需要将中文字符进行escape编码,
否则JS读到cookie中的中文字符将是乱码。
但php本身没有escape函数,我们新写一个escape函数:

代码如下:
function escape($str)
{
preg_match_all(“/[\x80-\xff].|[\x01-\x7f]+/”,$str,$r);
$ar = $r[0];
foreach($ar as $k=>$v)
{
if(ord($v[0]) < 128)
$ar[$k] = rawurlencode($v);
else
$ar[$k] = “%u”.bin2hex(iconv(“UTF-8″,”UCS-2”,$v));
}
return join(“”,$ar);
}

JS读cookie的时候,用unescape解码,

然后就解决cookie中有中文乱码的问题了。

2.外部JS文件UTF-8编码问题

当一个HTML页面或则PHP页面包含一个外部的JS文件时,

如果HTML页面或则PHP页面是UTF-8编码格式的文件,

外部的JS文件同样要转成UTF-8的文件,

否则将出现,没有包含不成功,调用函数时没有反应的情况。

点击编辑器的菜单:“文件”->“另存为”,可以看到当前文件的编码,确保文件编码为:UTF-8,

如果是ANSI,需要将编码改成:UTF-8。

五.FLASH相关的UTF-8编码问题

FLASH内部对所有字符串,默认都是以UTF-8处理
1.FLASH读文普通本文件(txt,html)
要将文本文件的编码存为UTF-8
点击编辑器的菜单:“文件”->“另存为”,可以看到当前文件的编码,确保文件编码为:UTF-8,
如果是ANSI,需要将编码改成:UTF-8。
2.FLASH读XML文件
要将XML文件的编码存为UTF-8
点击编辑器的菜单:“文件”->“另存为”,可以看到当前文件的编码,确保文件编码为:UTF-8,
如果是ANSI,需要将编码改成:UTF-8。
在XML第1行写:

3.FLASH读PHP返回数据
如果PHP编码本身是UTF-8的,直接echo就可以了
如果PHP编码本身是GB2312的,可以将PHP转存成UTF-8编码格式的文件,直接echo就可以了
如果PHP编码本身是GB2312的,而且不允许改文件的编码格式,
用下面的语句将字符串转换成UTF-8的编码格式
$new_str = iconv(“GB2312”, “UTF-8”, “$str”);
再echo就可以了
4.FLASH读数据库(MYSQL)的数据
FLASH要通过PHP读取数据库中的数据
PHP本身的编码不重要,关键是如果数据库的编码是GB2312的话,
需要用下面的语句将字符串转换成UTF-8的编码格式
$new_str = iconv(“GB2312”, “UTF-8”, “$str”);

5.FLASH通过PHP写数据
一句话,FLASH传过来的字符串是UTF-8格式的,
要转换成相应的编码格式,再操作(写文件、写数据库、直接显示等等)
还是用iconv函数转换
6.FLASH使用本地编码(理论上不推荐使用)
如果想让FLASH不使用UTF-8编码,而是使用本地编码
对于中国大陆地区而言,本地编码是GB2312或GBK
AS程序内,可以添加以下代码:
System.useCodepage = true;
那么FLASH内所有字符都是使用GB2312的编码了
所有导入到FLASH或者从FLASH导出的数据,都应该做相应的编码转换
因为使用本地编码,会造成使用繁体中文地区的用户产生乱码,所以不推荐使用