PHP扩展中使用php.ini中的配置

编写PHP扩展的时候使用PHP自带的ext_skel生成一个模板文件,里面会包含一些初始设置和注释,可以方便初学者搞懂一些基础知识

这里讲讲编写扩展的时候如何读取在php.ini中设置的值,这里以testini扩展为例

./ext_skel –extname=testini

打开testini.c会看到有一下几行代码:

/* {{{ PHP_INI
 */
/* Remove comments and fill if you need to have entries in php.ini
PHP_INI_BEGIN()
    STD_PHP_INI_ENTRY("testini.global_value",      "42", PHP_INI_ALL, OnUpdateLong, global_value, zend_testini_globals, testini_globals)
    STD_PHP_INI_ENTRY("testini.global_string", "foobar", PHP_INI_ALL, OnUpdateString, global_string, zend_testini_globals, testini_globals)
PHP_INI_END()
*/
/* }}} */

可以看出,这段代码默认是被注释掉了的,要使用他,先把注释去掉:

PHP_INI_BEGIN()
    STD_PHP_INI_ENTRY("testini.global_value",      "42", PHP_INI_ALL, OnUpdateLong, global_value, zend_testini_globals, testini_globals)
    STD_PHP_INI_ENTRY("testini.global_string", "foobar", PHP_INI_ALL, OnUpdateString, global_string, zend_testini_globals, testini_globals)
PHP_INI_END()

然后把STD_PHP_INI_ENTRY(“test………)替换成PHP_INI_ENTRY(“testini………”,      “42″, PHP_INI_ALL, NULL),即:

PHP_INI_BEGIN()
    PHP_INI_ENTRY("testini.global_value",      "42", PHP_INI_ALL, NULL)
    PHP_INI_ENTRY("testini.global_string", "foobar", PHP_INI_ALL, NULL)
PHP_INI_END()

然后找到如下代码:

/* {{{ PHP_MINIT_FUNCTION
 */
PHP_MINIT_FUNCTION(testini)
{
 /* If you have INI entries, uncomment these lines
 REGISTER_INI_ENTRIES();
 */
 return SUCCESS;
}
/* }}} */

/* {{{ PHP_MSHUTDOWN_FUNCTION
 */
PHP_MSHUTDOWN_FUNCTION(testini)
{
 /* uncomment this line if you have INI entries
 UNREGISTER_INI_ENTRIES();
 */
 return SUCCESS;
}
/* }}} */

去掉里面的注释变成:

/* {{{ PHP_MINIT_FUNCTION
 */
PHP_MINIT_FUNCTION(testini)
{
  REGISTER_INI_ENTRIES();

 return SUCCESS;
}
/* }}} */

/* {{{ PHP_MSHUTDOWN_FUNCTION
 */
PHP_MSHUTDOWN_FUNCTION(testini)
{
  UNREGISTER_INI_ENTRIES();

 return SUCCESS;
}
/* }}} */

好了,再在你的php.ini设置
testini.global_string = test
testini.global_value = 1234

这样,便可以通过INI_INT、INI_STR等获取值了,比如:INI_STR(“testini.global_string”)

PHP扩展入门之吸取QQ歌词

书接上篇博文讲的《PHP吸星大法之吸取QQ歌词》,为了学习PHP扩展的编写,我把这个用PHP扩展实现,与同学们共同学习。

QQ歌词的获取办法如果有不清楚的回到上一篇文章看一下。

这个扩展我取名叫qqlrc,只有一个函数 string fetch_lrc($author, $songname),该函数传递歌手和歌名信息,返回LRC歌词字符串。

进入PHP源码中的扩展目录:
$ cd php-5.2.10/ext 

编写qqlrc.proto函数列表如下:
fetch_lrc(char *author, char *songname)

使用ext_skel生成向导文件:
$ ./ext_skel –extname=qqlrc –proto=qqlrc.proto

进入qqlrc目录,修改config.m4,并用phpize预设编译环境:
去掉“PHP_ARG_WITH(qqlrc, for qqlrc support,
dnl Make sure that the comment is aligned:
[  --with-qqlrc             Include qqlrc support])”前的dnl
$ /usr/local/php/bin/phpize

打开qqlrc.c文件,找到函数fetch_lrc的地方。

添加三个函数replace_all(用于替换空格等)、get_songid(分析出获得数据中的歌曲id号)、get_lrc(获取指定歌曲的lrc数据),这三个函数如下:

static void replace_all(char* *o_str, char *r_str, char *t_str){
    char *pts = estrdup(*o_str);
    char result[strlen(*o_str)];
    result[0] = '\0';
    while(pts[0]!='\0'){
        char *tmp = estrndup(pts, strlen(r_str));
        if(strcmp(tmp, r_str)==0){
            strcat(result, t_str);
        }else {
            tmp = estrndup(pts, 1);
            strcat(result, tmp);
        }
        efree(tmp);
        pts++;
    }
    (*o_str) = strdup(result);
}
static void get_songid(char *json_str, char* *songid, int offset){
    int num = 0;
    char *flag_word = "song_id:\"";
    char tmpid[100];
    tmpid[0] = '\0';
    *songid = emalloc(1);
    (*songid)[0] = '\0';
    while(json_str[0]!='\0'){
        if(strcmp(estrndup(json_str, strlen(flag_word)), flag_word)==0){
            if(num==offset){
                char *tmp;
                tmp = estrndup(json_str+strlen(flag_word), 1);
                strcat(tmpid, tmp);
            }
            json_str+=strlen(flag_word)+1;
            num++;
        }else {
            if(strlen(tmpid)>0){
                char *c;
                c = estrndup(json_str, 1);
                if(strcmp(c, "\"")==0){
                    *songid = estrdup(tmpid);
                    return;
                }else{
                    strcat(tmpid, c);
                }
                efree(c);
            }
            json_str++;
        }
    }
}
static void get_lrc(char *xml, char* *lrc){
    char *xml2 = estrdup(xml);
    char *start_tag = "<![CDATA[";
    char *end_tag = "]]>";
    int start_pos = 0;
    int end_pos = 0;
    int pos = 0;
    *lrc = emalloc(1);
    (*lrc)[0] = '\0';
    while(xml2[0]!='\0'){
        if(start_pos==0&&strcmp(estrndup(xml2, strlen(start_tag)), start_tag)==0){
            start_pos = pos+strlen(start_tag);
        }else if(strcmp(estrndup(xml2, strlen(end_tag)), end_tag)==0){
            end_pos = pos;
        }
        xml2++;
        pos++;
    }
    if(start_pos!=end_pos)
        *lrc = estrndup(xml+start_pos, end_pos-start_pos-1);
}

主程序函数fetch_lrc(char *author, char *song_name, int offset):

/* {{{ proto  fetch_lrc()
   char *author, char *song, int offset) */
PHP_FUNCTION(fetch_lrc)
{
//判断传递的参数数量,必须三个都有
 if (ZEND_NUM_ARGS() != 3) {
  WRONG_PARAM_COUNT;
 }
 char *author;
 int author_len;
 char *songname;
 int songname_len;
 int offset;
//读出参数值,存入变量author songname songname_len,数据类型为ssl,即String String Long(PHP中没有int) 
if(zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ssl", &author, &author_len, &songname, &songname_len, &offset)==FAILURE) RETURN_FALSE;
 char *keywords = (char*)emalloc(100);
//将songname和author合并,并将所有的空格替换为"+"
 sprintf(keywords, "%s %s", author, songname);
 replace_all(&keywords, " ", "+");
 char *search_url = (char*)emalloc(250);
//构建出QQ Music网页版的歌曲搜索Url
 sprintf(search_url, http://shopcgi.qqmusic.qq.com/fcgi-bin/shopsearch.fcg?value=%s&type=qry_song&out=json&page_no=1&page_record_num=10&", keywords);
//新建PHP Stream,用于读取seach_url的返回值 
 php_stream *qqstream = php_stream_open_wrapper(search_url, "r", REPORT_ERRORS, NULL);
 if(qqstream){
     char json_buffer[4096];
     json_buffer[0] = '\0';
     while(!php_stream_eof(qqstream)){
         char buff[1024];
         if(php_stream_gets(qqstream, buff, sizeof(buff))){
             strcat(json_buffer, buff);
         }
     }
     if(strlen(json_buffer)>0){
         char *song_id;
        //返回格式为JSON,用笨方法来读取吧,offset是指读取Songid在歌曲列表中偏移
         get_songid(json_buffer, &song_id, offset);
            if(strlen(song_id)>0){
                char *song_cid = estrndup(song_id+strlen(song_id)-2, 2);
               //获得了songid,组织lrc歌词的URL
                char xml_url[150];
                sprintf(xml_url, "http://music.qq.com/miniportal/static/lyric/%d/%s.xml", atoi(song_cid), song_id);
                php_stream *xml_stream = php_stream_open_wrapper(xml_url, "r", REPORT_ERRORS, NULL);
                if(xml_stream){
                    char xml_buff[5120];
                    xml_buff[0] = '\0';
                    while(!php_stream_eof(xml_stream)){
                        char buff[1024];
                        if(php_stream_gets(xml_stream, buff, sizeof(buff))){
                            strcat(xml_buff, buff);
                        }
                    }
                    php_stream_close(xml_stream);
                    if(strlen(xml_buff)>0){
                        char *lrc;
                        //读出XML中的LRC数据,还是用笨方法
                        get_lrc(xml_buff, &lrc);
                        //函数返回值
                        RETURN_STRING(lrc, 1);                   
                    }
                    RETURN_FALSE;
                }
                RETURN_FALSE;
            }
            RETURN_FALSE;
     }   
     php_stream_close(qqstream);
     RETURN_FALSE;
 }
 RETURN_FALSE; 
}

附上测试地址:QQ Music LRC Demo
最后附上源码打包(Linux+PHP5.1 Above):qqlrc.tar.gz