基于curl封装一个爬虫

<?php  
if ( ! defined('BASEPATH')) exit('No direct script access allowed');
/**
 * CodeIgniter
 *
 * An open source application development framework for PHP 5.1.6 or newer
 *
 * @package		CodeIgniter
 * @author		ExpressionEngine Dev Team
 * @copyright	Copyright (c) 2008 - 2011, EllisLab, Inc.
 * @license		http://codeigniter.com/user_guide/license.html
 * @link		http://codeigniter.com
 * @since		Version 1.0
 * @filesource
 */

// ------------------------------------------------------------------------

class Crawler {
	private $_url;
	private $_handle;
	//多线程处理时一些变量
	private $_batch_config = array(
											'handle_array' => array(),
											'map_array' => array()
									);
	private $_curl_option;
	private $_single_or_multi = TRUE; //TRUE表示是单个curl句柄,FALSE表示一组批处理curl句柄(多线程操作)

	function __construct() {
		$this->_curl_option = array(
				CURLOPT_TIMEOUT => 60,
				CURLOPT_FOLLOWLOCATION => TRUE,
				CURLOPT_RETURNTRANSFER => TRUE,
				CURLOPT_HEADER => TRUE,
				CURLOPT_NOSIGNAL => TRUE,
		);
	}

	public function deal($url) {
		$this->set_url($url);
		$this->init_handle();

		return $this->get_response();
	}

	public function set_url($url) {
		$this->_url = $url;
		$this->_single_or_multi = is_array($url) ? FALSE : TRUE;
	}

	public function set_curl_option($option) {
		$this->_curl_option = $option;
	}

	public function init_handle() {
		if(is_array($this->_url)) {
			$this->_handle = curl_multi_init();
			foreach ($this->_url as $id=>$s_url) {
				$ch = curl_init($s_url);
				$this->_batch_config['handle_array'][] = $ch;
				curl_setopt_array($ch, $this->_curl_option);

				curl_multi_add_handle($this->_handle, $ch);
				$this->_batch_config['map_array'][(string)$ch] = $id;
// 				print_r($ch);
// 				echo "\n" . (string)$ch . "\n";
			}
			print_r($this->_batch_config);
		}
		else {
			$this->_handle = curl_init($this->_url);
			curl_setopt_array($this->_handle, $this->_curl_option);
		}
	}

	public function get_response() {
		if($this->_single_or_multi) {
			$response = curl_exec($this->_handle);
			curl_close($this->_handle);

			return $response;
		}
		else {
			$responses = array();
			do
			{
				while(($code = curl_multi_exec($this->_handle , $active)) == CURLM_CALL_MULTI_PERFORM);
				if($code != CURLM_OK)
				{
					break;
				}

				// a request was just completed -- find out which one
				while($done = curl_multi_info_read($this->_handle))
				{

					// get the info and content returned on the request
					$content = curl_multi_getcontent($done['handle']);
					$responses[$this->_batch_config['map_array'][(string) $done['handle']]] = $content;//$this->parseHead($content);

					// remove the curl handle that just completed
					curl_multi_remove_handle($this->_handle , $done['handle']);
					curl_close($done['handle']);
				}

				// Block for data in / output; error handling is done by
				// curl_multi_exec
				if($active > 0)
				{
					curl_multi_select($this->_handle , 0.5);
				}
			}
			while($active);

			return $responses;
		}
	}
}

今天在CI下写一个爬虫库,此爬虫支持单url抓取和多线程批量url抓取,以及自定义正则匹配所需要的内容。

未完成

===========2013.05.06============

完成多线程部分,类代码待完善

XML相关技术探讨

xml数据经常作为一种数据格式广泛运用在web接口中。“可扩展标记语言(XML)被称为标记语言和基于文本的数据存储格式,这要看对谁来说。它是标准通用标记语言(SGML)的一个子集,采用文本方式应用和描述信息的树状结构。XML 是很多语言/格式的基础,如 Really Simple Syndication (RSS)、Mozilla 的 XML User Interface Language (XUL)、Macromedia 的 Maximum eXperience Markup Language (MXML)、Microsoft 的 eXtensible Application Markup Language (XAML) 以及开放源代码的 Java XML UI Markup Language (XAMJ)。”——IBM developworks
在php中对xml数据的处理有很多种方式,本文会梳理下xml相关知识以及对利用PHP对XML数据的几种解析方式做一个小小的总结:对XML的解析主要有树和流两种方式,各有不同的适用场景.用树的方式解析,需要将整个XML加载到内存。树型解析的例子包括DOM和SimpleXML(基于libxml2)。流解析不需要将整个文档加载到内存中。是按需加载,只能访问当前解析的节点,适用于解析大型xml文件。流解析器的例子包括XMLReader和SAX。
示例xml文件:xmltest.xml

<?xml version="1.0" encoding="UTF-8"?>
<SeachData>
	<item id="first">
		<title id="ftitle"><![CDATA[樱桃红]]></title>
		<subtitle><![CDATA[38集电视剧 在线观看]]></subtitle>
		<url><![CDATA[http://tv.2345.com/detail/18922.html]]></url>
		<tag>1</tag>
		<describ><![CDATA[主演:宋小宝 沈春阳 赵本山]]></describ>
		<type>2</type>
	</item>
	<item id="second">
		<title id="stitle"><![CDATA[贤妻]]></title>
		<subtitle><![CDATA[30集电视剧 在线观看]]></subtitle>
		<url><![CDATA[http://tv.2345.com/detail/19716.html]]></url>
		<tag>1</tag>
		<describ><![CDATA[主演:刘涛 保剑锋 谢祖武]]></describ>
		<type>2</type>
	</item>
</SeachData>

树解析:

1.DOM解析

<?php
$xml = new DOMDocument();
$xml->load('xmltest.xml');
$xml->preserveWhiteSpace = false;
$data = $xml->getElementsByTagName('item');

foreach( $data as $k=>$v )
{
	//$v是DOMElement
	echo $data->item($k)->getAttribute('id')."\n";
	//DOMNodeList 
	$titleNode = $v->getElementsByTagName('title');
	foreach ($titleNode as $k2 => $v2)
	{
		echo $v2->nodeValue. "\n";
	}
}

输出:

first
樱桃红
second
贤妻

DOM和XPATH解析

<?php
$xml = new DOMDocument;
$xml->preserveWhiteSpace = false;
$xml->load('xmltest.xml');

$xpath = new DOMXPath($xml);

// We start from the root element
$query = '//item/title';

//DOMNodeList Object
$entries = $xpath->query($query);

foreach ($entries as $k=>$v) {
	echo $v->nodeValue . "\n";
	echo "Found {$v->nextSibling->nodeValue}," . " by {$v->nodeValue}\n";
}

输出:

樱桃红
Found 38集电视剧 在线观看, by 樱桃红
贤妻
Found 30集电视剧 在线观看, by 贤妻

是不是很像js解析html,^_^

XPATH资料

 

2.SimpleXML解析

<?php
$xmlString = file_get_contents('xmltest.xml');
$xml = new SimpleXMLElement($xmlString);
echo $xml->item[0]->title;

输出:

樱桃红
38集电视剧 在线观看

在此值得一提的有三个函数:

simplexml_import_dom(将一个dom节点转化为SimpleXMLElement对象,相反功能的一个函数dom_import_simplexml)
simplexml_load_file(加载xml文件,得到SimpleXMLElement对象)
simplexml_load_string(加载格式化的xml字符串,得到SimpleXMLElement对象)

 

 

流解析
1.XMLReader解析

nodeType属性 取值 说明
1 代表标签的开始
15 代表标签的介绍
14 代表空标签体
3 代表标签体内容

<?php
$reader = new XMLReader();
$reader->open("testxml.xml");
while ($reader->read()) {
	switch ($reader->nodeType) {
		case (XMLREADER::ELEMENT):
			if ($reader->localName == 'item') {
				$domElement = $reader->expand();
				$dom = new DOMDocument();
				$domNode = $dom->importNode($domElement, TRUE);
				$simpleXml = simplexml_import_dom($domNode);
				echo $simpleXml->title . "\n";
				echo $simpleXml->subtitle . "\n";
				echo $simpleXml->url . "\n";
				echo "------------\n";
			}
	}
}

输出:

樱桃红
38集电视剧 在线观看
http://tv.2345.com/detail/18922.html
------------
贤妻
30集电视剧 在线观看
http://tv.2345.com/detail/19716.html
------------

 

2.SAX解析Simple API for XML (SAX),这个用的少了,大文件用XMLReader配合前面的DOMDocument和SimpleXML基本可以搞定一切

Simple API for XML (SAX) 
<?php
$g_items = array ();
$g_elem = null;
function startElement($parser, $name, $attrs) {
	global $g_items, $g_elem;
	if ($name == 'item')
		$g_items [] = array ();
	$g_elem = $name;
}
function endElement($parser, $name) {
	global $g_elem;
	$g_elem = null;
}
function textData($parser, $text) {
	global $g_items, $g_elem;
	if ($g_elem == 'TITLE') {
		$g_items [] = $text;
	}
}

$parser = xml_parser_create ();

xml_set_element_handler ( $parser, "startElement", "endElement" );
xml_set_character_data_handler ( $parser, "textData" );

$f = fopen ( 'testxml.xml', 'r' );

while ( $data = fread ( $f, 4096 ) ) {
	xml_parse ( $parser, $data );
}

xml_parser_free ( $parser );
foreach ( $g_items as $item ) {
	echo $item . "\n";
}

输出:

樱桃红
贤妻

 

以上就是总结的几点对php对xml数据的解析了,今天写了这几个例子跑了下,也熟悉了想相关的函数和类,当然关于xml还有很多其他知识点,暂不讨论了。转载请注明出处: CoderAladdin

 

trim函数的妙用

trim本来只是过滤头尾的空白字符或者特定字符
但是如果这样用
trim($v,'(,)’);
可以过滤”(fadfasdf),”这个字符串中的第一个和最后两个字符,注意”,”和”)”是最后两个字符

自动同步wordpress文章到有道云笔记的的插件制作(一)

一直想玩一下各大开放平台来着,虽然老早就申请了各大平台的开发者账号,但是从来没有开过刀。一直都忙的跟狗一样,再加上自己难以克服的惰性,所以…

今天是春节前在公司的最后一天,上午和@麦克是你的河马在公司dota来着,玩到high处,我开始高调起来,全然不顾走过来的部门总监,大喊大叫,于是可想而知的悲剧了……然后就安静的看起有道openAPI的文档还有sdk,想把之前的一个想法实现下。一直以来都是有道笔记的忠实用户,这款笔记软件也一直没让我失望,表现一直不错(还记的当时较低版本的时候提了个小建议,升级的时候那个功能竟然加了进去,不知道是不是采纳了我的建议,嘿嘿)。不用evernote就是因为免费版的左下角有个小块的广告,虽然谈不上难看,但是我的洁癖是不能容忍的。也许你会说,现在有道笔记的左下角也有个android客户端的推广广告。是的,正是因为这个小广告,我才开始有了做这个插件的想法,不想直视它,但是又不愿意放弃它(在这里给有道笔记提个小建议,如果用户从这个推广链接点到有道的应用下载界面,然后点了安装过这个软件,就不要再去显示了嘛,不然像我这种人,怎么看怎么不舒服,至于实现,是very easy的哦~)。我的这个想法是把平时的笔记文章写到博客上然后自动同步到有道笔记去,好处嘛自己去体会喽。

第一次玩开放平台,也是第一次接触oauth认证,流程很容易懂,开发者先去开放平台申请,然后等个几天之后,平台会给你key或许还有个secret,通过这些信息,你可以去按照api规定的一些方法组装一些参数去获取一组token,通过这个token,跳到登陆授权页面,让用户选择是否授权,然后用户授权之后,重定向到callbackUrl(如果有callbackUrl的话),同时有一个verifier,然后通过这个verifier和之前得到的token,再去请求一个accessToken,成功的话,给你返回一个accessToken和accessSecret。ok到了这里,你就可以通过这个accessToken和accessSecret来操作用户的有道笔记了[注],增删改查神马的,一切由你的代码说了算喽(当然这是在用户给你的代码授权的前提下),遇到的一个问题就是,我第一次成功走了这遍流程的时候,那我第二次是不是要再去要用户授权再去操作呢?我想那会把用户逼疯的,所以我觉得只要一次授权,就可以了。回头看我标记了[注]的那句话。是的,就是这个accessToken和accessSecret,只要用户第一次授权之后,你把这玩意保存下来,怎么存随你了,那么就可以用这玩意去做你想做的事情了(增删改查对应accessToken用户的笔记)。这个问题把我搞了有好一会,还是在一个腾讯微博开放平台开发者论坛里面找到的答案,要是看文档的时候能心细点看到我标[注]相关的那段,也就不用纠结这个了。当然,文档上是这样写的“通常Access Token 具有一定的有效期,在有效期内应用程序可以一直访问该用户的数据,而当Access Token 过期后,应用程序则需要再次走一遍授权流程。”。所以过期之后,又得走一遍授权,这点上希望有道让用户自己来决定是否撤销授权。也就是让用户自己操作删除第三方应用保存的accessToken。

今天就是小改了下有道托管在google code的sdk,自己实在太懒,懒得去组装api中规定的请求参数,就直接用sdk中封装好的方法,实现了下代码对笔记的操作,还没真正写成wordpress的插件,所以本文是(一),其实还没写过wordpress的插件,囧rz..,什么时候才能完工,还真心说不定。下面就是改的sdk里面sample的代码,代码丑陋,斗胆放出。文章表达观点若有不当,还请斧正。

<?php
include 'ynote_client.php';
header("Content-type: text/html; charset=utf-8");
$do = $_GET['do'] ? $_GET['do'] : 'api_test';

// please fill the following fields to run the demo
$oauth_consumer_key = "**********************";
$oauth_consumer_secret = "***********************";
$this_page = "http://localhost/test/php_sdk/ynote_client_example.php"; // this is the URL for the demo to get back to this page.

if(!($_GET['oauth_token'] && $_GET['oauth_verifier']))
{
	if ($do == 'api_test') {
	/******************************************** DEMO *************************************************/
		$client = new YnoteClient($oauth_consumer_key, $oauth_consumer_secret, 'http://sandbox.note.youdao.com');

		$response = $client->getRequestToken();
	    $request_token = $response['oauth_token'];
		$request_secret = $response['oauth_token_secret'];
		echo '<br />';

		$call_back = $this_page.'?request_token='.$request_token.'&request_secret='.$request_secret;
		$content = $client->getAuthorizeUrl($call_back);
		echo '<script type="text/javascript">location.href="'.$content.'"</script>';

	}
}
else 
{
	$post['verifier'] = $_GET['oauth_verifier'];
	$post['oauth_request_token'] = $_GET['request_token'];
	$post['oauth_request_secret'] = $_GET['request_secret'];

	$client = new YnoteClient($oauth_consumer_key, $oauth_consumer_secret);

	//这里要把token保存好,下次就不用授权了
    $oauth_access_token = '***************';
    $oauth_access_secret = '************************';

    echo 'access token:'.$oauth_access_token;
    echo '<br />';
    echo 'access secret:'.$oauth_access_secret;
    echo '<br />';

    $user_info_response = $client->getUserInfo($oauth_access_token, $oauth_access_secret);
    echo '<pre>';
    print_r(json_decode($user_info_response));
    echo '</pre>';

    echo '<br />';
    $list_notebook_response = $client->listNotebooks($oauth_access_token, $oauth_access_secret);
    $list_notebook = json_decode($list_notebook_response);
    echo '<pre>';
    print_r($list_notebook);
    echo '</pre>';

    echo '<br />';
    $list_notes_response = $client->listNotes($oauth_access_token, $oauth_access_secret, $list_notebook[0]->path);
    $list_note = json_decode($list_notes_response);
    echo '<pre>';
    print_r($list_note);
    echo '</pre>';

    echo '<br />';
    $get_note_response = $client->getNote($oauth_access_token, $oauth_access_secret, $list_note[0]);
	echo '<pre>';
    print_r(json_decode($get_note_response));
	echo '</pre>';
}

用开放平台的接口做事情还是有一定的局限性的,现在肚子里对微博神马的还有不少想法想去实现,如果开放的这些接口不能满足我的需求的话,会借@朱光星云共享给我的某个神器去做,哈哈。

顺便吐个槽,昨晚睡前掐指一算,无形地诞生了很多痛苦,不算上年终奖和1月份的工资(因为还没发,日),我12年整年攒下的钱一共才1k+,是的没错,才1000多块!真不晓得钱去哪里了,我了个大操!今年光棍节的时候一共花了六七百块给自己买了两件外套和两双鞋,没有买裤子,现在穿身上的牛仔裤也穿了快三年了,袋口和裤脚都破破烂烂了,真他妈苦逼。

php中的(多线程)curl批量处理

function getMultiUrls($urls, $timeout = 30)
	{
		$queue = curl_multi_init();
		$map = array();
	
		foreach($urls as $id=>$url)
		{
			$ch = curl_init();
			curl_setopt($ch , CURLOPT_URL , $url);
			curl_setopt($ch , CURLOPT_TIMEOUT , $timeout);
			curl_setopt($ch , CURLOPT_RETURNTRANSFER , 1);
 			curl_setopt($ch, CURLOPT_HEADER, true);
// 			curl_setopt($ch , CURLOPT_HEADER , 0);
			curl_setopt($ch, CURLOPT_NOBODY, true);
			curl_setopt($ch , CURLOPT_NOSIGNAL , true);
	
			curl_multi_add_handle($queue , $ch);
			$map[(string) $ch] = $id;
		}
	
		$responses = array();
		do
		{
			while(($code = curl_multi_exec($queue , $active)) == CURLM_CALL_MULTI_PERFORM);
			if($code != CURLM_OK)
			{
				break;
			}
	
			// a request was just completed -- find out which one
			while($done = curl_multi_info_read($queue))
			{
	
				// get the info and content returned on the request
				$content = curl_multi_getcontent($done['handle']);
	
				$responses[$map[(string) $done['handle']]] = $this->parseHead($content);
	
				// remove the curl handle that just completed
				curl_multi_remove_handle($queue , $done['handle']);
				curl_close($done['handle']);
			}
	
			// Block for data in / output; error handling is done by
			// curl_multi_exec
			if($active > 0)
			{
				curl_multi_select($queue , 0.5);
			}
		}
		while($active);
		curl_multi_close($queue);
		return $responses;
	}
	
	function parseHead($headSream)
	{
		$headArrayTemp = explode("\r\n", $headSream);
		foreach ($headArrayTemp as $k=>$v)
		{
			if ($k==0)
			{
				$httpstas = explode(" ",$v);
				$headArray["http-edition"] = trim($httpstas[0]);
				$headArray["http-state"] = trim($httpstas[1]);
				$headArray["http-describe"] = "";
				for($i=2;$i<count($httpstas);$i++){
						$headArray["http-describe"] .= " ".trim($httpstas[$i]);
				}
			}
			else
			{
				if ($v == '')
				{
					break;
				}
				$headArray[strtolower(substr($v, 0, strpos($v, ':')))] = substr($v,strpos($v, ':')+1);
			}
		}
		
		return $headArray;
	}

正则中的一些特殊字母

i 匹配大小写

s 模式中的圆点元字符(.)匹配所有的字符,包括换行符

x 模式中的空白字符除了被转义的或在字符类中的以外完全被忽略,在未转义的字符类之外的 # 以及下一个换行符之间的所有字符,包括两 头,也都被忽略

A (PCRE_ANCHORED) 如果设定了此修正符,模式被强制为“anchored”,即强制仅从目标字符串的开头开始匹配即自动在模式开头加上^。

D (PCRE_DOLLAR_ENDONLY) 如果设定了此修正符,模式中的美元元字符仅匹配目标字符串的结尾。没有此选项时,如果最后一个字符是换行符的话,美元符号也会匹配此字符之前(但不会匹配 任何其它换行符之前)。如果设定了 m 修正符则忽略此选项。Perl 中没有与其等价的修正符。  S 当一个模式将被使用若干次时,为加速匹配起见值得先对其进行分析。如果设定了此修正符则会进行额外的分析。目前,分析一个模式仅对没有单一固定起始字符的 non-anchored 模式有用。

U (PCRE_UNGREEDY) 本修正符反转了匹配数量的值使其不是默认的重复,而变成在后面跟上“?”才变得重复。这和 Perl 不兼容。也可以通过在模式之中设定 (?U) 修正符来启用此选项。

X (PCRE_EXTRA) 此 修正符启用了一个 PCRE 中与 Perl 不兼容的额外功能。模式中的任何反斜线后面跟上一个没有特殊意义的字母导致一个错误,从而保留此组合以备将 来扩充。默认情况下,和 Perl 一样,一个反斜线后面跟一个没有特殊意义的字母被当成该字母本身。当前没有其它特性受此修正符控制。即:贪婪模式,最 大限度匹配 如:/a[\w]+?e/U匹配abceadeddd中的abceade而不是abce,如果不加U修正,则匹配abce  u (PCRE_UTF8) 此修正符启用了一个 PCRE 中与 Perl 不兼容的额外功能。模式字符串被当成 UTF-8。本修正符在 Unix 下自 PHP 4.1.0 起可用,在 win32 下自 PHP 4.2.3 起可用。

php中关于date中的周次

for ($i = 1990; $i <= 2025; $i++) {
	echo $i . '年第一天是星期' . date('w', strtotime($i . '-01-01')) . '====第'  . date('W', strtotime($i . '-01-01')) . '周&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;' . $i . '年最后一天是星期' . date('w', strtotime($i . '-12-31')) . '====第'  . date('W', strtotime($i . '-12-31')) . '周<br />';
}

clipboard

 

可以看到:
                年初的时候,如果第一天是周1,周2,周3,周4这几天,那么用date(‘W’,time())会解析出是这年的第一周
                                     如果第一天是周5,周6,周日这几天,那么用date(‘W’,time())会解析出是上一年的最后一周
                年末的时候,如果最后一天是周1,周2,周3这几天,那么用date(‘W’,time())会解析出是下一年的第一周
                                     如果 最后一天是周4周5,周6,周日这几天,那么用date(‘W’,time())会解析出是这年的最后一周

php匹配汉字的正则表达式,utf-8编码和gbk编码

/^[\x{4e00}-\x{9fa5}]+$/u

以上这个正则表达式就是困扰了很多php程序员的匹配汉字的正则表达式

大家可能会觉得很简单,实际上不同编码,不同程序语言,都有些细微的出入,稍不注意就得不到正确的结果。
下面是utf-8编码的例子:
程序语言为php
$str = "MyBB中文站";
if (preg_match("/^[\x{4e00}-\x{9fa5}]+$/u",$str)) {
print("该字符串全部是中文");
} else {
print("该字符串不全部是中文");
}

下面的例子包含gbk,gb2312的用法,需要的可以取消gbk那行的注释,然后把utf-8的注释掉

<?php
$action = trim($_GET['action']);
if($action == "sub")
{
    $str = $_POST['dir'];    
    //if(!preg_match("/^[".chr(0xa1)."-".chr(0xff)."A-Za-z0-9_]+$/",$str)) //GB2312汉字字母数字下划线正则表达式 
    if(!preg_match("/^[\x{4e00}-\x{9fa5}A-Za-z0-9_]+$/u",$str))   //UTF-8汉字字母数字下划线正则表达式
    {   
        echo "<font color=red>您输入的[".$str."]含有违法字符</font>";   
    }
    else 
    {
        echo "<font color=green>您输入的[".$str."]完全合法,通过!</font>";   
    }
}
?>
<form method="POST" action="?action=sub">
输入字符(数字,字母,汉字,下划线):
    <input type="text" name="dir" value="">
    <input type="submit" value="提交">
</form>

具体如何得出这个正则表达式的,可以参考原文:http://www.diybl.com/course/4_webprogram/php/phpjs/20090302/156831.html

通过伪造Referer来解决外链问题

什么是Referer?
Referer是HTTP Header的一个字段,当浏览器向服务器发送请求的时候一般会包含Referer信息,这一字段保存的是访客的来源URI。

以PHP为例,通过输出$_SERVER变量,你就可以看到HTTP_REFERER信息:

如今很多知名的网络相册(如网易相册、百度相册、51相册等等)都限制了外链,我不知道它们用什么方式实现,但是目前而言大多数防盗链的机制都是基于对Referer的判断来实现的。比如说,我有一个网站,其中一个页面地址是 http://example.com/test.html,里面需要外链一张猫扑的图片,因此,image.html里面可以这么写:

但是我们会发现这样外链的图片是无法显示出来的。原因在于,当我们访问http://example.com/test.html时,浏览器会向upload3.mop.com也就是猫扑的服务器发送一个请求,这一请求中包含的Referer信息应该就是这样:

http://example.com/test.html

这样,猫扑的服务器就可以判断出这是一个来自外部网站的请求,从而予以拒绝,这样我们就无法显示这张图片了。

那么,应该如何解决这一问题呢? 用火狐浏览器的可能知道,火狐有个插件叫做RefControl,可以用它来伪造Referer,从而正常显示图片。但是如果你是站长,你总不能要求你的 访客都使用火狐浏览器对吧?即便你所有的访客都使用火狐浏览器,你也很难保证他们都安装了RefControl这个插件。
这样,我们只能从程序方面入手解决问题:

<?php
ob_start();
$img=$_GET['url'];
&nbsp;
$host=$path=str_replace('http://','',$img);
$host=explode('/',$host);
$host=$host[0];
$path=strstr($path,'/');
$fp = fsockopen($host, 80, $errno, $errstr, 30);
if ($fp)
{
	@fputs($fp, "GET $path HTTP/1.1\r\n");
	@fputs($fp, "Host: $host\r\n");
	@fputs($fp, "Accept: */*\r\n");
	@fputs($fp, "Referer: http://$host/\r\n");
	@fputs($fp, "User-Agent: Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1)\r\n");
	@fputs($fp, "Connection: Close\r\n\r\n");
}
&nbsp;
$Content = '';
while ($str = fread($fp, 4096))
	$Content .= $str;
@fclose($fp);
$pos=strpos($Content,"\r\n\r\n");
$head=substr($Content,0,$pos);
$text=substr($Content,$pos+4);
header($head);
echo $text;
?>

实际上这就是通过伪造Referer来实现我们想要的效果。

我们把这段程序保存为redirect.php,放到服务器上,例如http://example.com/redirect.php,那么,接下来我们只需要将原来的外链图片地址经由这段程序处理,就可以正常显示。

[来源]

stdClass object的处理

php取回的json数据是stdClass,要将数据处理成数组,需要用get_object_vars函数,但是该函数只能将第一级对象转为数组

例子:
$back_info = file_get_contents(“http://xxxx/act/cps_api/gamelist/index/?game_ids=” . $ids);
$back_temp = json_decode($back_info);
$back = get_object_vars($back_temp);
foreach ($back as $k => $v) {
print_r($k);
echo “<br />”;
print_r($v);
exit;
}
输出:
97<br />stdClass Object
(
    [game_name] => 神仙道
    [server_info] => stdClass Object
        (
            [894] => stdClass Object
                (
                    [server_number] => 双线94区
                    [server_name] => 九鼎记事
                    [game_url] => http://xxxx/webgame/index/sxd/s94?from=0gsp_cps2345&source=cps&from_ly=cps2345
                )
        )
)
如果要访问stdClass的某个子元素:例$v->game_name