存档

文章标签 ‘php’

php中set names与mysql_set_charset

2010年4月13日 没有评论

今天看到大家在讨论,发现这是个很严重而又容易疏忽的问题,我以前也一直是用set names,遂记录下来,也提醒自己一把。

1.set names与mysql_set_charset有什么区别?

一般情况下, 使用”SET NAMES”就足够了, 也是可以保证正确的. 那么为什么手册又要说推荐使用 mysqli_set_charset(PHP>=5.0.5)呢。手册里面也没有明确说明。我们可以看下php扩展的源代码:

//php-5.2.11-SRC/ext/mysqli/mysqli_nonapi.c line 342
PHP_FUNCTION(mysqli_set_charset)
{
    MY_MYSQL            *mysql;
    zval                *mysql_link;
    char                *cs_name = NULL;
    unsigned int        len;
    if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis()
                , "Os", &mysql_link, mysqli_link_class_entry, &cs_name, &len) == FAILURE) {
        return;
    }
    MYSQLI_FETCH_RESOURCE(mysql, MY_MYSQL*, &mysql_link, "mysqli_link", MYSQLI_STATUS_VALID);
    if (mysql_set_character_set(mysql->mysql, cs_name)) {
                //** 调用libmysql的对应函数
        RETURN_FALSE;
    }
    RETURN_TRUE;
}

可以看到php的mysql扩展是直接调用了mysql的mysql_set_character_set函数,接下来看看mysql的代码

//mysql-5.1.30-SRC/libmysql/client.c, line 3166:
int STDCALL mysql_set_character_set(MYSQL *mysql, const char *cs_name)
{
  struct charset_info_st *cs;
  const char *save_csdir= charsets_dir;
  if (mysql->options.charset_dir)
    charsets_dir= mysql->options.charset_dir;
  if (strlen(cs_name) < MY_CS_NAME_SIZE &&
     (cs= get_charset_by_csname(cs_name, MY_CS_PRIMARY, MYF(0))))
  {
    char buff[MY_CS_NAME_SIZE + 10];
    charsets_dir= save_csdir;
    /* Skip execution of "SET NAMES" for pre-4.1 servers */
    if (mysql_get_server_version(mysql) < 40100)       return 0;     sprintf(buff, "SET NAMES %s", cs_name);     if (!mysql_real_query(mysql, buff, strlen(buff)))     {       mysql->charset= cs;
    }
  }
  //以下省略

可以看到,除了调用real_query设置set names,还设置了mysql的charset变量。

2.这样有什么影响?

mysql_real_escape_string会受到影响,它与mysql_escape_string的区别就 是,  它会考虑”当前”字符集。如果仅仅使用set names,mysql_real_escape_string可能会失效。

例子:

$mysqli = new mysqli("localhost", "user", "pass", "test", 3306);

/* check connection */
if (mysqli_connect_errno()) {
    printf("Connect failed: %s\n", mysqli_connect_error());
    exit();
}

$mysqli->query('SET NAMES gbk'); //使用set names设置字符集
$city = chr(0xbf).chr(0x5c); //0xbf5c是个有效的gbk字符,模拟用户输入
$city = $mysqli->real_escape_string ($city);//使用real_escape进行过滤

/* this query will fail, cause we didn't escape $city */
 if (!$mysqli->query("INSERT into myCity(name) VALUES ('$city')")) {
    print "INSERT into myCity (name) VALUES ('$city')\n";
    printf("Error: %s\n", $mysqli->error);
}

var_dump($city);

var_dump($mysqli->client_encoding());

$mysqli->close();

3.解决方案

mysqli_set_charset函数对PHP和Mysql有版本要求,必须当mysql版本大于5,PHP版本大于5.0.5时,此函数才有效。至于另一个mysql_set_charset函数,则更要求PHP版本大于5.2.3时才能有效。对于mysql4.1以上版本,使用”SET character_set_client=binary;”
推荐使用mysql_set_charset设置字符集的方案,只有在环境不允许的情况下,我们才推荐使用第二种binary编码的方案。但是无论在什么情况下,都禁止使用”SET NAMES”来作为设置字符集的操作。

---------------------------------------------------------------
本站作品根据创作共同协议进行授权, 转载时请务必以超链接形式标明文章原始出处
原文地址:http://www.mirecle.com/2010/04/13/php-in-the-set-names-and-mysql_set_charset.html
---------------------------------------------------------------

分类: 程序员 标签: ,

文件grep-选出两个文件中相同/不同的内容

2010年2月2日 没有评论

升级于2010-6-10,发现了一个bug,当时用notmatch模式时,如果文件2先eof将导致文件1中的内容没有输出

这个是最近做数据统计用的比较多的一个脚本,目的是根据key值,输出文件中相同或者不同的行。例如文件A的样子:

10000007^H_O
10000036^Hzerui
10000037^Hyanpeng_haha

文件B的样子:

10000037^Hyanpeng_haha

注意文件中的^H是一个字符,在vim中使用输入ctrl+v再输入ctrl+h就可以看到了,这里用它主要是起到文件不同列之间的分隔符作用

使用命令

php mygrep.php A B

可以得到“10000037^Hyanpeng_haha”这一行数据,使用命令

php mygrep.php A B “notmatch”

可以得到另外两行数据。

脚本默认使用第零列作为筛选依据,默认使用^H作为分隔符,在脚本中自己配置一下可以更改。脚本工作时,要求筛选依据是已排序的。对于排序,可以使用sort命令操作文件,sort通过-t参数指定分隔符,-f指定按照那一列进行排序。

mygrep.php的代码:

$base_file_name    = $argv[1];
$check_file_name   = $argv[2];
$mode              = isset($argv[3])?$argv[3]:false;

$field_index = 0;
$delimiter = ',';

//////////////////////////////////////////////////////////////
$base_file = @fopen($base_file_name, 'r');
$check_file = @fopen($check_file_name, 'r');
$read_base_file = true;
$compare_result = 0;
$readed_base_file_arr = array();

//以要检查的文件作为外层循环
while(!feof($check_file)){
    //读取要检查的文件
    $readed_check_arr = explode($delimiter, trim(fgets($check_file)));
    do{
        //读取基准文件
        if($read_base_file === true){
            $readed_base_arr = explode($delimiter, trim(fgets($base_file)));
        }   

        //作比较
        $compare_result = strcmp($readed_check_arr[$field_index], $readed_base_arr[$field_index]);
        $grep_flag = ($compare_result == 0);
        //如果是要取出不相等的数据
        //且检查key小于或等于基准key时,说明需要将检查key下移一行,即此比较key已经比较完成
        //此时如果比较结果相等则不输出,
        //如果比较结果不等,并且检查key大于基准key则输出,如果检查结果小于基准key,说明检查key要下移继续检查
        if($mode !== false && (strcmp($mode, "notmatch") == 0)
            && $compare_result >= 0){
            $grep_flag = !$grep_flag;
        }

        //print("comparing check=".$readed_check_arr[$field_index]." base=".$readed_base_arr[$field_index]." result=$compare_result
grep_flag=$grep_flag\n");

        if($grep_flag){
            print implode($delimiter, $readed_base_arr)."\n";
        }

        //总是设置为要读取,如果跳出循环,则由外面设置
        $read_base_file = true;

    //如果检查的key是大于基准的key,并且检查文件未到尾,则重新读取一行基准文件进行检查
    }while($compare_result > 0 && !feof($base_file));

    if(feof($base_file)){
        break;
    }

    //当检查key小于基准key时,不读取下个基准key,等于则是因为已经比较过,两个都需要读取
    if($compare_result < 0){
        $read_base_file = false;
    }
}

//当check_file结束了但是base_file未结束
do{
    print implode($delimiter, $readed_base_arr)."\n";
    $readed_base_arr = explode($delimiter, trim(fgets($base_file)));
}while(!feof($base_file));

fclose($check_file);
fclose($base_file);

---------------------------------------------------------------
本站作品根据创作共同协议进行授权, 转载时请务必以超链接形式标明文章原始出处
原文地址:http://www.mirecle.com/2010/02/02/file-grep-select-two-files-same-different-content.html
---------------------------------------------------------------

分类: 程序员, 软件 标签:

php反射效果:基类访问子类数据

2010年1月18日 2 条评论

php不用学习直接使用的特点,使它迅速风靡起来,并且被很多不注意的人用烂。当然,它在设计之初就没有考虑采用很规范化的方式也是原因之一。最近在写代码的偷懒之余,偶然发现,基类是可以访问子类的数据的(php 5.2.6):

class base{

    protected $data_test1 = false;

    //FIXME 这个搞法太山寨了
    function set_data($name, $data){
        $this->$name = $data;
    }
}

class extend extends base{
    protected $data_test2 = false;

    function do_output(){
        var_dump($this->data_test2);
    }
}

$test_class = new extend();
$test_class->set_data("data_test1", "hello1");
$test_class->set_data("data_test2", "hello2");
var_dump($test_class);
$test_class->do_output();

看看结果就能知道,php没有将方法的作用范围与类严格的绑定在一起。不过这个对依赖注入的框架来说,这个算是好事了,只需要以数组的形式提供自己所需要的数据,框架用个foreach就给注入进去了。

---------------------------------------------------------------
本站作品根据创作共同协议进行授权, 转载时请务必以超链接形式标明文章原始出处
原文地址:http://www.mirecle.com/2010/01/18/php-reflection-effect-the-base-class-to-access-sub-categories-of-data.html
---------------------------------------------------------------

分类: 程序员 标签: