标签 cURL 下的文章

libcurl sample program

#define CURL_STATICLIB
#define _CRT_SECURE_NO_WARNINGS
#define _CRT_SECURE_NO_DEPRECATE 
#pragma comment(lib,"ws2_32.lib")
#pragma comment(lib,"D:\\win32dev\\curl-7.19.0\\lib\\Debug\\curllib.lib")
/* Start of test program */
#include <stdio.h>
#include <stdlib.h> 

#include <curl/curl.h>
#include <curl/types.h>
#include <curl/easy.h>

size_t write_data(void *ptr, size_t size, size_t nmemb, FILE *stream)
{
    static int first_time=1;
    char outfilename[FILENAME_MAX] = "body.html";
    static FILE *outfile;
    size_t written;
    if (first_time) {
        first_time = 0;
        outfile = fopen(outfilename,"w+");
        if (outfile == NULL) {
            return -1;
        }
        fprintf(stderr,"The body is <%s>\n",outfilename);
    }
    written = fwrite(ptr,size,nmemb,outfile);
    return written;
}

int main(int argc, char **argv)
{
    CURL *curl_handle;
    char headerfilename[FILENAME_MAX] = "head.html";
    FILE *headerfile;
    int rc=0;
    curl_handle = curl_easy_init();
    curl_easy_setopt(curl_handle,   CURLOPT_URL, "http://www.sina.com.cn");
    curl_easy_setopt(curl_handle,   CURLOPT_NOPROGRESS  ,1); 
    curl_easy_setopt(curl_handle,   CURLOPT_WRITEFUNCTION,&write_data);
    headerfile = fopen(headerfilename,"w");
    if (headerfile == NULL) {
        curl_easy_cleanup(curl_handle);
        return -1;
    }
    curl_easy_setopt(curl_handle,   CURLOPT_WRITEHEADER ,headerfile);
    curl_easy_perform(curl_handle);
    printf("The head is <%s>\n",headerfilename);
    fclose(headerfile);
    curl_easy_cleanup(curl_handle);
    return 0;
}
/* End of test program */

将获取的html文件内容保存在body.html。保存的方法是curl_easy_setopt函数中设置CURLOPT_WRITEFUNCTION的回调函数为write_data。

在write_data这个回调函数中需要注意的是,curl碰到web文件过大的情况会分段获取内容

size_t write_data(void *ptr, size_t size, size_t nmemb, FILE *stream)

参数ptr是指向分段下载内容的指针。size是内容大小,mmemb指定单位一般是1(Byte)。stream就是CURLOPT_WRITEDATA指定的指针。如果要讲所有html内容保存在buffer中,可以strcat(stream,ptr);就可以了。

libcurl 无法解析的外部符号

仔细检查以下几点,防止“无法解析的外部符号”链接问题的出现。

  • 确保curllib项目的运行时库和引用curllib.lib程序的运行时库(c/c++ ->code generation)保持一致(比如都是/MDd)。

  • 确保curllib项目和引用curllib.lib项目的程序的字符集保持一致(比如都是:使用多字节字符集)。

  • 确保curllib项目在没有LDAP支持的情况下在preprocessor definition中加入:CURL_DISABLE_LDAP(/D)。

  • 编译curllib静态库时,请在preprocessor definition中加入:CURL_STATICLIB

VC编译curl 7.38.0

用nmake编译curl 7.38.0静态库

开始里面运行“Visual Studio x64 兼容工具命令提示(2010)”,出现的cmd里面输入如下命令

D:\dev\curl\winbuild>nmake /f Makefile.vc VC=10  mode=static

Microsoft (R) 程序维护实用工具 8.00.50727.762 版
版权所有 (C) Microsoft Corporation。保留所有权利。

Invalid mode:
Usage: nmake /f Makefile.vc mode=<static or dll> <options>
where <options> is one or many of:
VC=<6,7,8,9,10,11,12> - VC versions
WITH_DEVEL=<path> - Paths for the development files (SSL, zlib, etc.)
Defaults to sibbling directory deps: ../deps
Libraries can be fetched at http://pecl2.php.net/downloads/php-windows-builds/
Uncompress them into the deps folder.
WITH_SSL=<dll or static> - Enable OpenSSL support, DLL or static
WITH_ZLIB=<dll or static> - Enable zlib support, DLL or static
WITH_SSH2=<dll or static> - Enable libSSH2 support, DLL or static
ENABLE_IDN=<yes or no> - Enable use of Windows IDN APIs, defaults to yes
Requires Windows Vista or later, or installation from:
http://www.microsoft.com/downloads/details.aspx?FamilyID=AD6158D7-DDBA-416A-9109-07607425A815
ENABLE_IPV6=<yes or no> - Enable IPv6, defaults to yes
ENABLE_SSPI=<yes or no> - Enable SSPI support, defaults to yes
ENABLE_WINSSL=<yes or no> - Enable native Windows SSL support, defaults to yes
GEN_PDB=<yes or no> - Generate Program Database (debug symbols for release build)
DEBUG=<yes or no> - Debug builds
MACHINE=<x86 or x64> - Target architecture (default x64 on AMD64, x86 on others)

生成结束后在D:\dev\curl\builds目录生成三个目录:

libcurl-vc10-x86-release-static-ipv6-sspi-winssl
libcurl-vc10-x86-release-static-ipv6-sspi-winssl-obj-lib
libcurl-vc10-x86-release-static-ipv6-sspi-winssl-obj-curl

生成的静态库文件就是:

D:\dev\curl\builds\libcurl-vc10-x86-release-static-ipv6-sspi-winssl\lib\libcurl_a.lib

curl的VC版MakeFile的参数如下

VC=<6,7,8,9,10> 指定编译器的版本,从VC 6到VC 7(2003) VC 8(2005) VC9(2008) VC 10(2010) ,以后估计可能会支持VC 11(2012)

WITH_DEVEL 指定依赖库的路径,默认是兄弟目录的deps目录

WITH_SSL 打开OpenSSL支持

WITH_ZLIB 打开ZLIB支持

WITH_SSH2 打开LibSSH2支持

ENABLE_IPV6 打开IPV6支持,默认是支持的

ENABLE_IDN 是否打开对IDN Windows API的使用,Vista极其以上版本才支持此选项

GEN_PDB 是否生成调试符号

DEBUG 是否是调试编译

MACHINE 编译指定CPU平台代码(x64, x86)

用nmake编译支持OpenSSL的curl 7.38.0动态库

PHP的cURL模块批量下载脚本

<?php
/*
Title: download resource with regular URLs
Author: tunpishuang(http://tunps.com)
Desc: 这个脚本可以下载url有规律的资源,比如数字递增,字母递增的。
并且可以定义“循环数”。
Usage: php.exe this.php fromValue1 toValue1 fromValue2 toValue2 fromValue3 toValue3 ...
this.php是这个脚本的名称
fromValue1是第一个循环的初始值
toValue1是第二个循环的初始值
fromValue2以此类推
toValue2以此类推 一直到fromValueN->toValueN
Example: php this.php http://tunps.com/uploads/*//*.jpg 001 206 001 500

Thx: jondro哥(http://stackoverflow.com/questions/2627000/how-to-write-a-function-to-output-unconstant-loop)对关键函数loop()的编写。
*/
function plus($num){
$len=strlen($num);
$num++;
while(strlen($num)<$len)
{
$num="0".$num;
}
return $num;
}
//generate loop
function loop($a) {
$from1 = array_shift($a);
$to1 = array_shift($a);
$result = array();
while ($from1 <= $to1) {
if (sizeof($a) > 0) {
$rest = loop($a);
foreach ($rest as $b) {
$result[] = $from1.'|'.$b;
}

} else {
$result[] = $from1;
}
$from1=plus($from1);
}
return $result;
}
//download resource
function download($u,$f,$e){
$ch = curl_init();
$options=array(
CURLOPT_URL=>$u,
CURLOPT_RETURNTRANSFER=>true
);
curl_setopt_array($ch,$options);
$data = curl_exec($ch);
if(curl_getinfo($ch,CURLINFO_HTTP_CODE)==200){
$fp=fopen($f.$e,"w");
echo "downloading:".$u."->".$f.$e."\n";
fwrite($fp,$data);
fclose($fp);
}
curl_close($ch);
}
//main
if($argc==1){
print_r("用法:php ".basename(__FILE__)." url from to from to ...\n");
print_r("\turl \t包含通配符*的网址\n");
print_r("\tfrom \t\turl中通配符的起始数字or字母,按顺序匹配*\n");
print_r("\tto \turl中通配符的终止数字or字母,按顺序匹配*\n");
print_r("\n");
print_r("例子:\n");
print_r("\tphp http://tunps.com/*/*.jpg 0 100 5 200 \n");
print_r("\t\t\t\t ----- -----\n");
print_r("\t\t\t\t ↓ ↓ \n");
print_r("\t\t\t\t * * \n");
}else{
if(($argc-2)%2 != 0){
echo "argument error";
exit();
}else{
$loopCount=($argc-2)/2;
while($loopCount > 0){
if($argv[($loopCount-1)*2+2] >= $argv[($loopCount-1)*2+3]){
echo "from cannot larger than to";
exit();
}
$loopCount--;
}
}
if(!preg_match("/^http:\/\/[A-Za-z0-9]+\.[A-Za-z0-9]+[\/=\?%\-&_~`@[\]\':+!]*([^\"\"])*$/",$argv[1]) || strpos($argv[1],"*") === false){
echo "url malformed or lack of char of \"*\" ";
exit();
}else{
$url=$argv[1];
$ext=substr($url,strrpos($url,'.'),strlen($url)-strrpos($url,'.'));
$fileName=1;
$originUrl=$url;
array_shift($argv);
array_shift($argv);
$rangeArr=$argv;
$numArr=loop($rangeArr);
foreach($numArr as $n){
$num=array_reverse(explode('|',$n));
$i=0;
while(strpos($url,'*') && $i<count($num)){
$lastOccur=strrpos($url,"*");
$url=substr_replace($url,$num[$i],$lastOccur,1);
$i++;
}
download($url,$fileName,$ext);
$fileName++;
$url=$originUrl;
}
}
}
exit();
?>

普通权限用户在redhat 9机子上安装带curl支持cli sapi的php

2010年4月18日(星期天)下午考试完心神不宁的《英美文学选读》的时候,我的心开始飞翔,我此刻的心灵得到了片刻的安息。

于是最近开始写一个仿迅雷批量下载功能的php脚本,可以下载循环次数不定的规则的url,这方面比迅雷的单循环要强大。

这个需要php在cli的server api下面运行,并且需要带curl扩展。

刚发现了一批有规则的url准备下载:

http://wvw.xxx.com/uploads/001/001.jpg

http://wvw.xxx.com/uploads/206/500.jpg

嵌套了2个循环。

本来打算在本机下载,但是哥在学校的寝室,上网是算流量的,这些图下完估计也得1G多,所以打算使用学校内网的linux服务器,可以联到互联网。

首先来看看服务器的配置情况:

-bash-2.05b$ uname -a
Linux ftpserver 2.4.20-8 #1 Thu Mar 13 17:54:28 EST 2003 i686 i686 i386 GNU/Linux
-bash-2.05b$ php -v
4.2.2

-bash-2.05b$ php -m
Running PHP 4.2.2
Zend Engine v1.2.0, Copyright (c) 1998-2002 Zend Technologies

[PHP Modules]

...

curl

...

...

查了一下php文档:可以知道,php cli是从4.2.0实验性的引入,并且./configure的时候需要带参数--enable-cli。并且在服务器上我运行php -i >test.html,然后查看test.html,发现:

Configure Command './configure' '--host=i386-redhat-linux' '--build=i386-redhat-linux' '--target=i386-redhat-linux-gnu' '--program-prefix=' '--prefix=/usr' '--exec-prefix=/usr' '--bindir=/usr/bin' '--sbindir=/usr/sbin' '--sysconfdir=/etc' '--datadir=/usr/share' '--includedir=/usr/include' '--libdir=/usr/lib' '--libexecdir=/usr/libexec' '--localstatedir=/var' '--sharedstatedir=/usr/com' '--mandir=/usr/share/man' '--infodir=/usr/share/info' '--cache-file=../config.cache' '--with-config-file-path=/etc' '--with-config-file-scan-dir=/etc/php.d' '--enable-force-cgi-redirect' '--disable-debug' '--enable-pic' '--disable-rpath' '--enable-inline-optimization' '--with-bz2' '--with-db3' '--with-curl' '--with-dom=/usr' '--with-exec-dir=/usr/bin' '--with-freetype-dir=/usr' '--with-png-dir=/usr' '--with-gd' '--enable-gd-native-ttf' '--with-ttf' '--with-gdbm' '--with-gettext' '--with-ncurses' '--with-gmp' '--with-iconv' '--with-jpeg-dir=/usr' '--with-openssl' '--with-png' '--with-pspell' '--with-regex=system' '--with-xml' '--with-expat-dir=/usr' '--with-zlib' '--with-layout=GNU' '--enable-bcmath' '--enable-exif' '--enable-ftp' '--enable-magic-quotes' '--enable-safe-mode' '--enable-sockets' '--enable-sysvsem' '--enable-sysvshm' '--enable-discard-path' '--enable-track-vars' '--enable-trans-sid' '--enable-yp' '--enable-wddx' '--without-oci8' '--with-pear=/usr/share/pear' '--with-imap=shared' '--with-imap-ssl' '--with-kerberos=/usr/kerberos' '--with-ldap=shared' '--with-mysql=shared,/usr' '--with-pgsql=shared' '--with-snmp=shared,/usr' '--with-snmp=shared' '--enable-ucd-snmp-hack' '--with-unixODBC=shared' '--enable-memory-limit' '--enable-bcmath' '--enable-shmop' '--enable-versioning' '--enable-calendar' '--enable-dbx' '--enable-dio' '--enable-mcal' '--enable-force-cgi-redirect'
Server API CGI

在cli下面的server api还是CGI,可以充分的肯定服务器上的php是没有cli模式的。所以我选择了自己编译一个php。

下载curl的最新源代码包:

wget http://curl.haxx.se/download/curl-7.20.1.tar.bz2
tar jxvf curl-7.20.1.tar.bz2
./configure --prefix=/home/tun/curl-7.20.1
make
make install

安装完了,看看版本:

-bash-2.05b$ /home/open/tun/curl-7.20.1/bin/curl --version
curl 7.20.1 (i686-pc-linux-gnu) libcurl/7.20.1 OpenSSL/0.9.7a zlib/1.1.4
Protocols: dict file ftp ftps http https imap imaps ldap pop3 pop3s rtsp smtp smtps telnet tftp
Features: Largefile NTLM SSL libz

下载php的最新源代码包:

wget http://cn2.php.net/distributions/php-5.3.2.tar.bz2

解压、配置、编译、安装:

-bash-2.05b$ pwd
/home/open/tun
-bash-2.05b$ tar jxvf php-5.3.2.tar.bz2
-bash-2.05b$ cd php-5.3.2
-bash-2.05b$ ./configure --prefix=./

配置加入 --prefix=./ 主要是因为我没有这台机子上面的root权限,没有办法让系统目录写文件。

结果configure包括,因为libxml版本过低,我本来打算只带cli,curl的阉割版php,所以打算将包括libxml在内的很多库都在参数中disable,将./configure改为:

./configure --prefix=./** --with-curl=/home/open/tun/curl-7.20.1** --disable-libxml --disable-dom --disable-simplexml --disable-xml --disable-xmlreader --disable-xmlwriter --without-pear --disable-cgi --disable-rpath --disable-ipv6 --disable-ctype --disable-fileinfo --disable-filter --disable-hash --disable-json --disable-mbregex --disable-mbregex-backtrack --disable-pdo --disable-phar --disable-session --disable-tokenizer
make
make install

这样php就安装好了,看看版本、扩展信息:

-bash-2.05b$ /home/open/tun/php-5.3.2/bin/php -v
PHP 5.3.2 (cli) (built: Apr 19 2010 22:36:50)
Copyright (c) 1997-2010 The PHP Group
Zend Engine v2.3.0, Copyright (c) 1998-2010 Zend Technologies

-bash-2.05b$ /home/open/tun/php-5.3.2/bin/php -m
[PHP Modules]
Core
curl
date
ereg
iconv
pcre
posix
Reflection
SPL
SQLite
sqlite3
standard

[Zend Modules]

再来看看phpinfo() :

curl

cURL support => enabled
cURL Information => 7.20.1

然后再找一个包含$argc,$argv的脚本来测试一下,都是可以的。

看看php权限,普通用户权限:

-bash-2.05b$ ls -la /home/open/tun/php-5.3.2/bin/php
-rwxr-xr-x    1 open     open     11440897 Apr 20 01:10 /home/open/tun/php-5.3.2/bin/php