今日两坑

坑1:

$a = 'test';
echo $a['bdd'];

得到结果

t

一个字符串,把它当成数组并取它一个不存在的键值,得到的是第一个字符。今天写一个方法的时候,返回结果可能是字符串也可能是数组,调用这个方法的时候用数组中的某个值来判断,无疑是错的!

坑2:

在post的时候有大量的数据,发现post不过去,原来php在5.3.9以后的版本中加入了最大post数量的限制,默认是1000条,可以在php.ini中找到该项

max_input_vars来做修改。

为什么在5.3.9中加入这个参数?这个就要提到hash冲突的一个漏洞了,这个漏洞在没patch的低版本php中存在,包括java等各种语言中存在。hash表是一种良好的数据结构,当数据被精心构造过之后,会使hash表降级成一个链表结构,在查询数据的时候每次都会发生hash冲突,一次命中率极低,大大降低了效率,这就使得单机DDOS攻击成为可能。因此加入这个post数量限制限制了服务器接收的post数据,即使post过来默认的1000个数据都能精确的造成hash冲突,那么也是在服务器能够承受的范围内了。

可以参考:

参考1

参考2

原生PHP和Zend Framwork中使用SOAP做webservice

soap的两种实现方式:WSDL和Non-WSDL

1.non-wsdl模式利用php的soap扩展实现:

server

<?php
class HandleClass {
    public function test() {
        return '23434';
    }
}

//uri必填
$soap_server = new SoapServer(null, array('uri'=>'http://soap/','location'=>'http://localhost/soap/server.php'));
$soap_server->setClass('HandleClass');
$soap_server->handle();

client

<?php
//location和uri必填
$soap_client = new SoapClient(null, array('location'=>'http://localhost/soap/server.php','uri'=>'http://soap/'));
echo $soap_client->test();

output:

23434

2.wsdl利用php的soap扩展实现

server:

<?php
class service {
	public function HelloWorld() {
		return "Hello";
	}
}
$server = new SoapServer ('helloworld.wsdl');
$server->setClass ( "service" );
$server->handle ();

client:

<?php
$client = new SoapClient ( "helloworld.wsdl" );
echo $client->HelloWorld ();

wsdl:

<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<wsdl:definitions xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" xmlns:tns="http://www.example.org/helloworld/" xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" name="helloworld" targetNamespace="http://www.example.org/helloworld/">
  <wsdl:types>
    <xsd:schema targetNamespace="http://www.example.org/helloworld/">
      <xsd:element name="HelloWorld">
        <xsd:complexType>
          <xsd:sequence>
            <xsd:element name="in" type="xsd:string"/>
          </xsd:sequence>
        </xsd:complexType>
      </xsd:element>
      <xsd:element name="HelloWorldResponse">
        <xsd:complexType>
          <xsd:sequence>
            <xsd:element name="out" type="xsd:string"/>
          </xsd:sequence>
        </xsd:complexType>
      </xsd:element>
    </xsd:schema>
  </wsdl:types>
  <wsdl:message name="HelloWorldRequest">

  </wsdl:message>
  <wsdl:message name="HelloWorldResponse">
    <wsdl:part name="HelloWorldReturn" type="xsd:string"/>
  </wsdl:message>
  <wsdl:portType name="helloworld">
    <wsdl:operation name="HelloWorld">
      <wsdl:input message="tns:HelloWorldRequest"/>
      <wsdl:output message="tns:HelloWorldResponse"/>
    </wsdl:operation>
  </wsdl:portType>
  <wsdl:binding name="helloworldSOAP" type="tns:helloworld">
    <soap:binding style="document" transport="http://schemas.xmlsoap.org/soap/http"/>
    <wsdl:operation name="HelloWorld">
      <soap:operation soapAction="http://www.example.org/helloworld/HelloWorld"/>
      <wsdl:input>
        <soap:body use="literal"/>
      </wsdl:input>
      <wsdl:output>
        <soap:body use="literal"/>
      </wsdl:output>
    </wsdl:operation>
  </wsdl:binding>
  <wsdl:service name="helloworld">
    <wsdl:port binding="tns:helloworldSOAP" name="helloworldSOAP">
      <soap:address location="http://localhost/soap/wsdlServer.php"/>
    </wsdl:port>
  </wsdl:service>
</wsdl:definitions>

output:

Hello

BTW,zendstudio 10中可以通过插件的 方式支持wsdl的图形化编辑,见下图QQ截图20130720164549

3.non-wsdl模式利用zend的soap组件实现

handle:

<?php
class Example_Manager {

	/**
	 * Returns list of all products in database
	 *
	 * @return array
	 */
	public function getProducts() {
		$db = Zend_Registry::get ( 'Zend_Db' );
		$sql = "SELECT * FROM products";
		return $db->fetchAll ( $sql );
	}

	/**
	 * Returns specified product in database
	 *
	 * @param integer $id        	
	 * @return array Exception
	 */
	public function getProduct($id) {
		if (! Zend_Validate::is ( $id, 'Int' )) {
			throw new Exception ( 'Invalid input' );
		}
		$db = Zend_Registry::get ( 'Zend_Db' );
		$sql = "SELECT * FROM products WHERE id = '$id'";
		$result = $db->fetchAll ( $sql );
		if (count ( $result ) != 1) {
			throw new Exception ( 'Invalid product ID: ' . $id );
		}
		return $result;
	}
}

 

server:

public function soapserverAction()
    {
    	$this->getHelper('viewRenderer')->setNoRender(true);

    	$server = new Zend_Soap_Server(null, array('uri' => 'http://zenddemo.com/index/soapserver', 'location'=> 'http://zenddemo.com/index/soapserver'));

    	$server->setClass('Example_Manager');

    	$server->handle();
    }

client:

public function soapclientAction() {
    	$this->getHelper('viewRenderer')->setNoRender(true);
    	$options = array(
    			'location' => 'http://zenddemo.com/index/soapserver',
    			'uri'      => 'http://zenddemo.com/index/soapserver'
    	);

    	try {
    		$client = new Zend_Soap_Client(null, $options);
    		$result = $client->getProducts();
    		print_r($result);
    	} catch (SoapFault $s) {
    		die('ERROR: [' . $s->faultcode . '] ' . $s->faultstring);
    	} catch (Exception $e) {
    		die('ERROR: ' . $e->getMessage());
    	}
    }

 4.wsdl模式用zend的soap组件实现

handle:同上

server:

public function soapwsdlserverAction() {
    	$this->getHelper('viewRenderer')->setNoRender(true);

    	$server = new Zend_Soap_AutoDiscover();
    	$server->setClass('Example_Manager');
    	$server->setUri('http://zenddemo.com/index/soapserver');
    	$server->handle();
    }

client:

public function soapclientAction() {
    	$this->getHelper('viewRenderer')->setNoRender(true);

    	try {
    		$client = new Zend_Soap_Client('http://zenddemo.com/index/soapwsdlserver');	
    		$result = $client->getProducts();
    		print_r($result);
    	} catch (SoapFault $s) {
    		die('ERROR: [' . $s->faultcode . '] ' . $s->faultstring);
    	} catch (Exception $e) {
    		die('ERROR: ' . $e->getMessage());
    	}
    }

 

 

nginx php 502 bad gateway

今天配centos6.3+nginx+php5.4.15(fpm),蛋碎了无数次,其中一个问题就是配PMA的时候,访问phpMyAdmin时,出现下面错误。

phpMyAdmin – Error

Cannot start session without errors, please check errors given in your PHP and/or webserver log file and configure your PHP installation properly.第一次打开提示,刷新提示:

502 bad gateway

查看nginx error log:

[error]  recv() failed (104: Connection reset by peer) while reading response header from upstream, client:, server: , request: “GET / HTTP/1.1”, upstream: “fastcgi://127.0.0.1:9000”, host: “mysql.veryi.com”

查看php session.save_path的设置,默认是/var/lib/php/session。修改该目录nginx进程的用户有读写权限。问题解决。

参考

 

基于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),”这个字符串中的第一个和最后两个字符,注意”,”和”)”是最后两个字符

陈欧体PHP版

你只看到前端的华丽,却想不到后端的复杂;你有你的想法,我有我的语法;你否定我的正统,我决定我的受众;你嘲笑我章法混乱不配作为一门语言,我可怜你总是比来比去一事无成;你可以蔑视我的草根,我会证明谁是开源的宠儿。梦想,是注定孤独的旅行,路上少不了质疑和嘲笑,但,那又怎样?哪怕千夫所指,也要流淌出我code的模样。我是PHP,我为自己代言。

自动同步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多块!真不晓得钱去哪里了,我了个大操!今年光棍节的时候一共花了六七百块给自己买了两件外套和两双鞋,没有买裤子,现在穿身上的牛仔裤也穿了快三年了,袋口和裤脚都破破烂烂了,真他妈苦逼。

为什么2013年是PHP之年[原创翻译]

2012年是PHP社区杰出的一年,由于一些迫切需要的功能加入到了5.4版本,而且还有无数的项目,使得PHP达到了新的高度。
在这篇文章里,我将和大家重温下过去人们对PHP的大量疑问,同时一窥为什么我说2013是PHP之年。

敌意
这可能令你惊讶,但是许多人对php开发者有偏见,当然对php语言本身也一样。你应该知道我的意思,如果你在过去的几年里由于来自别人的压力考虑过学习ruby。
“可是,在你改变主意是,你应该扪心自问:为什么PHP有这么多的污点?”
好吧,就想很多生活中的重要问题,这没有一个十分明确的答案。在网上搜索过一些关于php的意见之后,你会发现大概有80%的关于反对php的意见都是来自于他们的根深蒂固的无知,不管以什么样的形式的表达。

初学者
有这样的初学者,他们并没有真正了解的运行原理。这导致了问题出现,就像:为什么你不能利用php监听按钮的事件?包括一些相似的关于AJAX的问题。

一种语言统治了一群人
下面,看看这样一群人,他们除了自己用的不知道其他的语言或者框架。这就是对php产生意见的某些人,比如坚持说rails比php简单多了的哪些人等等。

还在php4里面挣扎的人
第三种误解来自那些没有跟着php的发展与时俱进的一群人。相反,他们仍然还在古老的语言里面纠结,尽管它已经是很多年前的语言了。这导致了一些论调,比如:php不是面向对象的,或者:php真垃圾,不支持命名空间。哈哈,你懂我的意思。

规模
还有,有很多的天才开发者,他们坚持认为php不能形成规模,或者php没有标准等等。当然,这些是完全错误的。规模和语言本身没什么关系,和服务关系更大,当然还有你的应用的架构。至于标准,哈哈,你去google一下PHP-FIG.
——————————————————————————————————————————–
小贴士:
什么是PHP-FIG?
这个组织旨在为了项目成员来讨论我们项目之间的共性,还有找到我们写作的方法。我们的主要受众就是我们自己,但是我们也意识到剩下的PHP社区正在观望,如果其他人愿意把我们现在在做的移植过去,这是很受欢迎的,但是这不是目的。
——————————————————————————————————————————–

不幸的事实就是,弥漫在互联网的这些对php的意见基本都是错的,或者是过时的
PHP不完美
不过,在这些批评里面也有一些是事实。PHP确实不是完美的。有一些核心特性和方法的实现是不合理的,这些意见是完全正确的。
尽管这些不合理之处并不是毫无缘由的。我们今天所说的php源自一种模板语言。自从那时候起,他演变成过各种各样的形式,转变成一门实用的语言,然后又进化成我们现在在用的完全面向对象的语言。在这演变历史中,有很多优秀的项目浮现过,也有越来越多点人掌握了新加入的东西。这却导致了一门语言中各种不同‘风格’的代码。现在你可能会疑问,为什么不可以去反对这么语言中这些并不好的部分。
这个问题的答案就想为什么我们仍然在做网站的时候兼容老版本的IE浏览器一样。不要误会我的意思,我也很想去放弃它,但是很多这种重大的改动不是一蹴而就的。希望随着时间的变化,PHP能进一步的推动面向对象编程,形式上来讲,可以用点号操作符来替代他的对象的函数用法,并不仅仅是可以接受的‘->’操作符的使用。比如。作为‘array_push($arr, “Value”)’的替代形式可以是这样的‘$arr.push(“value”)’
别着急,这种事情都是发展的很慢的看看PHP5.5的特性。老式的面向函数的MYSQL操作已经被摒弃了,这有利于更新的面向对象的实现。

当前形势
说完了过去,我们来说说现在。有一些相当酷的项目,有一些汲取了别的语言的优点,来推动PHP达到更高的水平。让我们来看看这些:
1.Composer(PHP包管理器)
2.Laravel框架
3.测试驱动的开发
4.PHP5.4/5.5

Composer
受到一些工具的启发,比如打包机和网络打印机管理器,PHP社区现在已经有了防止重造轮子的方法,向Composer致敬。Node.js 是第一种我用packages比较舒适的语言,如果你以前用过它,你就知道我指的是什么。Packages是转载你本地的项目目录,对大多数插件来讲,很容易找到文档,这也是的你提交自己的packages时相对比较简单。
PEAR?
PHP很多年来一直给用户提供一个大型库的选择,那就是PEAER,但它并不是想象中的那么好用。如果我只是要去获取一些纯文本文件,会感觉它非常之笨重。而且,你必须要全局地安装它所有的包。这就使得你在你发布项目源码的时候必须去通知所有人那些包你用了,这会导致一些版本不统一的问题,还有其他类似的问题。
Composer只需要本地的包就解决了所有的此类问题。也可以去创建每个项目的独立文件。这意味着你可以很容易的去发布你的项目,只需要这写独立文件,这样其他人就可以用他们自己的Composer的拷贝去纸动画的下载所有具体的单独文件,同时使他们保持更新。
还有一点,Composer是用PHP写的一款轻型应用,它本身就有一个自动加载的特性。这个没有遵循PSR-0标准(上文提到的),这项功能是只有在你需要的时候才去加载需要的文件,这样你的应用就能保持竟可能的精简。
所有的这些特性都是一定的进步,可是,没有社区的共性,这一切都是不存在的。我很高兴告诉你它是很受欢迎的。大型项目,比如Symfony和Laravel,已经将它们的组件上传到了Composer的库,这里是列表(https://packagist.org/)。将框架分解成一些组件意味着你可以很容易的创建你自己的自定义的框架来满足你的需求。从另一方面来讲,再也没有臃肿的框架束缚了。如果你想试试,你可以去选择你需要的组件了。

Laravel
现在如果不详细讨论下Laravel,那就不是一篇关于PHP特性的文章了。我们总是被问到,为什么你们总是 推崇Laravel。其实这是个不对的问题,应该说,为什么不呢?
即使你有一些关于PHP的问题,Laravel几乎将它们全抽象化了,给你的是一种语言的优雅感,像Ruby,但是是用的简易舒适的PHP。
Laravel是由Eloquent(https://packagist.org/packages/illuminate/database)发展而来的,一个完全重新设计的处理数据库的对象关系模型,你从数据库中得到的是一个资源对象,你必须通过一个成员方法来从这个资源对象获取结果。在Laravel中,所有的返回值都遵循PHP标准,你得到的对象可以修改和保存。你可以进行多表查询,得到的结果利用数据调用来保存,当然,仅仅做这些是可笑的,比如验证和自定义查询。另外,如果你不喜欢写SQL,那么这些工作都可以通过面向对象的方式来完成,用简单的可读性搞的方法,比如find和delete
我们只看到了冰山一角,但是,你已经能看到这些改进。Laravel把这种革新带到了PHP的几乎每一个领域包括,模板,路由,迁移,REST风格的类,等等。不过,最好的部分是,在每一个新的版本, Laravel的创造者Taylor Otwell,不断地在改进。
“如果你想更深入地学习下Laravel,我推荐Tuts+ Premium课程,Laravel Essentials(https://tutsplus.com/course/laravel-essentials/),讲师是我们的Jeffrey Way.我不是指的Nettuts+的成员,而是一个看这些教程的家伙。我很诚实地告诉你,我对Laravel的了解是零,但是Jeffrey在这个方面做的是尽可能的优秀”
这不是关于这个框架的文章,但是有社区的支持。一个项目只要有支持维护,它就会有不断的更新和相关的观点。如果你担心它能流行的时间不是太长,那么,只要积极地使用它,那么你就是在加强你的优势。

PHP5.4/5.5
下一件我想讨论的事情是2012年PHP发布的新版本。随着PHP5.4版本的发行,大量的新特性出现了。你可以看下这两篇文章来一窥大概5.4(http://net.tutsplus.com/tutorials/php/php-5-4-is-here-what-you-must-know/),5.5(http://net.tutsplus.com/tutorials/php/what-to-expect-from-php-5-5/)
不过,下面还是要讲讲我最喜欢的几点新特性
Traits
traits使得PHP可以创建“partials”类,这在你不需要覆写的情况下创建相同的对象.(不是太明白这个,可以参考鸟哥的文章http://www.laruence.com/2011/07/02/2097.html);
Generators
Generators可以让你通过数据列表来做一些很酷的事情,也能让你从所有特性中获益
CLI Web Server
另一项伟大的特性是内置的web服务器,通过这个你可以测试你的程序在不同版本php中的兼容性,这一切都不需要类似apache这种服务器软件的支持
Dereferencing
Dereferencing不是一个大的功能,但是它可以在不用方法的情况下来调子元素(这段不明白)。这包括了就像通过下标来引用字符串的字符一样的功能(见http://www.laruence.com/2011/07/02/2097.html)
新的密码散列API
通过这个新的API,你可以去加密字符串,验证或者加强密码,当然你不需要去了解任何的bcrypt或者别的哈希算法

这些特征只是很少一部分的新特性,还有一整个列表的特性正在为了下个版本的发布处于讨论阶段,按照日程应该在今年的晚些时候发布。

测试驱动的开发
最后,让我们讨论下测试的问题。尽管在2012年里,被接纳的有点晚了,我们的社区还是看到了测试驱动开发模式的广泛被采纳。我可以去调查下这方面增长的百分比,但是我感觉你去看看不通的开发者站点还有论坛能更好的说明这个增长。你肯定能看到一个spike!说到PHP中的测试,PHPUnit是一个很好被接受的标准
为什么测试很重要?
很多时候,你准备写代码了,但是你在实现需求的时候漏掉了很多东西。我说这些是指的你计划一件事情的时候,当你实现它的时候,容易失去大局,漏掉一些细节。另一个普遍的问题一直在增长,当给大项目写代码的时候,结束的时候,你可能写了大量的类和大量的文件他们都是不相干的。你剩下的可能是一些纠结的方法的演化,这样才能跟上进度。就像搭积木游戏,随着一块积木的增加,你可能搞倒了另一块,毁了整个项目。这只是两个例子,当然还有很多其他的。
测试驱动开发带来哪些帮助?
你在写任何产品的代码之前写好了清晰的测试样例。这意味着,当你开始写真实代码的时候,这就被限定必须遵循最开始的计划。不光这一段,是完全彻底地,所有都被你的测试所跟进。如果你更新了代码,不经意间没有通过测试,你会马上发现。
是的,实现这些测试需要额外的步骤,但是请三思后行。有任何人通过这种模式的开发获益么?当然没有。测试也是一样的,在你开始开发项目之前,多加思考,就想一个牛仔。
延伸阅读
测试驱动的开发(https://tutsplus.com/course/test-driven-php/)
PHP中的测试驱动开发(http://net.tutsplus.com/sessions/test-driven-php/)

总结
这个时代成为php开发者是令人振奋的。很多既有的问题正在或者已经被解决了,至于其他的问题,我们都可以通过框架和测试来找到解决方案
你的想法呢?你是否已经在码字?不同意我们?如果这样的话,在下面留言吧。

[本文译自netTuts+,转载请保留出处,本文固定链接http://coderaladdin.com/why-2013-is-the-year-of-php/ ‎]

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;
	}