<?php
declare(ticks = 1);
$running = 1;
//信号处理函数
function sig_handler($signo)
{
switch ($signo) {
case SIGINT:
finish();
break;
default:
break;
}
}
pcntl_signal(SIGINT, "sig_handler");
class test extends \Thread {
public $url;
public $result;
public function __construct($url) {
$this->url = $url;
}
public function run() {
if ($this->url) {
$this->result = model_http_curl_get($this->url);
}
}
}
function model_http_curl_get($url) {
$curl = curl_init();
curl_setopt($curl, CURLOPT_URL, $url);
curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($curl, CURLOPT_TIMEOUT, 5);
curl_setopt($curl, CURLOPT_USERAGENT, 'Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.2)');
$result = curl_exec($curl);
curl_close($curl);
return $result;
}
for ($i = 0; $i < 500; $i++) {
$urls[] = 'http://www.baidu.com/s?wd='. rand(10000, 20000);
}
$pool = array();
for ($i=1;$i<=5;$i++) {
$key = uniqid();
$url = array_shift($urls);
$pool[$key] = new test($url);
$pool[$key]->start();
echo "启动线程$key\n";
}
while ($urls && $running) {
foreach ($pool as $key=>$worker) {
if(! $worker->isRunning()){
//unset($pool[$key]);
echo "线程".$key."已结束\n";
$url = array_shift($urls);
$pool[$key] = new test($url);
$pool[$key]->start();
echo "启动线程$key\n";
}
}
usleep(1000);
}
function finish() {
global $running;
global $pool;
$running = 0;
echo "接收到信号,等待运行中线程结束\n";
foreach ($pool as $key=>$worker) {
if ($pool[$key]->join()) {
var_dump($pool[$key]->result);
}
}
}
先我们来看看一段用php如何识别用户是通过 PC、iPad 还是手机来访问网站?
<?php
$uAgent = $_SERVER['HTTP_USER_AGENT'];
$osPat = "mozilla|m3gate|winwap|openwave|Windows NT|Windows 3.1|95|Blackcomb|98|ME|XWindow|ubuntu|Longhorn|AIX|Linux|AmigaOS|BEOS|HP-UX|OpenBSD|FreeBSD|NetBSD|OS\/2|OSF1|SUN";
if(preg_match("/($osPat)/i", $uAgent ))
{
echo "来着PC访问";
}
else
{
echo "其他终端访问";
}
?>
以下是腾讯的通过JS语句判断WEB网站的访问端是电脑还是手机
腾讯网的适配代码
如何判断访问网站的机器类型-如何判断ipad
JS 判断浏览器客户端类型(ipad,iphone,android)
<script type="text/javascript">
<!--
//平台、设备和操作系统
var system = {
win: false,
mac: false,
xll: false,
ipad:false
};
//检测平台
var p = navigator.platform;
system.win = p.indexOf("Win") == 0;
system.mac = p.indexOf("Mac") == 0;
system.x11 = (p == "X11") || (p.indexOf("Linux") == 0);
system.ipad = (navigator.userAgent.match(/iPad/i) != null)?true:false;
//跳转语句,如果是手机访问就自动跳转到wap.baidu.com页面
if (system.win || system.mac || system.xll||system.ipad) {
} else {
window.location.href = "http://www.jdpatro.com/3g/";
}
-->
</script>
腾讯网的适配代码
<script type="text/javascript">
if(/AppleWebKit.*Mobile/i.test(navigator.userAgent) || (/MIDP|SymbianOS|NOKIA|SAMSUNG|LG|NEC|TCL|Alcatel|BIRD|DBTEL|Dopod|PHILIPS|HAIER|LENOVO|MOT-|Nokia|SonyEricsson|SIE-|Amoi|ZTE/.test(navigator.userAgent))){
if(window.location.href.indexOf("?mobile")<0){
try{
if(/Android|webOS|iPhone|iPod|BlackBerry/i.test(navigator.userAgent)){
window.location.href="http://shipei.qq.com/index.htm";
}else if(/iPad/i.test(navigator.userAgent)){
}else{
window.location.href="http://shipei.qq.com/simple/s/index/"
}
}catch(e){}
}
}
</script>
<script type="text/javascript">
var browser = {
versions : function() {
var u = navigator.userAgent, app = navigator.appVersion;
return {//移动终端浏览器版本信息
trident : u.indexOf('Trident') > -1, //IE内核
presto : u.indexOf('Presto') > -1, //opera内核
webKit : u.indexOf('AppleWebKit') > -1, //苹果、谷歌内核
gecko : u.indexOf('Gecko') > -1 && u.indexOf('KHTML') == -1, //火狐内核
mobile : !!u.match(/AppleWebKit.*Mobile.*/)
|| !!u.match(/AppleWebKit/), //是否为移动终端
ios : !!u.match(/\(i[^;]+;( U;)? CPU.+Mac OS X/), //ios终端
android : u.indexOf('Android') > -1 || u.indexOf('Linux') > -1, //android终端或者uc浏览器
iPhone : u.indexOf('iPhone') > -1 || u.indexOf('Mac') > -1, //是否为iPhone或者QQHD浏览器
iPad: u.indexOf('iPad') > -1, //是否iPad
webApp : u.indexOf('Safari') == -1,//是否web应该程序,没有头部与底部
google:u.indexOf('Chrome')>-1
};
}(),
language : (navigator.browserLanguage || navigator.language).toLowerCase()
}
document.writeln("语言版本: "+browser.language);
document.writeln(" 是否为移动终端: "+browser.versions.mobile);
</script>
如何判断访问网站的机器类型-如何判断ipad
如何判断是否是 iPad 浏览器呢,关键是看它的 User Agent 中是否有 iPad。iPad 使用的是 Safari Mobile 浏览器,他的的 User Agent 是:
Mozilla/5.0 (iPad; U; CPU OS 3_2 like Mac OS X; en-us) AppleWebKit/531.21.10 (KHTML, like Gecko) Version/4.0.4 Mobile/7B334b Safari/531.21.10
function is_iPad(){
[object Object] [object Object] [object Object]var ua = navigator.userAgent.toLowerCase();
[object Object] [object Object] [object Object]if(ua.match(/iPad/i)=="ipad") {
[object Object] [object Object] [object Object] [object Object] [object Object] [object Object]return true;
[object Object] [object Object] [object Object]} else {
[object Object] [object Object] [object Object] [object Object] [object Object] [object Object]return false;
[object Object] [object Object] [object Object]}
}
$is_iPad = (bool) strpos($_SERVER['HTTP_USER_AGENT'],'iPad');
RewriteCond %{HTTP_USER_AGENT} ^.*iPad.*$
RewriteRule ^(.*)$ http://ipad.fairyfish.net [R=301]
JS 判断浏览器客户端类型(ipad,iphone,android)
<script type="text/javascript">
var bForcepc
= fGetQuery("dv") == "pc";
function
fBrowserRedirect(){
var sUserAgent = navigator.userAgent.toLowerCase();
var bIsIpad = sUserAgent.match(/ipad/i) ==
"ipad";
var bIsIphoneOs = sUserAgent.match(/iphone os/i) == "iphone os";
var bIsMidp = sUserAgent.match(/midp/i) == "midp";
var bIsUc7 = sUserAgent.match(/rv:1.2.3.4/i) == "rv:1.2.3.4";
var bIsUc = sUserAgent.match(/ucweb/i) == "ucweb";
var bIsAndroid = sUserAgent.match(/android/i) == "android";
var bIsCE = sUserAgent.match(/windows ce/i) == "windows ce";
var bIsWM = sUserAgent.match(/windows mobile/i) == "windows
mobile";
if(bIsIpad){
var sUrl =
location.href;
if(!bForcepc){
window.location.href = "http://ipad.mail.163.com/";
}
}
if(bIsIphoneOs || bIsAndroid){
var sUrl =
location.href;
if(!bForcepc){
window.location.href = "http://smart.mail.163.com/";
}
}
if(bIsMidp||bIsUc7||bIsUc||bIsCE||bIsWM){
var sUrl =
location.href;
if(!bForcepc){
window.location.href = "http://m.mail.163.com/";
}
}
}
function
fGetQuery(name){//获取参数值
var sUrl = window.location.search.substr(1);
var r = sUrl.match(new RegExp("(^|&)" + name +
"=([^&]*)(&|$)"));
return (r == null ? null : (r[2]));
}
function
fShowVerBlock(){
if(bForcepc){
document.getElementByIdx_x("dv_block").style.display = "block";
}
else{
document.getElementByIdx_x("ad_block").style.display = "block";
}
}
fBrowserRedirect();
</script>
![Accept-Length下载获取不到文件大小](/upload/news/201611/20150509224722867.jpg)
![Content-Length下载获取到了文件大小](/upload/news/201611/20150509224724738.jpg)
简介
SPL全称为(Standard PHP Library,PHP标准库),从官方文档上来看,SPL主要包含以下几块:
接口
数据结构
迭代器
异常
函数加强
ArrayObject
SqlFileInfo
一、接口
接口提供了对类的约束,在一个架构良好的类库中,通常都有设计非常好的接口定义,这里包括该抽象成接口的要抽象,同时避免接口滥用。在SPL里,主要的接口有以下几个:Countable,
OuterIterator,RecursiveIterator,SeekableIterator。
首先,这几个方法都继承自Iterator,复习下Iterator的定义:
1: Iterator extends Traversable {
2:
3: abstract public mixed current ( void )
4: abstract public scalar key ( void )
5: abstract public void next ( void )
6: abstract public void rewind ( void )
7: abstract public boolean valid ( void )
8: }
Countable明显是提供一个计数的约定,在Iterator之上,通过count方法获取集合中的数目。
OutIterator封装了Iterator,在此基础上添加了获取迭代器的方法。
RecursiceIterator在Iterator的基础上支持了迭代,新增检查和获取子节点的方法。
SeekIterator在Iterator基础上,新增了seek方法,用以获取指定位置的对象。
三、数据结构
SPL给PHP配置了一些加强的数据结构,使PHP看起来稍现代了点。添加的数据结构有以下几个:
双链表
栈
队列
优先级队列
堆
大顶堆
小顶堆
数组
定长数组
映射
对象映射
双链表(SplDoublyLinkedList),栈(SplStack),队列(SplQueue),优先级队列(SplPriorityQueue)都实现了Iterator接口,ArrayAccess接口,Countable接口。我们主要复习下ArrayAccess,我们以前使用的数组,可以看做是映射的 版本,而ArrayAccess,则是映射的版,也就是说,可以用这种方法来存取对象: arr[“one”]=1; arr[obj1]=2; 继续看数据结构,双链表等在以上接口的基础上增加了pop,push等该接口常见的操作。
堆(SplHeap),大顶堆(SplMaxHeap),小顶堆(SplMinHeap)只继承了Iterator接口和Countable接口。值得一提的是,大顶堆和小顶堆是通过compare方法来将数据插入堆中,数据结构来维护堆的筛操作。
定长数组(SplFixedArray),常规的数组支持各种数据类型的键,并且长度可变,灵活的同时带来了性能的损耗。定长数组牺牲灵活性来换取性能。具体性能的测评可以看这里。
Coutable接口:
实现Countable接口的对象可用于count()函数计数。
class Mycount implements Countable
{
public function count()
{
static $count = 0;
$count++;
return $count;
}
}
$count = new Mycount();
$count->count();
$count->count();
echo count($count); //3
echo count($count); //4
说明:
调用count()函数时,Mycount::count()方法被调用
count()函数的第二个参数将不会产生影响
OuterIterator接口:
自定义或修改迭代过程。
//IteratorIterator是OuterIterator的一个实现类
class MyOuterIterator extends IteratorIterator {
public function current()
{
return parent::current() . 'TEST';
}
}
foreach(new MyOuterIterator(new ArrayIterator(['b','a','c'])) as $key => $value) {
echo "$key->$value".PHP_EOL;
}
/*
结果:
0->bTEST
1->aTEST
2->cTEST
*/
在实际运用中,OuterIterator极其有用:
$db = new PDO('mysql:host=localhost;dbname=test', 'root', 'mckee');
$db->query('set names utf8');
$pdoStatement = $db->query('SELECT * FROM test1', PDO::FETCH_ASSOC);
$iterator = new IteratorIterator($pdoStatement);
$tenRecordArray = iterator_to_array($iterator);
print_r($tenRecordArray);
RecursiveIterator接口:
用于循环迭代多层结构的数据,RecursiveIterator另外提供了两个方法:
RecursiveIterator::getChildren 获取当前元素下子迭代器
RecursiveIterator::hasChildren 判断当前元素下是否有迭代器
class MyRecursiveIterator implements RecursiveIterator
{
private $_data;
private $_position = 0;
public function __construct(array $data) {
$this->_data = $data;
}
public function valid() {
return isset($this->_data[$this->_position]);
}
public function hasChildren() {
return is_array($this->_data[$this->_position]);
}
public function next() {
$this->_position++;
}
public function current() {
return $this->_data[$this->_position];
}
public function getChildren() {
print_r($this->_data[$this->_position]);
}
public function rewind() {
$this->_position = 0;
}
public function key() {
return $this->_position;
}
}
$arr = array(0, 1=> array(10, 20), 2, 3 => array(1, 2));
$mri = new MyRecursiveIterator($arr);
foreach ($mri as $c => $v) {
if ($mri->hasChildren()) {
echo "$c has children: " .PHP_EOL;
$mri->getChildren();
} else {
echo "$v" .PHP_EOL;
}
}
/*
结果:
0
1 has children:
Array
(
[0] => 10
[1] => 20
)
2
3 has children:
Array
(
[0] => 1
[1] => 2
)
*/
SeekableIterator接口:
通过seek()方法实现可搜索的迭代器,用于搜索某个位置下的元素。
class MySeekableIterator implements SeekableIterator {
private $position = 0;
private $array = array(
"first element" ,
"second element" ,
"third element" ,
"fourth element"
);
public function seek ( $position ) {
if (!isset( $this -> array [ $position ])) {
throw new OutOfBoundsException ( "invalid seek position ( $position )" );
}
$this -> position = $position ;
}
public function rewind () {
$this -> position = 0 ;
}
public function current () {
return $this -> array [ $this -> position ];
}
public function key () {
return $this -> position ;
}
public function next () {
++ $this -> position ;
}
public function valid () {
return isset( $this -> array [ $this -> position ]);
}
}
try {
$it = new MySeekableIterator ;
echo $it -> current (), "\n" ;
$it -> seek ( 2 );
echo $it -> current (), "\n" ;
$it -> seek ( 1 );
echo $it -> current (), "\n" ;
$it -> seek ( 10 );
} catch ( OutOfBoundsException $e ) {
echo $e -> getMessage ();
}
/*
结果:
first element
third element
second element
invalid seek position ( 10 )
*/
SplObserver和SplSubject接口:
SplObserver和SplSubject接口用来实现观察者设计模式,观察者设计模式是指当一个类的状态发生变化时,依赖它的对象都会收到通知并更新。使用场景非常广泛,比如说当一个事件发生后,需要更新多个逻辑操作,传统方式是在事件添加后编写逻辑,这种代码耦合并难以维护,观察者模式可实现低耦合的通知和更新机制。
看看SplObserver和SplSubject的接口结构:
//SplSubject结构 被观察的对象
interface SplSubject{
public function attach(SplObserver $observer); //添加观察者
public function detach(SplObserver $observer); //剔除观察者
public function notify(); //通知观察者
}
//SplObserver结构 代表观察者
interface SplObserver{
public function update(SplSubject $subject); //更新操作
}
看下面一个实现观察者的例子:
class Subject implements SplSubject
{
private $observers = array();
public function attach(SplObserver $observer)
{
$this->observers[] = $observer;
}
public function detach(SplObserver $observer)
{
if($index = array_search($observer, $this->observers, true)) {
unset($this->observers[$index]);
}
}
public function notify()
{
foreach($this->observers as $observer) {
$observer->update($this);
}
}
}
class Observer1 implements SplObserver
{
public function update(SplSubject $subject)
{
echo "逻辑1代码".PHP_EOL;
}
}
class Observer2 implements SplObserver
{
public function update(SplSubject $subject)
{
echo "逻辑2代码".PHP_EOL;
}
}
$subject = new Subject();
$subject->attach(new Observer1());
$subject->attach(new Observer2());
$subject->notify();
/*
结果:
逻辑1代码
逻辑2代码
*/
加入我们现在有两个PHP文件,内容如下:
Test1.php
<?php class Test1 { public function func1() { return 'test1'; } } ?>
Test2.php
<?php class Test2 { public function func2() { return 'test2'; } } ?>
然而在需要载入这两个文件时,传统的写法是这样的:
<?php require ('Test1.php'); require ('Test2.php'); $TestObj1 = new Test1(); $TestObj2 = new Test2(); echo $TestObj1->func1().'<br/>'; echo $TestObj2->func2(); ?>
现在我们使用PHP类的自动载入,只需要定义 __autoload() 方法既可将类自动载入,方法如下:
<?php //define autoload function function __autoload($class) { require __DIR__.'/'.$class.'.php'; } $TestObj1 = new Test1(); $TestObj2 = new Test2(); echo $TestObj1->func1().'<br/>'; echo $TestObj2->func2(); ?>
很方便吧,可是之后__autoload这个函数被废弃掉了,主要原因是因为,我们一个PHP的项目可能会依赖多个框架,如果我们每一个框架都拥有这个函数,那么程序就会报一个函数重复定义的致命错误。当然不用担心,在PHP5.3之后呢,官方提供了一个 spl_autoload_register() 函数来取代 __autoload,这个函数的特点是它允许你存在多个相同的载入函数,即使我写了多个载入,也不会出现任何问题,代码如下:
<?php spl_autoload_register(autoload1); spl_autoload_register(autoload2); //define autoload function function autoload1($class) { require __DIR__.'/'.$class.'.php'; } function autoload2($class) { require __DIR__.'/'.$class.'.php'; } $TestObj1 = new Test1(); $TestObj2 = new Test2(); echo $TestObj1->func1().'<br/>'; echo $TestObj2->func2(); ?>
这种方法会更先进一些,也是我们采用的最主要的方法。博主最近开发的项目使用的是ThinkPHP框架,就在框架的核心文件Think.class.php中找到它的自动载入函数,拷过来给大家看下。
static public function start() { // 注册AUTOLOAD方法 spl_autoload_register('Think\Think::autoload'); } /** * 类库自动加载 * @param string $class 对象类名 * @return void */ public static function autoload($class) { // 检查是否存在映射 if(isset(self::$_map[$class])) { include self::$_map[$class]; } elseif (false !== strpos($class,'\\')){ $name = strstr($class, '\\', true); if(in_array($name,array('Think','Org','Behavior','Com','Vendor')) || is_dir(LIB_PATH.$name)){ // Library目录下面的命名空间自动定位 $path = LIB_PATH; }else{ // 检测自定义命名空间 否则就以模块为命名空间 $namespace = C('AUTOLOAD_NAMESPACE'); $path = isset($namespace[$name])? dirname($namespace[$name]).'/' : APP_PATH; } $filename = $path . str_replace('\\', '/', $class) . EXT; if(is_file($filename)) { // Win环境下面严格区分大小写 if (IS_WIN && false === strpos(str_replace('/', '\\', realpath($filename)), $class . EXT)){ return ; } include $filename; } }elseif (!C('APP_USE_NAMESPACE')) { // 自动加载的类库层 foreach(explode(',',C('APP_AUTOLOAD_LAYER')) as $layer){ if(substr($class,-strlen($layer))==$layer){ if(require_cache(MODULE_PATH.$layer.'/'.$class.EXT)) { return ; } } } // 根据自动加载路径设置进行尝试搜索 foreach (explode(',',C('APP_AUTOLOAD_PATH')) as $path){ if(import($path.'.'.$class)) // 如果加载类成功则返回 return ; } } }
更多的相关知识大家可以自行去搜索,或者查看相关手册。