PHP扩展入门之吸取QQ歌词

森森 2009-09-29 140 views

书接上篇博文讲的《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

Tags: , , , , / Posted in PHP应用, PHP扩展
欢迎订阅: Google Reader | 鲜果 | 抓虾 | 九点 | QQ邮箱 | 有道 | 更多

评论暂缺

  • (Required)
  • (Required, will not be published)

友情链接

Design By CKSKY TEAM VERSION 3.0 他说博客不用备案... © Copyright 2010 All Rights Reserved