The MySQL C API

简介

C APIs包含在mysqlclient库文件当中与MySQL的源代码一块发行,用于连接到数据库和执行数据库查询。有一些例子在MySQL原代码的clients目录里。

MySQL C 变量类型

以下变量类型在MySQL的库当中定义。我们需要这些变量是为了使用MySQL的函数。这些变量有详细的解释,但是这些解释对于写代码来说并不重要。

MYSQL

要连接MYSQL,必须建立MYSQL实例,通过mysql_init初始化方能开始进行连接。

[code=c]typedef struct st_mysql {
NET           net;            /* Communication parameters */
gptr          connector_fd;   /* ConnectorFd for SSL */
char          *host,*user,*passwd,*unix_socket,
*server_version,*host_info,*info,*db;
unsigned int  port,client_flag,server_capabilities;
unsigned int  protocol_version;
unsigned int  field_count;
unsigned int  server_status;
unsigned long thread_id;      /* Id for connection in server */
my_ulonglong affected_rows;
my_ulonglong insert_id;       /* id if insert on table with NEXTNR */
my_ulonglong extra_info;              /* Used by mysqlshow */
unsigned long packet_length;
enum mysql_status status;
MYSQL_FIELD   *fields;
MEM_ROOT      field_alloc;
my_bool       free_me;        /* If free in mysql_close */
my_bool       reconnect;      /* set to 1 if automatic reconnect */
struct st_mysql_options options;
char          scramble_buff[9];
struct charset_info_st *charset;
unsigned int  server_language;
} MYSQL;[/code]

MYSQL_RES

这个结构代表返回行的一个查询的(SELECT, SHOW, DESCRIBE, EXPLAIN)的结果。返回的数据称为“数据集”,在C的API里对应的就是MYSQL_RES,从数据库读取数据,最后就是从MYSQL_RES中读取数据。

[code=c]typedef struct st_mysql_res {
my_ulonglong row_count;
unsigned int  field_count, current_field;
MYSQL_FIELD   *fields;
MYSQL_DATA    *data;
MYSQL_ROWS    *data_cursor;
MEM_ROOT      field_alloc;
MYSQL_ROW     row;            /* If unbuffered read */
MYSQL_ROW     current_row;    /* buffer to current row */
unsigned long *lengths;       /* column lengths of current row */
MYSQL         *handle;        /* for unbuffered reads */
my_bool       eof;            /* Used my mysql_fetch_row */
} MYSQL_RES;[/code]

MYSQL_ROW

这是一个行数据的类型安全(type-safe)的表示。当前它实现为一个计数字节的字符串数组。(如果字段值可能包含二进制数据,你不能将这些视为空终止串,因为这样的值可以在内部包含空字节) 行通过调用mysql_fetch_row()获得。

typedef char **MYSQL_ROW;

MYSQL_FIELD

这个结构包含字段信息,例如字段名、类型和大小。其成员在下面更详细地描述。你可以通过重复调用mysql_fetch_field()对每一列获得MYSQL_FIELD结构。字段值不是这个结构的部分;它们被包含在一个MYSQL_ROW结构中。

[code=c]typedef struct st_mysql_field {
char *name;                   /* Name of column */
char *table;                  /* Table of column if column was a field */
char *def;                    /* Default value (set by mysql_list_fields) */
enum enum_field_types type;   /* Type of field. Se mysql_com.h for types */
unsigned int length;          /* Width of column */
unsigned int max_length;      /* Max width of selected set */
unsigned int flags;           /* Div flags */
unsigned int decimals;        /* Number of decimals in field */
} MYSQL_FIELD;[/code]

my_ulonglong
typedef unsigned long my_ulonglong;

该类型用于行编号和mysql_affected_rows()、mysql_num_rows()和mysql_insert_id()。这种类型提供 0到1.84e19的一个范围。在一些系统上,试图打印类型my_ulonglong的值将不工作。为了打印出这样的值,将它变换到unsigned long并且使用一个%lu打印格式。例如:

printf (“Number of rows: %lun”, (unsigned long) mysql_num_rows(result));

连接MySQL,查询数据

MySQL的库文件在mysqlclient,因此在编译MySQL程序的时候有必要加上-lmysqlclient编译选项。
MySQL 的头文件在/usr/include/mysql目录下(根据Linux的发行版本的不同,这个目录也有所不同),因此你的程序头部看起来有点这个样子:

#include <mysql.h>

MySQL的变量类型和函数都包含在这个头文件当中

然后,我们需要创建连接数据库的变量,可以简单地这么做:

MYSQL mysql;

在连接数据库之前,先调用以下函数初始化这个变量:

mysql_init(&mysql);

然后,调用mysql_real_connect函数:

[code=c]
MYSQL *         STDCALL mysql_real_connect(MYSQL *mysql, const char *host,
const char *user,
const char *passwd,
const char *db,
unsigned int port,
const char *unix_socket,
unsigned int clientflag);[/code]

该函数被调用连接到数据库。host是MySQL服务器的主机名,user是登录的用户名,passwd是登录密码,db是要连接的数据库,port是 MySQL服务器的TCP/IP端口,unix_socket是连接类型,clientflag是MySQL运行成ODBC数据库的标记。连接寻建立后,这个函数返回0。

现在可以连接数据库,进行查询了:

char *query;

使用这个字符串我们可以创立任何SQL查询语句进行查询。执行这个查询的函数是:

int STDCALL mysql_real_query(MYSQL *mysql, const char *q, unsigned int length);

mysql是我们前面用过的变量,q是SQL查询语句,length是这个查询语句的长度。如果查询成功,函数返回0。

查询之后,我们要到一个MYSQL_RES变量来使用查询的结果。以下这行创立这个变量:

MYSQL_RES *res;

然后

 res = mysql_store_result(&mysql);

对客户端而言,有两种方法处理结果集合。一种方法是通过调用mysql_store_result()立刻检索全部结果。该函数从服务器获得查询返回的所有行,并将他们存储在客户端。第二种方法是对客户通过调用mysql_use_result()初始化一个一行一行地结果集合的检索。该函数初始化检索,但是实际上不从服务器获得任何行。

在两种情况中,你通过mysql_fetch_row()存取行。用mysql_store_result()、mysql_fetch_row()储存取已经从服务器被取出的行。用mysql_use_result()、mysql_fetch_row()实际上从服务器检索行。调用 mysql_fetch_lengths()可获得关于每行中数据值尺寸的信息。

在你用完一个结果集合以后,调用mysql_free_result()释放由它使用的内存。

两种检索机制是互补的。客户程序应该选择最适合他们的要求的途径。在实践中,客户通常更愿意使用mysql_store_result()。

该函数读出查询结果。

尽管可以很容易地查询了,要用这个查询的结果还要用到其它的函数。第一个是:

 MYSQL_ROW STDCALL mysql_fetch_row(MYSQL_RES *result);

该函数把结果转换成“数组”。你可能注意到了,该函数返回的是MYSQL_ROW变量类型。以下语句创立那样的变量:

 MYSQL_ROW row = mysql_fetch_row(res)

如前所解释的,变量row是一个字符串数组。也就是说,row[0]是数组的第一个值,row[1]是数组的第二个值…当我们用mysql_fetch_row的时候,接着变量row会取得结果的下一组的数据。当到了结果的尾部,该函数返回一负值。

使用数据集结束后,记得释放数据集,否则会发生内存泄漏,释放数据集函数如下:

void mysql_free_result(MYSQL_RES *result)

释放由mysql_store_result()、mysql_use_result()、mysql_list_dbs()等为一个结果集合分配的内存。当你用完了一个结果集合时,你必须调用mysql_free_result()来释放它使用的内存。

最后我们要关闭这个连接:

mysql_close(&mysql);

例子程序

执行一个select操作,从数据库中取数据,并执行一个insert操作,往数据库中插入数据,根据这两个操作你可以自由的扩展为任意数据库操作,
准备条件

1、已经安装mysql,上有数据库test,如果没有执行Create Databse test

建立数据库

2、test数据库上有表t1,如果没有,执行CREATE TABLE `t1` (
`id` int(11) default NULL,
`name` varchar(100) default NULL
)

建立表t1
testsql.c:

[code=c]
#include <mysql.h>
#include <stdio.h>
int main(){
MYSQL mysql;     // need a instance to init
MYSQL_RES *res;
MYSQL_ROW row;
char *query;
int t,r;
// connect the database
mysql_init(&mysql);
if (!mysql_real_connect(&mysql,”localhost”, “mmim”, “mmim”, “test”,0,NULL,0))
{
printf( “Error connecting to database: %sn”,mysql_error(&mysql));
}
else printf(“Connected…n”);

// get the result from the executing select query
query = “select * from t1”;

t = mysql_real_query(&mysql,query,(unsigned int) strlen(query));
if (t)
{
printf(“Error making query: %sn”,
mysql_error(&mysql));
}
else printf(“[%s] made…n”, query);
res = mysql_store_result(&mysql);
while(row = mysql_fetch_row(res))
{
for(t=0;t<mysql_num_fields(res);t++)
{
printf(“%s “,row[t]);
}
printf(“n”);
}

printf(“mysql_free_result…n”);
mysql_free_result(res);     //free result after you get the result

sleep(1);

// execute the insert query
query = “insert into t1(id, name) values(3, ‘kunp’)”;
t = mysql_real_query(&mysql,query,(unsigned int) strlen(query));
if (t)
{
printf(“Error making query: %sn”,
mysql_error(&mysql));
}
else printf(“[%s] made…n”, query);

mysql_close(&mysql);

return 0;
}
[/code]

编译

假定mysql的头文件在/usr/include/mysql,库文件在/usr/lib/mysql,执行下列命令进行编译:
gcc testsql.c -I/usr/include/mysql -L/usr/lib/mysql -lmysqlclient

php基础测试

如何改进以下的这行php代码?这段代码可以被用来测试php工程师应聘者。

< ?
echo(“Search results for query: ” .$_GET[‘query’] . “.”);
? >

这段代码非常适合用来测试一个php开发人员是否合格。因为这段代码并没有要求太多记忆上的东西(例如函数的记忆),但是对安全,性能,兼容性上都做了考察。

继续阅读“php基础测试”

用 memcache 来存储 session

PECL :: Package :: memcache 2.1.1 版本的 Changelog 中有一条:

– Added experimental session storage support. You can use memcached as session storage.

也就是可以直接用 memcache 来作 PHP 的 session.save_handler。

1. 安装 memcached:
标准的

./configure; make; make install

注意 memcached 用 libevent 来作事件驱动,所以要先安装有 libevent。

2. 安装 pecl::memcache,用 pecl 命令行工具安装:

pecl install memcache

或直接从源码安装:

phpize
./configure
make
make install

将 php.ini 中 extension=memcache.so 打开,重启一下 apache,查看 phpinfo 中的 “Registered save handlers” 会有 “files user memcache” 这3个可用。

3. 修改配置文件,在 php.ini 中全局设置:

session.save_handler = memcache
session.save_path = “tcp://127.0.0.1:11211”

或者某个目录下的 .htaccess :

php_value session.save_handler “memcache”
php_value session.save_path “tcp://127.0.0.1:11211”

再或者在某个一个应用中:

ini_set(“session.save_handler”, “memcache”);
ini_set(“session.save_path”, “tcp://127.0.0.1:11211”);

使用多个 memcached server 时用逗号”,”隔开,并且和 Memcache::addServer() 文档中说明的一样,可以带额外的参数”persistent”、”weight”、”timeout”、”retry_interval” 等等,类似这样的:

“tcp://host1:port1?persistent=1&weight=2,tcp://host2:port2”

4. 启动 memcached:

memcached -d -l 127.0.0.1 -p 11212 -m 128

5. 在程序中使用 memcache 来作 session 存储,用例子测试一下:

session_start();
if (!isset($_SESSION[‘TEST’])) {
$_SESSION[‘TEST’] = time();
}

$_SESSION[‘TEST3’] = time();

print $_SESSION[‘TEST’];
print “<br><br>”;
print $_SESSION[‘TEST3’];
print “<br><br>”;
print session_id();

6. 用 sessionid 去 memcached 里查询一下:

$memcache = memcache_connect(‘localhost’, 11211);
var_dump($memcache->get(‘19216821213c65cedec65b0883238c278eeb573e077’));

会有看到

string(37) “TEST|i:1177556731;TEST3|i:1177556881;”

这样的输出,证明 session 正常工作。

用 memcache 来存储 session 在读写速度上会比 files 时快很多,而且在多个服务器需要共用 session 时会比较方便,将这些服务器都配置成使用同一组 memcached 服务器就可以,减少了额外的工作量。缺点是 session 数据都保存在 memory 中,持久化方面有所欠缺,但对 session 数据来说也不是很大的问题。

另外,WS Memcached Session Handler for PHP 提供了另外一种用 session_set_save_handler 来利用 memcached 的方法,可以参考。

编码的陷阱之 mysql

MySQL 从 4.1 开始对多语言的支持有了很大变化 ,这导致了问题的出现。

许多 PHP 程序以 MySQL 作为默认的数据库管理软件,但它们一般不区分 MySQL 4.1 与 4.1 以下版本的区别,笼统地称“MySQL 3.xx.xx 以上版本”就满足安装需求了。因为 latin1 在许多地方 (下边会详细描述具体是哪些地方) 作为默认的字符集,成功的蒙蔽了许多 PHP 程序的开发者和用户,掩盖了在中文等语言环境下会出现的问题。
简单的说,MySQL 自身的变化和使用 MySQL 的 PHP 程序对此忽略,导致了问题的出现和复杂化,而由于大部分用户使用的是英文,使这种问题不被重视。这里提到的 PHP 程序,以 WordPress 为例。

MySQL 4.1 字符集支持的粒度:MySQL 4.1 对于字符集的指定可以细化到一台机器上安装的 MySQL,其中的一个数据库,其中的一张表,其中的一栏,应该用什么字符集。但是,传统的 Web 程序在创建数据库和数据表时并没有使用那么复杂的配置,它们用的是默认的配置,那么,默认的配置从何而来呢?

编译 MySQL 时,指定了一个默认的字符集,这个字符集是 latin1;
安装 MySQL 时,可以在配置文件 (my.ini,my.cnf) 中指定一个默认的的字符集,如果没指定,这个值继承自编译时指定的;
启动 mysqld 时,可以在命令行参数中指定一个默认的的字符集,如果没指定,这个值继承自配置文件中的;
此时 character_set_server 被设定为这个默认的字符集;
当创建一个新的数据库时,除非明确指定,这个数据库的字符集被缺省设定为 character_set_server;
当选定了一个数据库时,character_set_database 被设定为这个数据库默认的字符集;
在这个数据库里创建一张表时,表默认的字符集被设定为 character_set_database,也就是这个数据库默认的字符集;
当在表内设置一栏时,除非明确指定,否则此栏缺省的字符集就是表默认的字符集;
这个字符集就是数据库中实际存储数据采用的字符集,mysqldump 出来的内容就是这个字符集下的;
简 单的总结一下,如果什么地方都不修改,那么所有的数据库的所有表的所有栏位的都用 latin1 存储,不过我们如果安装 MySQL,一般都会选择多语言支持,也就是说,安装程序会自动在配置文件中把 default_character_set 设置为 UTF-8,这保证了缺省情况下,所有的数据库的所有表的所有栏位的都用 UTF-8 存储。

当一个 PHP 程序与 MySQL 建立连接后,这个程序发送给 MySQL 的数据采用的是什么字符集?MySQL 无从得知 (它最多只能猜测),所以 MySQL 4.1 要求客户端必须指定这个字符集,也就是 character_set_client,MySQL 的怪异之处在于,得到的这个字符集并不立即转换为存储在数据库中的那个字符集,而是先转换为 character_set_connection 变量指定的一个字符集;这个 connection 层究竟有什么用我不大明白,但转换为 character_set_connection 的这个字符集之后,还要转换为数据库默认的字符集,也就是说要经过两次转换;当这个数据被输出时,又要由数据库默认的字符集转换为 character_set_results 指定的字符集。这样,最终PHP程序获得的,是以character_set_results 指定的字符集编码的数据。

被保护: 我的WebService

  • 盛大灵游记:http://shop.ourgame.com/GLGGBilling/Service4Partner.asmx
  • 新浪机战:http://222.77.177.169/sinapay/ChargeMoneyInterface1.asmx
  • 腾龙功夫世界:http://secure.tengwu.com.cn/MainService.asmx
  • 星级家园:(非webservice提供接口)
  • PHP5 Soap 接口代码框架:

    try {
    $response = $soap_client->__soapCall("m_GetRolesList",$params);
    if ($response['m_GetRolesListResult'] != 1) {
    $err = m_GFSJ_GetErrText($response['m_GetRolesListResult']);
    $loge->uniLog("$err");
    return false;
    }else {
    $logv->uniLog("{$response['lsRoleIDName']}");
    $rolestr = trim($response['lsRoleIDName']);
    return $rolestr;
    }
    } catch (SoapFault $fault) {
    $loge->uniLog("faultcode:{$fault->faultcode}tfaultstring:{$fault->faultstring}");
    return false;
    }

    PHP忽略用户中断

            做  Web 开发的人都知道,浏览器和服务器之间是通过 HTTP 协议进行连接通讯的。这是一种基于请求和响应模型的协议。浏览器通过 URL 向某台服务器发起请求(Request),Web 服务器接收到请求,执行一段程序,然后做出响应(Response),也就是一段字符串,这个字符串符合 HTTP 协议的格式,有 HEAD 和 BODY 两部分。

    这其中有一个问题,Web  服务器执行一段程序,可能几毫秒就完成,也可能几分钟都完不成。如果程序执行缓慢,用户可能没有耐心等下去,就关闭浏览器了。这个时候,服务器会接收到连 接状态改变的通知,因为 HTTP  是最上层的协议,下面还有一层 TCP 协议,TCP  会知道连接中断。连接一断,服务端的程序会立即停止执行。

    现在说到问题的关键了,服务端的程序立即停止执行,如果这个程序只是读取信息的还好说,停了不读了就是了。万一是一个写入的程序呢?比如,用户提交一 段文本,也许服务端的设计比较复杂,需要同时更新好几个表,但由于某些原因,例如其中一个表被其他进程锁定,那么这个程序就会一直等待,这个时候用户要是 关闭浏览器,那程序就不等了,直接退出了。结果就是这条信息保存不完整。

    举个具体的例子,用户提交的文本需要写到 A、B、C、D 四个表里,写入 A、B 两个表可能 0.1 毫秒就完成了,但 C 表被另一个进程锁定,那当前进程就得一直等,这时用户关闭浏览器,当前进程退出,那么,就会造成一种状况,A、B 表里有新的内容,而 C、D 表里没有这条内容,产生了严重的数据一致性的问题!

    虽然,利用数据库的事务,可以使状态回滚,但结果就是用户的本次提交无效。

    现在希望的是,只要用户提交了,就要成功保存,也许遇到意外情况导致执行时间过长,但用户关闭浏览器也没关系。

    于是,就需要 ignore_user_abort 这个函数。

    当调用 ignore_user_abort(1) 时, 就设定了忽略用户退出这个标志位,也就是不管怎样,也要把程序执行到底,除非在程序中调用了 exit。

    其实,还有另一个函数,register_shutdown_function,它可以注册一个函数或方法,在程序退出的时候调用,有些类似于 javascript 里面的 onunload 和 onbeforeunload 事件。

    这里引用了PHP手册中文版的相关内容:

    章 40. 连接处理
    注意: 以下内容对 PHP 3.0.7 及更高版本适用。

    在 PHP 内部,系统维护着连接状态,其状态有三种可能的情况:

    0 – NORMAL(正常)

    1 – ABORTED(异常退出)

    2 – TIMEOUT(超时)

    当 PHP 脚本正常地运行 NORMAL 状态时,连接为有效。当远程客户端中断连接时,ABORTED 状态的标记将会被打开。远程客户端连接的中断通常是由用户点击 STOP 按钮导致的。当连接时间超过 PHP 的时限(请参阅 set_time_limit() 函数)时,TIMEOUT 状态的标记将被打开。

    可以决定脚本是否需要在客户端中断连接时退出。有时候让脚本完整地运行会带来很多方便,即使没有远程浏览器接受脚本的输出。默认的情况是当远程客户 端连接中断时脚本将会退出。该处理过程可由 php.ini 的 ignore_user_abort 或由 Apache .conf 设置中对应的“php_value ignore_user_abort”以及 ignore_user_abort() 函数来控制。如果没有告诉 PHP 忽略用户的中断,脚本将会被中断,除非通过 register_shutdown_function() 设置了关闭触发函数。通过该关闭触发函数,当远程用户点击 STOP 按钮后,脚本再次尝试输出数据时,PHP 将会检测到连接已被中断,并调用关闭触发函数。

    脚本也有可能被内置的脚本计时器中断。默认的超时限制为 30 秒。这个值可以通过设置 php.ini 的 max_execution_time 或 Apache .conf 设置中对应的“php_value max_execution_time”参数或者 set_time_limit() 函数来更改。当计数器超时的时候,脚本将会类似于以上连接中断的情况退出,先前被注册过的关闭触发函数也将在这时被执行。在该关闭触发函数中,可以通过调 用 connection_status() 函数来检查超时是否导致关闭触发函数被调用。如果超时导致了关闭触发函数的调用,该函数将返回 2。

    需要注意的一点是 ABORTED 和 TIMEOUT 状态可以同时有效。这在告诉 PHP 忽略用户的退出操作时是可能的。PHP 将仍然注意用户已经中断了连接但脚本仍然在运行的情况。如果到了运行的时间限制,脚本将被退出,设置过的关闭触发函数也将被执行。在这时会发现函数 connection_status() 返回 3。

    PHP 的官方网站在线文档有英文原版说明,下面还有一些用户的反馈,也很有价值,这里是链接:

     http://www.php.net/manual/en/features.connection-handling.php

    PHP的一个bug

    “Fatal error:Maximum execution time of 0 seconds exceeded”

    php.ini 设置:

    max_execution_time = 0 ; Maximum execution time of each script, in seconds
    max_input_time = 60 ; Maximum amount of time each script may spend parsing request data
    memory_limit = 128M ; Maximum amount of memory a script may consume (128MB)

    这里报错并不是因为脚本执行时间超时,而是输入时间超时,属于错误定位不准确,导致出错信息无效甚至误导编程者。

    我的 minicraw 脚本在某些服务器上总是死掉,找了半天,才在 google 上找到答案。其实应该是:Maximum input time of 60 seconds exceeded。解决办法:将 max_input_time = 60 改为 max_input_time = 0 即可。

    PHP清除指定内容的HTML标记

    系统带的函数:

    strip_tags($str); // Strip HTML and PHP tags from a string

    自己写的函数:

    /**
    * 清除指定内容中的HTML 标记
    *
    * @param string $content
    * @return string $text
    */
    function clear_tag($content)
    {
    $search = array (“‘‘si”, // 去掉 javascript
    “‘

    ‘si”, // 去掉 javascript
    “‘<[/!]*?[^]*?>’si”, // 去掉 HTML 标记
    “‘([rn])[s]+'”, // 去掉空白字符
    “‘&(quot|#34);’i”, // 替换 HTML 实体
    “‘&(amp|#38);’i”,
    “‘&(lt|#60);’i”,
    “‘&(gt|#62);’i”,
    “‘&(nbsp|#160);’i”,
    “‘&(iexcl|#161);’i”,
    “‘&(cent|#162);’i”,
    “‘&(pound|#163);’i”,
    “‘&(copy|#169);’i”,
    “‘&#(d+);’e”,
    “‘[s]+'”
    ); // 作为 PHP 代码运行

    $replace = array (“”,
    “”,
    “”,
    “1”,
    “””,
    “&”,
    “”,
    ” “,
    chr(161),
    chr(162),
    chr(163),
    chr(169),
    “chr(1)”,
    “” );

    $text = preg_replace ($search, $replace, $content);
    return $text;
    }

    PHP中GBK和UTF8编码处理

    一、编码范围1. GBK (GB2312/GB18030)
    x00-xff GBK双字节编码范围
    x20-x7f ASCII
    xa1-xff 中文
    x80-xff 中文

    2. UTF-8 (Unicode)
    u4e00-u9fa5 (中文)
    x3130-x318F (韩文
    xAC00-xD7A3 (韩文)
    u0800-u4e00 (日文)
    ps: 韩文是大于[u9fa5]的字符
    正则例子:
    preg_replace(“/([x80-xff])/”,””,$str);
    preg_replace(“/([u4e00-u9fa5])/”,””,$str);

    二、代码例子

    //判断内容里有没有中文-GBK (PHP)
    function check_is_chinese($s){
    return preg_match(‘/[x80-xff]./’, $s);
    }

    //获取字符串长度-GBK (PHP)
    function gb_strlen($str){
    $count = 0;
    for($i=0; $i<strlen($str); $i++){
    $s = substr($str, $i, 1);
    if (preg_match("/[x80-xff]/", $s)) ++$i;
    ++$count;
    }
    return $count;
    }

    //截取字符串字串-GBK (PHP)
    function gb_substr($str, $len){
    $count = 0;
    for($i=0; $i<strlen($str); $i++){
    if($count == $len) break;
    if(preg_match("/[x80-xff]/", substr($str, $i, 1))) ++$i;
    ++$count;
    }
    return substr($str, 0, $i);
    }

    //统计字符串长度-UTF8 (PHP)
    function utf8_strlen($str) {
    $count = 0;
    for($i = 0; $i 127) {
    $count++;
    if($value >= 192 && $value = 224 && $value = 240 && $value <= 247) $i = $i + 3;
    else die('Not a UTF-8 compatible string');
    }
    $count++;
    }
    return $count;
    }

    //截取字符串-UTF8(PHP)
    function utf8_substr($str,$position,$length){
    $start_position = strlen($str);
    $start_byte = 0;
    $end_position = strlen($str);
    $count = 0;
    for($i = 0; $i = $position && $start_position > $i){
    $start_position = $i;
    $start_byte = $count;
    }
    if(($count-$start_byte)>=$length) {
    $end_position = $i;
    break;
    }
    $value = ord($str[$i]);
    if($value > 127){
    $count++;
    if($value >= 192 && $value = 224 && $value = 240 && $value <= 247) $i = $i + 3;
    else die('Not a UTF-8 compatible string');
    }
    $count++;

    }
    return(substr($str,$start_position,$end_position-$start_position));
    }

    //判断是否是有韩文-UTF-8 (JavaScript)
    function checkKoreaChar(str) {
    for(i=0; i 0x3130 && str.charCodeAt(i) = 0xAC00 && str.charCodeAt(i) <= 0xD7A3))) {
    return true;
    }
    }
    return false;
    }

    //判断是否有中文字符-GBK (JavaScript)
    function check_chinese_char(s){
    return (s.length != s.replace(/[^x00-xff]/g,"**").length);
    }