PHP备忘

By 淡水河边, 2010-02-04 20:33

1,stdClass
他是php内置的一个类,提供给我们直接实例化使用。

$obj = new stdClass();
$obj->prop = 'hello world';
echo $obj->prop;

我们可以看看他的内部结构

Reflection::export(new ReflectionClass('stdClass'));
/* 输出结果
Class [ <internal> class stdClass ] {
  - Constants [0] {
  }
  - Static properties [0] {
  }
  - Static methods [0] {
  }
  - Properties [0] {
  }
  - Methods [0] {
  }
}
</internal>
*/

2,php的exception和error处理
他们各自的发生:
exception可以通过php5 的try{}抛出,然后通过catch{}被捕获。
php内置函数执行时发生问题,是通过trigger_error显示error。
使用异常:

<?php
// 定义未捕获异常的处理函数
function ExceptionHandler($e) {
    
echo "<strong>Exception:</strong>",$e->getMessage(),"<br />";
    
echo "Stack Trace String:".$e->getTraceAsString();
}
// 设置用户自定义异常处理函数
set_exception_handler('ExceptionHandler');
 
throw new Exception('Uncaught Exception occurred.');
echo 'Not Executed.'
?>

使用错误处理:

<?php
function ErrorHandler($errno, $errmsg, $errfile, $errline){
    
if($errno == E_USER_ERROR) {
        
$msg = "<strong>Custom Error:</strong>$errmsg<br />\n";
        
$msg .= "File:$errfile<br />\n";
        
$msg .= "Line Number:$errline<br />\n";
    
}
    
echo $msg;
    
// 记录错误信息
    
error_log(date("[Y-m-d H:i:s]")." -[".$_SERVER['REQUEST_URI']."] :<br />\n".$msg."<hr />", 3, 'error_log.html');
    
//exit();
}
 
// set_error_handler()函数用于让用户自定义错误处理函数
// set_error_handler(error_function, error_type)
// error_function 必须, 制定发生错误时运行的函数
// error_type 可选, 规定不同的错误级别提示的不同信息, 默认是"E_ALL"
set_error_handler('ErrorHandler');
 
$foo = 2;
if ($foo > 1) {
    
// trigger_error()接收一个错误信息和一个常量作为参数,
    
// 常量为 E_USER_ERROR -> a fatal error
    
//       E_USER_WARNING -> a non-fatal error
    
//       E_USER_NOTICE -> a report that may not represent an error
    
trigger_error("A custom error has been trigglered", E_USER_ERROR);
}
echo 'Go on...';

不同之处,处理异常后,脚本不再执行;但是error有可能会继续执行。
整理一下,可以放到tinymvc里做script plugin。

<?php
// 定义未捕获异常的处理函数
function ExceptionHandler($e) {
    
echo "<strong>Exception:</strong>",$e->getMessage(),"<br />\n";
    
echo "Stack Trace String:".$e->getTraceAsString();
}
// 设置用户自定义异常处理函数
set_exception_handler('ExceptionHandler');
 
function ErrorHandler($errno, $errmsg, $errfile, $errline){
    
if($errno == E_USER_ERROR) {
        
$msg = "<strong>Custom Error:</strong>$errmsg<br />\n";
        
$msg .= "File:$errfile<br />\n";
        
$msg .= "Line Number:$errline<br />\n";
    
}
    
echo $msg;
    
// 记录错误信息
    
error_log(date("[Y-m-d H:i:s]")." -[".$_SERVER['REQUEST_URI']."] :<br />\n".$msg."<hr />", 3, 'error_log.html');
    
//exit();
}
 
// set_error_handler()函数用于让用户自定义错误处理函数
// set_error_handler(error_function, error_type)
// error_function 必须, 制定发生错误时运行的函数
// error_type 可选, 规定不同的错误级别提示的不同信息, 默认是"E_ALL"
set_error_handler('ErrorHandler');
 
/*
 * DEOM
 *
 * throw new Exception('Uncaught Exception occurred.');
 *
 * $foo = 2;
 *
 * if ($foo > 1) {
 *     // trigger_error()接收一个错误信息和一个常量作为参数,
 *     // 常量为 E_USER_ERROR -> a fatal error
 *     //       E_USER_WARNING -> a non-fatal error
 *     //       E_USER_NOTICE -> a report that may not represent an error
 *     trigger_error("A custom error has been trigglered", E_USER_ERROR);
 * }
 *
 */

?>

3,include 创建配置文件
include这个语法,也可以这样用的。比如有个config.db.php

<?php defined('SYSPATH') OR die('No direct access allowed.');
return array(
    
'hostname' => 'localhost',
    
'database' => 'db',
    
'username' => 'root',
    
'password' => '123456',
);
</
code>
这个
include可以直接赋值给变量:
<
code>
$config = include 'config.db.php'; // $config现在就是这个数组
// echo $config['database'];

4,简单的判断用OR , AND

mysql_connect('locahost','root','') OR die('数据库连接失败');

之所以用 OR 可以达到,当函数错误后,执行OR后面的函数是因为:
1.逻辑运算的运算顺序是从左向右
2.OR运算中,如果运算时有值为真了,则整个表达式为真,后面不需要运算
前面执行成功就不用执行后面的语句时用OR;只有前面执行成功了,才执行后面的语句时,用AND.如:

mysql_connect('locahost','root','') AND echo '数据库连接成功';

一般需要给后面语句赋值并要保持程序运行的情况,用AND。

TinyMVC中文手册

By 淡水河边, 2010-02-03 09:04

照例,先罗嗦几句。
一直想把codeigniter的代码通读一遍,虽然codeigniter是比较轻量级的php框架,但是里面的东西还是很多的,所以一直没有实现。顺便也一直在寻找适合的代替品。其间,大致看了punny,还有很自由的lotusphp。lotusphp 这个不像是框架了,倒像是个php的几个常用功能封装起来的组件,很牛13的,好多都可以作为插件放到tinymvc里去。。。
最后还是选中了tinymvc。理由,它确实很小,但是我要的东西他基本都有了:

  • mvc模式
  • url路由
  • pdo封装
  • 自由的插件机制
  • php5 only
  • 最关键的是和codeigniter非常相似的结构和语法

于是,淡水抱恙(身体和心理都有病)花费了一天的时间,通读了一般它的代码,翻译了它的文档,也就是这个《TinyMVC中文手册》了。如果想研究一下Php的框架,可以从这个入手。没有很多的分岔干扰,比较干净。如果你有什么建议或是插件需要分享的,可以留言。
TinyMVC中文手册

CodeIgniter 和 Doctrine 从零开始 1-8章翻译打包下载

By 淡水河边, 2010-01-26 09:19

简介一下:
CodeIgniter 和 Doctrine 从零开始 是ci配合一个php的orm类库结合开发一个论坛的例子。
这一系列文章,写的不错,淡水一直在跟着翻译。本想当作新春贺礼的,但是看到有人已经开始重复劳动了,还是先放出下载吧。
暂时只有八章,第九章还在翻译中,原作者写到了第十章了。
原作者地址:

http://www.phpandstuff.com/

CodeIgniter 和 Doctrine 从零开始 1-8

基于PHP的cURL快速入门[译][转]

By 淡水河边, 2010-01-19 15:41

本来想要翻译的,不想在蓝色上已经有人译好了。直接yy然后p吧(linux下vi的复制粘贴指令,最近捣鼓linux比较多些)。
原文地址:http://net.tutsplus.com/tutorials/php/techniques-and-resources-for-mastering-curl/
译文地址:http://bbs.blueidea.com/viewthread.php?tid=2966700&extra=page%3D1%26amp%3Bfilter%3Dtype%26amp%3Btypeid%3D20

cURL 是一个利用URL语法规定来传输文件和数据的工具,支持很多协议,如HTTP、FTP、TELNET等。最爽的是,PHP也支持 cURL 库。本文将介绍 cURL 的一些高级特性,以及在PHP中如何运用它。

为什么要用 cURL?

是的,我们可以通过其他办法获取网页内容。大多数时候,我因为想偷懒,都直接用简单的PHP函数:

$content = file_get_contents("http://www.nettuts.com");
// or
$lines = file("http://www.nettuts.com");
// or
readfile(http://www.nettuts.com);
?>

不过,这种做法缺乏灵活性和有效的错误处理。而且,你也不能用它完成一些高难度任务——比如处理coockies、验证、表单提交、文件上传等等。

cURL 是一种功能强大的库,支持很多不同的协议、选项,能提供 URL 请求相关的各种细节信息。

基本结构

在学习更为复杂的功能之前,先来看一下在PHP中建立cURL请求的基本步骤:

  • 初始化
  • 设置变量
  • 执行并获取结果
  • 释放cURL句柄
// 1. 初始化
$ch = curl_init();
// 2. 设置选项,包括URL
curl_setopt($ch, CURLOPT_URL, "http://www.nettuts.com");
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_HEADER, 0);
// 3. 执行并获取HTML文档内容
$output = curl_exec($ch);
// 4. 释放curl句柄
curl_close($ch);

第二步(也就是 curl_setopt() )最为重要,一切玄妙均在此。有一长串cURL参数可供设置,它们能指定URL请求的各个细节。要一次性全部看完并理解可能比较困难,所以今天我们只试一下那些更常用也更有用的选项。

检查错误

你可以加一段检查错误的语句(虽然这并不是必需的):

// ...
$output = curl_exec($ch);
if ($output === FALSE) {
    
echo "cURL Error: " . curl_error($ch);
}
// ...

请注意,比较的时候我们用的是“=== FALSE”,而非“== FALSE”。因为我们得区分 空输出 和 布尔值FALSE,后者才是真正的错误。

获取信息

这是另一个可选的设置项,能够在cURL执行后获取这一请求的有关信息:

// ...
curl_exec($ch);
$info = curl_getinfo($ch);
echo '获取'. $info['url'] . '耗时'. $info['total_time'] . '';
// ...

返回的数组中包括了以下信息:
“url” //资源网络地址
“content_type” //内容编码
“http_code” //HTTP状态码
“header_size” //header的大小
“request_size” //请求的大小
“filetime” //文件创建时间
“ssl_verify_result” //SSL验证结果
“redirect_count” //跳转技术
“total_time” //总耗时
“namelookup_time” //DNS查询耗时
“connect_time” //等待连接耗时
“pretransfer_time” //传输前准备耗时
“size_upload” //上传数据的大小
“size_download” //下载数据的大小
“speed_download” //下载速度
“speed_upload” //上传速度
“download_content_length”//下载内容的长度
“upload_content_length” //上传内容的长度
“starttransfer_time” //开始传输的时间
“redirect_time”//重定向耗时

基于浏览器的重定向

在第一个例子中,我们将提供一段用于侦测服务器是否有基于浏览器的重定向的代码。例如,有些网站会根据是否是手机浏览器甚至用户来自哪个国家来重定向网页。

我们利用 CURLOPT_HTTPHEADER 选项来设定我们发送出的HTTP请求头信息(http headers),包括user agent信息和默认语言。然后我们来看看这些特定网站是否会把我们重定向到不同的URL。

// 测试用的URL
$urls = array(
    
"http://www.cnn.com",
    
"http://www.mozilla.com",
    
"http://www.facebook.com"
);
// 测试用的浏览器信息
$browsers = array(
    
"standard" => array (
        
"user_agent" => "Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US; rv:1.9.1.6) Gecko/20091201 Firefox/3.5.6 (.NET CLR 3.5.30729)",
        
"language" => "en-us,en;q=0.5"
        
),
    
"iphone" => array (
        
"user_agent" => "Mozilla/5.0 (iPhone; U; CPU like Mac OS X; en) AppleWebKit/420+ (KHTML, like Gecko) Version/3.0 Mobile/1A537a Safari/419.3",
        
"language" => "en"
        
),
    
"french" => array (
        
"user_agent" => "Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1; GTB6; .NET CLR 2.0.50727)",
        
"language" => "fr,fr-FR;q=0.5"
        
)
);
foreach ($urls as $url) {
    
echo "URL: $url\n";
    
foreach ($browsers as $test_name => $browser) {
        
$ch = curl_init();
        
// 设置 url
        
curl_setopt($ch, CURLOPT_URL, $url);
        
// 设置浏览器的特定header
        
curl_setopt($ch, CURLOPT_HTTPHEADER, array(
                
"User-Agent: {$browser['user_agent']}",
                
"Accept-Language: {$browser['language']}"
            
));
        
// 页面内容我们并不需要
        
curl_setopt($ch, CURLOPT_NOBODY, 1);
        
// 只需返回HTTP header
        
curl_setopt($ch, CURLOPT_HEADER, 1);
        
// 返回结果,而不是输出它
        
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
        
$output = curl_exec($ch);
        
curl_close($ch);
        
// 有重定向的HTTP头信息吗?
        
if (preg_match("!Location: (.*)!", $output, $matches)) {
            
echo "$test_name: redirects to $matches[1]\n";
        
} else {
            
echo "$test_name: no redirection\n";
        
}
    
}
    
echo "\n\n";
}

首先,我们建立一组需要测试的URL,接着指定一组需要测试的浏览器信息。最后通过循环测试各种URL和浏览器匹配可能产生的情况。

因为我们指定了cURL选项,所以返回的输出内容则只包括HTTP头信息(被存放于 $output 中)。利用一个简单的正则,我们检查这个头信息中是否包含了“Location:”字样。

运行这段代码应该会返回如下结果:

用POST方法发送数据

当发起GET请求时,数据可以通过“查询字串”(query string)传递给一个URL。例如,在google中搜索时,搜索关键即为URL的查询字串的一部分:

http://www.google.com/search?q=nettuts

这种情况下你可能并不需要cURL来模拟。把这个URL丢给“file_get_contents()”就能得到相同结果。

不过有一些HTML表单是用POST方法提交的。这种表单提交时,数据是通过 HTTP请求体(request body) 发送,而不是查询字串。例如,当使用CodeIgniter论坛的表单,无论你输入什么关键字,总是被POST到如下页面:

http://codeigniter.com/forums/do_search/

你可以用PHP脚本来模拟这种URL请求。首先,新建一个可以接受并显示POST数据的文件,我们给它命名为post_output.php:

print_r($_POST);

接下来,写一段PHP脚本来执行cURL请求:

$url = "http://localhost/post_output.php";
$post_data = array (
    
"foo" => "bar",
    
"query" => "Nettuts",
    
"action" => "Submit"
);
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
// 我们在POST数据哦!
curl_setopt($ch, CURLOPT_POST, 1);
// 把post的变量加上
curl_setopt($ch, CURLOPT_POSTFIELDS, $post_data);
$output = curl_exec($ch);
curl_close($ch);
echo $output;

执行代码后应该会得到以下结果:
Array
(
[foo]=>bar
[query]=>Nettuts
[action]=>Submit
)
这段脚本发送一个POST请求给 post_output.php ,这个页面 $_POST 变量并返回,我们利用cURL捕捉了这个输出。

文件上传

上传文件和前面的POST十分相似。因为所有的文件上传表单都是通过POST方法提交的。

首先新建一个接收文件的页面,命名为 upload_output.php:

print_r($_FILES);

以下是真正执行文件上传任务的脚本:

$url = "http://localhost/upload_output.php";
$post_data = array (
    
"foo" => "bar",
    
// 要上传的本地文件地址
    
"upload" => "@C:/wamp/www/test.zip"
);
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_POSTFIELDS, $post_data);
$output = curl_exec($ch);
curl_close($ch);
echo $output;

如果你需要上传一个文件,只需要把文件路径像一个post变量一样传过去,不过记得在前面加上@符号。执行这段脚本应该会得到如下输出:
Array
(
[upload]=> Array
(
[name] => test.zip
[type] =>application/octe-stream
[tmp_name] =>c:\wamp\tmp\php4CCB.tmp
[error] =>0
[size] =>1183642
)
)

cURL批处理(multi cURL)

cURL还有一个高级特性——批处理句柄(handle)。这一特性允许你同时或异步地打开多个URL连接。

下面是来自来自php.net的示例代码:

// 创建两个cURL资源
$ch1 = curl_init();
$ch2 = curl_init();
// 指定URL和适当的参数
curl_setopt($ch1, CURLOPT_URL, "http://lxr.php.net/");
curl_setopt($ch1, CURLOPT_HEADER, 0);
curl_setopt($ch2, CURLOPT_URL, "http://www.php.net/");
curl_setopt($ch2, CURLOPT_HEADER, 0);
// 创建cURL批处理句柄
$mh = curl_multi_init();
// 加上前面两个资源句柄
curl_multi_add_handle($mh,$ch1);
curl_multi_add_handle($mh,$ch2);
// 预定义一个状态变量
$active = null;
// 执行批处理
do {
    
$mrc = curl_multi_exec($mh, $active);
} while ($mrc == CURLM_CALL_MULTI_PERFORM);
while ($active && $mrc == CURLM_OK) {
    
if (curl_multi_select($mh) != -1) {
        
do {
            
$mrc = curl_multi_exec($mh, $active);
        
} while ($mrc == CURLM_CALL_MULTI_PERFORM);
    
}
}
// 关闭各个句柄
curl_multi_remove_handle($mh, $ch1);
curl_multi_remove_handle($mh, $ch2);
curl_multi_close($mh);

这里要做的就是打开多个cURL句柄并指派给一个批处理句柄。然后你就只需在一个while循环里等它执行完毕。

这个示例中有两个主要循环。第一个 do-while 循环重复调用 curl_multi_exec() 。这个函数是无隔断(non-blocking)的,但会尽可能少地执行。它返回一个状态值,只要这个值等于常量 CURLM_CALL_MULTI_PERFORM ,就代表还有一些刻不容缓的工作要做(例如,把对应URL的http头信息发送出去)。也就是说,我们需要不断调用该函数,直到返回值发生改变。

而接下来的 while 循环,只在 $active 变量为 true 时继续。这一变量之前作为第二个参数传给了 curl_multi_exec() ,代表只要批处理句柄中是否还有活动连接。接着,我们调用 curl_multi_select() ,在活动连接(例如接受服务器响应)出现之前,它都是被“屏蔽”的。这个函数成功执行后,我们又会进入另一个 do-while 循环,继续下一条URL。

还是来看一看怎么把这一功能用到实处吧:

WordPress 连接检查器

想象一下你有一个文章数目庞大的博客,这些文章中包含了大量外部网站链接。一段时间之后,因为这样那样的原因,这些链接中相当数量都失效了。要么是被和谐了,要么是整个站点都被功夫网了…

我们下面建立一个脚本,分析所有这些链接,找出打不开或者404的网站/网页,并生成一个报告。

请注意,以下并不是一个真正可用的WordPress插件,仅仅是一段独立功能的脚本而已,仅供演示,谢谢。

好,开始吧。首先,从数据库中读取所有这些链接:

// CONFIG
$db_host = 'localhost';
$db_user = 'root';
$db_pass = '';
$db_name = 'wordpress';
$excluded_domains = array(
    
'localhost', 'www.mydomain.com');
$max_connections = 10;
// 初始化一些变量
$url_list = array();
$working_urls = array();
$dead_urls = array();
$not_found_urls = array();
$active = null;
// 连到 MySQL
if (!mysql_connect($db_host, $db_user, $db_pass)) {
    
die('Could not connect: ' . mysql_error());
}
if (!mysql_select_db($db_name)) {
    
die('Could not select db: ' . mysql_error());
}
// 找出所有含有链接的文章
$q = "SELECT post_content FROM wp_posts
    WHERE post_content LIKE '%href=%'
    AND post_status = 'publish'
    AND post_type = 'post'
";
$r = mysql_query($q) or die(mysql_error());
while ($d = mysql_fetch_assoc($r)) {
    
// 用正则匹配链接
    
if (preg_match_all("!href=\"(.*?)\"!", $d['post_content'], $matches)) {
        
foreach ($matches[1] as $url) {
            
// exclude some domains
            
$tmp = parse_url($url);
            
if (in_array($tmp['host'], $excluded_domains)) {
                
continue;
            
}
            
// store the url
            
$url_list []= $url;
        
}
    
}
}
// 移除重复链接
$url_list = array_values(array_unique($url_list));
if (!$url_list) {
    
die('No URL to check');
}

我们首先配置好数据库,一系列要排除的域名($excluded_domains),以及最大并发连接数($max_connections)。然后,连接数据库,获取文章和包含的链接,把它们收集到一个数组中($url_list)。

下面的代码有点复杂了,因此我将一小步一小步地详细解释:

// 1. 批处理器
$mh = curl_multi_init();
// 2. 加入需批量处理的URL
for ($i = 0; $i < $max_connections; $i++) {
    
add_url_to_multi_handle($mh, $url_list);
}
// 3. 初始处理
do {
    
$mrc = curl_multi_exec($mh, $active);
} while ($mrc == CURLM_CALL_MULTI_PERFORM);
// 4. 主循环
while ($active && $mrc == CURLM_OK) {
    
// 5. 有活动连接
    
if (curl_multi_select($mh) != -1) {
        
// 6. 干活
        
do {
            
$mrc = curl_multi_exec($mh, $active);
        
} while ($mrc == CURLM_CALL_MULTI_PERFORM);
        
// 7. 有信息否?
        
if ($mhinfo = curl_multi_info_read($mh)) {
            
// 意味着该连接正常结束
            
// 8. 从curl句柄获取信息
            
$chinfo = curl_getinfo($mhinfo['handle']);
            
// 9. 死链么?
            
if (!$chinfo['http_code']) {
                
$dead_urls []= $chinfo['url'];
            
// 10. 404了?
            
} else if ($chinfo['http_code'] == 404) {
                
$not_found_urls []= $chinfo['url'];
            
// 11. 还能用
            
} else {
                
$working_urls []= $chinfo['url'];
            
}
            
// 12. 移除句柄
            
curl_multi_remove_handle($mh, $mhinfo['handle']);
            
curl_close($mhinfo['handle']);
            
// 13. 加入新URL,干活
            
if (add_url_to_multi_handle($mh, $url_list)) {
                
do {
                    
$mrc = curl_multi_exec($mh, $active);
                
} while ($mrc == CURLM_CALL_MULTI_PERFORM);
            
}
        
}
    
}
}
// 14. 完了
curl_multi_close($mh);
echo "==Dead URLs==\n";
echo implode("\n",$dead_urls) . "\n\n";
echo "==404 URLs==\n";
echo implode("\n",$not_found_urls) . "\n\n";
echo "==Working URLs==\n";
echo implode("\n",$working_urls);
// 15. 向批处理器添加url
function add_url_to_multi_handle($mh, $url_list) {
    
static $index = 0;
    
// 如果还剩url没用
    
if ($url_list[$index]) {
        
// 新建curl句柄
        
$ch = curl_init();
        
// 配置url
        
curl_setopt($ch, CURLOPT_URL, $url_list[$index]);
        
// 不想输出返回的内容
        
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
        
// 重定向到哪儿我们就去哪儿
        
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 1);
        
// 不需要内容体,能够节约带宽和时间
        
curl_setopt($ch, CURLOPT_NOBODY, 1);
        
// 加入到批处理器中
        
curl_multi_add_handle($mh, $ch);
        
// 拨一下计数器,下次调用该函数就能添加下一个url了
        
$index++;
        
return true;
    
} else {
        
// 没有新的URL需要处理了
        
return false;
    
}
}

下面解释一下以上代码。列表的序号对应着代码注释中的顺序数字。

新建一个批处理器。Created a multi handle.

稍后我们将创建一个把URL加入批处理器的函数 add_url_to_multi_handle() 。每当这个函数被调用,就有一个新url被加入批处理器。一开始,我们给批处理器添加了10个URL(这一数字由 $max_connections 所决定)。

运行 curl_multi_exec() 进行初始化工作是必须的,只要它返回 CURLM_CALL_MULTI_PERFORM 就还有事情要做。这么做主要是为了创建连接,它不会等待完整的URL响应。

只要批处理中还有活动连接主循环就会一直持续。

curl_multi_select() 会一直等待,直到某个URL查询产生活动连接。

cURL的活儿又来了,主要是获取响应数据。

检查各种信息。当一个URL请求完成时,会返回一个数组。

在返回的数组中有一个 cURL 句柄。我们利用其获取单个cURL请求的相应信息。

如果这是一个死链或者请求超时,不会返回http状态码。

如果这个页面找不到了,会返回404状态码。

其他情况我们都认为这个链接是可用的(当然,你也可以再检查一下500错误之类…)。

从该批次移除这个cURL句柄,因为它已经没有利用价值了,关了它!

很好,现在可以另外加一个URL进来了。再一次地,初始化工作又开始进行…

嗯,该干的都干了。关闭批处理器,生成报告。

回过头来看给批处理器添加新URL的函数。这个函数每调用一次,静态变量 $index 就递增一次,这样我们才能知道还剩多少URL没处理。

我把这个脚本在我的博客上跑了一遍(测试需要,有一些错误链接是故意加上的),结果如下:

共检查约40个URL,只耗费两秒不到。当需要检查更加大量的URL时,其省心省力的效果可想而知!如果你同时打开10个连接,还能再快上10倍!另外,你还可以利用cURL批处理的无隔断特性来处理大量URL请求,而不会阻塞你的Web脚本。

另一些有用的cURL 选项

HTTP 认证

如果某个URL请求需要基于 HTTP 的身份验证,你可以使用下面的代码:

$url = "http://www.somesite.com/members/";
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
// 发送用户名和密码
curl_setopt($ch, CURLOPT_USERPWD, "myusername:mypassword");
// 你可以允许其重定向
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 1);
// 下面的选项让 cURL 在重定向后
// 也能发送用户名和密码
curl_setopt($ch, CURLOPT_UNRESTRICTED_AUTH, 1);
$output = curl_exec($ch);
curl_close($ch);

FTP 上传

PHP 自带有 FTP 类库, 但你也能用 cURL:

// 开一个文件指针
$file = fopen("/path/to/file", "r");
// url里包含了大部分所需信息
$url = "ftp://username:password@mydomain.com:21/path/to/new/file";
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
// 上传相关的选项
curl_setopt($ch, CURLOPT_UPLOAD, 1);
curl_setopt($ch, CURLOPT_INFILE, $fp);
curl_setopt($ch, CURLOPT_INFILESIZE, filesize("/path/to/file"));
// 是否开启ASCII模式 (上传文本文件时有用)
curl_setopt($ch, CURLOPT_FTPASCII, 1);
$output = curl_exec($ch);
curl_close($ch);

翻墙术

你可以用代理发起cURL请求:

$ch = curl_init();
curl_setopt($ch, CURLOPT_URL,'http://www.example.com');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
// 指定代理地址
curl_setopt($ch, CURLOPT_PROXY, '11.11.11.11:8080');
// 如果需要的话,提供用户名和密码
curl_setopt($ch, CURLOPT_PROXYUSERPWD,'user:pass');
$output = curl_exec($ch);
curl_close ($ch);

回调函数

可以在一个URL请求过程中,让cURL调用某指定的回调函数。例如,在内容或者响应下载的过程中立刻开始利用数据,而不用等到完全下载完。

$ch = curl_init();
curl_setopt($ch, CURLOPT_URL,'http://net.tutsplus.com');
curl_setopt($ch, CURLOPT_WRITEFUNCTION,"progress_function");
curl_exec($ch);
curl_close ($ch);
function progress_function($ch,$str) {
    
echo $str;
    
return strlen($str);
}

这个回调函数必须返回字串的长度,不然此功能将无法正常使用。

在URL响应接收的过程中,只要收到一个数据包,这个函数就会被调用。

小结

今天我们一起学习了cURL库的强大功能和灵活的扩展性。希望你喜欢。下一次要发起URL请求时,考虑下cURL吧!

谢谢!

mysql数据库的备份和恢复

By 淡水河边, 2010-01-12 14:20

利用了mysql自带的工具,效率高,也不怕文件过大。
先说备份
mysqldump -u数据库用户名 -p密码 dbname > 备份路径/导出名.sql
就是把dbname数据库,导出到 备份路径/导出名.sql

恢复
mysql -u数据库用户名 -p密码 dbname < 备份路径/数据库名.sql

mysql命令说完了,下面该shell了,用shell来实现mysql的自动备份。

建立shell
mysqlback.sh 内容如下:
#!/bin/bash
X=`date +%Y%m%d` ;获取当天时间,命名用
M=/usr/local/mysql/bin ;mysql程序的路径
B= /usr/back/mysql ;mysql备份的路径

$M/mysqldump -uroot -proot test > $B/$X.sql
tar -zcvf $B/$X.tar.gz $B/$X.sql
rm -rf $B/$X.sql

tar 打包压缩后,rm 删除原sql文件
然后添加到计划任务,每天3点05分自动执行:
#echo "05 3 * * * root /usr/back/shell/mysqlback.sh &>/dev/null" >>/etc/crontab

vi/vim 中文乱码

By 淡水河边, 2010-01-12 10:43

linux下,用vi、vim编辑文件时,可能会碰到中文乱码。
由于在windows下默认是gb编码,而vim默认是utf-8(gedit默认也是utf-8),所以打开会成乱码。修改了一下配置文件,使vi、vim支持gb编码就好了。
$vi ~/.vimrc

let &termencoding=&encoding
set fileencodings=utf-8,gbk

$:wq
再次打开vi、vim,中文显示就正常了。

淡水的2009

By 淡水河边, 2010-01-06 09:49

终于肯花一点点时间,做个小小的回望了。
淡水2009年过得波澜不惊。年初结婚了,随后换了份工作,然后杭州出差3个月,然后买了房子成为房奴一族。再然后2009就过去了。想换个笔记本没有实现,只是在网上过过眼瘾;想把kohana梳理一遍没有实现,只是用它重写了一下以前用codeigniter做过的企业站;想好好折腾一下linux没能坚持,只是在虚拟机上装了几次又遗忘了;还想……
robin去做手机站了,所以dophp没了;pat失踪了,所以bsdcn也没了。还好hex的codeigniter.org.cn还在,还好icyleaf的kohana.cn还在……
2010到了,淡水的2009过了,大家继续努力吧,淡水说完了。

mysql的几个函数

By 淡水河边, 2009-10-15 10:45

缘由是数据库里的fax是由“区号+空格+号码”组成的,但是现在需要去掉空格。下图:update fax
先说简单点的方法:

UPDATE customer_copy set fax=REPLACE(fax,' ','')   where fax REGEXP '^[0-9]+[[:space:]][0-9]+';

细说一下:
REPLACE(fax,’ ‘,”),是替换空格
REGEXP ,是mysql里的正则
‘^[0-9]+[[:space:]][0-9]+’,是匹配 以至少有一个数字开头,后面有个空格,后面再跟着至少一个数字的记录。
再来一个另类的:

UPDATE customer_copy set fax= concat(substring_index(fax,' ',1), substring_index(fax,' ',-1))  where fax REGEXP '^[0-9]+[[:space:]][0-9]+';

这里用到了两个函数:concat(),substring_index()
concat(p1,p2,p3) 是拼接函数。把他的所有参数连接起来,结果就是p1p2p3
substring_index(str,delim,count) 返回字符串str中,第count个分隔符delim之前的子串.
SUBSTRING_INDEX(‘www.mysql.com’, ‘.’, 2); 返回第2个.之前的字串,也就是www.mysql
SUBSTRING_INDEX(‘www.mysql.com’, ‘.’, -2); 返回mysql.com
解释一下,如果count是负数,就从右边开始计数和截取。
substring_index(fax,’ ‘,1), 返回区号部分,substring_index(fax,’ ‘,-1), 返回空格后的号码,再用concat一组合,也就是去掉空格后的号码了。

PHP数据记录批量更新代码

By 淡水河边, 2009-09-16 18:00

需要用到,简单是思路,记录一下。不过用到的应该不多。。。
一般会循环列出表记录到表单里

<?php
$que=mysql_query("select * from test order by id ");         
while($rs1=mysql_fetch_array($que))         
{
?>         
<input  type="text" value="
<?php echo $rs1['title'] ?>" name="title[]" size="2">
<input  type="hidden" value="
<?php echo $rs1['id'] ?>" name="id[]" size="2">
<?php
}
?>

处理程序,搞个循环

$id=$_POST['id'];
$title=$_POST['title'];
if($num=count($id))
{
    
for($i=0;$i<$num;$i++)     
  
{   
      
$q=mysql_query("update test set title='".$title[$i]."' where id='".$id[$i]."'");
  
}
}

搞定,但是不知效率如何。明天测试效果。。。

windows7下面搭建 Xampplite+Eclipse PDT+XDebug的PHP开发环境

By 淡水河边, 2009-09-12 16:36

淡水是用xampplite1.7.1,它的php版本是5.2.9。最新版的xampp搭载的是php5.3,淡水的程序跑起来好像有些问题-_-!!

1,下载PDT(PHP Development Tools),地址:http://www.eclipse.org/pdt/downloads/
我下的版本是PDT 2.1 All In Ones,解压后如果不能运行,请安装JRE安装,因为Eclipse需要JRE才能运行。地址 :http://www.java.com/zh_CN/download/manual.jsp

2,下载XAMPPlite1.7.1这个集成的PHP+MySql运行环境,如果是EXE安装包,就双击安装,如果是ZIP包,就解压运行。地址:http://www.apachefriends.org/en/xampp-windows.html

3,下载XDebug,我下载的是php_xdebug-2.0.4-5.2.8.dll,用这个替换xampplite1.7.1自带的php_xdebug.dll,自带的无法正常调试。地址:http://xdebug.org/download.php

4,编辑php.ini
添加如下到php.ini
[XDebug]
;; Only Zend OR (!) XDebug
zend_extension_ts=”\xampplite\php\ext\php_xdebug.dll”
xdebug.remote_enable=true
xdebug.remote_host=127.0.0.1
xdebug.remote_port=9000
xdebug.remote_handler=dbgp
xdebug.profiler_enable=on
xdebug.profiler_output_dir=”\xampplite\tmp”

原来php.ini里有;extension=php_xdebug.dll,这里无需去掉注释。因为php5.2.9使用zend_extension_ts来挂载xdebug(php5.3开始用zend_extension挂载,又不一样了)

5,配置Eclipse PDT,进入window->preferences
展开PHP,配置其中的PHP Executables,如图
配置PHP Executables
配置Debug,如图
配置Debug
这样就搞定了,可以不用盗版的zend studio for Eclipse鸟。。。最后,说windows7下搭建。。其实只是个噱头;)

Themocracy WordPress Themes