【PHP】PHP图像裁剪缩略裁切类源代码及使用方法

最后更新于:2022-04-01 09:56:16

### 原因 最近在做网页拖拽验证码的开源项目,需要在服务端生成图片对应的可移动的色块,但是网上的资源都是做缩略图,对整个图片进行缩放的,所以自己动手,完成了对图片进行裁剪小块的工具 ### CODE ~~~ <?php namespace App\Libs; /** * 2016-01-07 15:54:58 * Lixiaoyu * * mode 1 : 强制裁剪,生成图片严格按照需要,不足放大,超过裁剪,图片始终铺满 * mode 2 : 和1类似,但不足的时候 不放大 会产生补白,可以用png消除。 * mode 3 : 只缩放,不裁剪,保留全部图片信息,会产生补白, * mode 4 : 只缩放,不裁剪,保留全部图片信息,生成图片大小为最终缩放后的图片有效信息的实际大小,不产生补白 * 默认补白为白色,如果要使补白成透明像素,请使用SaveAlpha()方法代替SaveImage()方法 */ class ImageCrop{ var $sImage; var $dImage; var $src_file; var $dst_file; var $src_width; var $src_height; var $src_ext; var $src_type; function __construct($src_file,$dst_file=''){ $this->src_file=$src_file; $this->dst_file=$dst_file; $this->LoadImage(); } function SetSrcFile($src_file){ $this->src_file=$src_file; } function SetDstFile($dst_file){ $this->dst_file=$dst_file; } function LoadImage(){ list($this->src_width, $this->src_height, $this->src_type) = getimagesize($this->src_file); switch($this->src_type) { case IMAGETYPE_JPEG : $this->sImage=imagecreatefromjpeg($this->src_file); $this->ext='jpg'; break; case IMAGETYPE_PNG : $this->sImage=imagecreatefrompng($this->src_file); $this->ext='png'; break; case IMAGETYPE_GIF : $this->sImage=imagecreatefromgif($this->src_file); $this->ext='gif'; break; default: exit(); } } function SaveImage($fileName=''){ $this->dst_file=$fileName ? $fileName : $this->dst_file; switch($this->src_type) { case IMAGETYPE_JPEG : imagejpeg($this->dImage,$this->dst_file,100); break; case IMAGETYPE_PNG : imagepng($this->dImage,$this->dst_file); break; case IMAGETYPE_GIF : imagegif($this->dImage,$this->dst_file); break; default: break; } } function OutImage(){ switch($this->src_type) { case IMAGETYPE_JPEG : header('Content-type: image/jpeg'); imagejpeg($this->dImage); break; case IMAGETYPE_PNG : header('Content-type: image/png'); imagepng($this->dImage); break; case IMAGETYPE_GIF : header('Content-type: image/gif'); imagegif($this->dImage); break; default: break; } } function SaveAlpha($fileName=''){ $this->dst_file=$fileName ? $fileName . '.png' : $this->dst_file .'.png'; imagesavealpha($this->dImage, true); imagepng($this->dImage,$this->dst_file); } function OutAlpha(){ imagesavealpha($this->dImage, true); header('Content-type: image/png'); imagepng($this->dImage); } function destory(){ imagedestroy($this->sImage); imagedestroy($this->dImage); } function Crop($dst_width,$dst_height,$mode=1,$dst_file=''){ if($dst_file) $this->dst_file=$dst_file; $this->dImage = imagecreatetruecolor($dst_width,$dst_height); $bg = imagecolorallocatealpha($this->dImage,255,255,255,127); imagefill($this->dImage, 0, 0, $bg); imagecolortransparent($this->dImage,$bg); $ratio_w=1.0 * $dst_width / $this->src_width; $ratio_h=1.0 * $dst_height / $this->src_height; $ratio=1.0; switch($mode){ case 1: // always crop if( ($ratio_w < 1 && $ratio_h < 1) || ($ratio_w > 1 && $ratio_h > 1)){ $ratio = $ratio_w < $ratio_h ? $ratio_h : $ratio_w; $tmp_w = (int)($dst_width / $ratio); $tmp_h = (int)($dst_height / $ratio); $tmp_img=imagecreatetruecolor($tmp_w , $tmp_h); $src_x = (int) (($this->src_width-$tmp_w)/2) ; $src_y = (int) (($this->src_height-$tmp_h)/2) ; imagecopy($tmp_img, $this->sImage, 0,0,$src_x,$src_y,$tmp_w,$tmp_h); imagecopyresampled($this->dImage,$tmp_img,0,0,0,0,$dst_width,$dst_height,$tmp_w,$tmp_h); imagedestroy($tmp_img); }else{ $ratio = $ratio_w < $ratio_h ? $ratio_h : $ratio_w; $tmp_w = (int)($this->src_width * $ratio); $tmp_h = (int)($this->src_height * $ratio); $tmp_img=imagecreatetruecolor($tmp_w ,$tmp_h); imagecopyresampled($tmp_img,$this->sImage,0,0,0,0,$tmp_w,$tmp_h,$this->src_width,$this->src_height); $src_x = (int)($tmp_w - $dst_width) / 2 ; $src_y = (int)($tmp_h - $dst_height) / 2 ; imagecopy($this->dImage, $tmp_img, 0,0,$src_x,$src_y,$dst_width,$dst_height); imagedestroy($tmp_img); } break; case 2: // only small if($ratio_w < 1 && $ratio_h < 1){ $ratio = $ratio_w < $ratio_h ? $ratio_h : $ratio_w; $tmp_w = (int)($dst_width / $ratio); $tmp_h = (int)($dst_height / $ratio); $tmp_img=imagecreatetruecolor($tmp_w , $tmp_h); $src_x = (int) ($this->src_width-$tmp_w)/2 ; $src_y = (int) ($this->src_height-$tmp_h)/2 ; imagecopy($tmp_img, $this->sImage, 0,0,$src_x,$src_y,$tmp_w,$tmp_h); imagecopyresampled($this->dImage,$tmp_img,0,0,0,0,$dst_width,$dst_height,$tmp_w,$tmp_h); imagedestroy($tmp_img); }elseif($ratio_w > 1 && $ratio_h > 1){ $dst_x = (int) abs($dst_width - $this->src_width) / 2 ; $dst_y = (int) abs($dst_height -$this->src_height) / 2; imagecopy($this->dImage, $this->sImage,$dst_x,$dst_y,0,0,$this->src_width,$this->src_height); }else{ $src_x=0;$dst_x=0;$src_y=0;$dst_y=0; if(($dst_width - $this->src_width) < 0){ $src_x = (int) ($this->src_width - $dst_width)/2; $dst_x =0; }else{ $src_x =0; $dst_x = (int) ($dst_width - $this->src_width)/2; } if( ($dst_height -$this->src_height) < 0){ $src_y = (int) ($this->src_height - $dst_height)/2; $dst_y = 0; }else{ $src_y = 0; $dst_y = (int) ($dst_height - $this->src_height)/2; } imagecopy($this->dImage, $this->sImage,$dst_x,$dst_y,$src_x,$src_y,$this->src_width,$this->src_height); } break; case 3: // keep all image size and create need size if($ratio_w > 1 && $ratio_h > 1){ $dst_x = (int)(abs($dst_width - $this->src_width )/2) ; $dst_y = (int)(abs($dst_height- $this->src_height)/2) ; imagecopy($this->dImage, $this->sImage, $dst_x,$dst_y,0,0,$this->src_width,$this->src_height); }else{ $ratio = $ratio_w > $ratio_h ? $ratio_h : $ratio_w; $tmp_w = (int)($this->src_width * $ratio); $tmp_h = (int)($this->src_height * $ratio); $tmp_img=imagecreatetruecolor($tmp_w ,$tmp_h); imagecopyresampled($tmp_img,$this->sImage,0,0,0,0,$tmp_w,$tmp_h,$this->src_width,$this->src_height); $dst_x = (int)(abs($tmp_w -$dst_width )/2) ; $dst_y = (int)(abs($tmp_h -$dst_height)/2) ; imagecopy($this->dImage, $tmp_img, $dst_x,$dst_y,0,0,$tmp_w,$tmp_h); imagedestroy($tmp_img); } break; case 4: // keep all image but create actually size if($ratio_w > 1 && $ratio_h > 1){ $this->dImage = imagecreatetruecolor($this->src_width,$this->src_height); imagecopy($this->dImage, $this->sImage,0,0,0,0,$this->src_width,$this->src_height); }else{ $ratio = $ratio_w > $ratio_h ? $ratio_h : $ratio_w; $tmp_w = (int)($this->src_width * $ratio); $tmp_h = (int)($this->src_height * $ratio); $this->dImage = imagecreatetruecolor($tmp_w ,$tmp_h); imagecopyresampled($this->dImage,$this->sImage,0,0,0,0,$tmp_w,$tmp_h,$this->src_width,$this->src_height); } break; } }// end Crop /** * * 裁切方法 * 2016-01-07 15:05:44 * Lixiaoyu * * @param $dst_width 目标长 * @param $dst_height 目标高 * @param $dst_x 裁剪部分和原图左侧的距离 * @param $dst_y 裁剪部分和原图右侧的距离 * @param int $mode 模式 * @param string $dst_file 目标文件路径 */ function Cut($dst_width,$dst_height,$dst_x,$dst_y,$dst_file='') { if ($dst_file) $this->dst_file = $dst_file; //设置目标文件位置 $this->dImage = imagecreatetruecolor($dst_width, $dst_height); //创建了目标文件的大小的画布 $bg = imagecolorallocatealpha($this->dImage, 255, 255, 255, 127); //给画布分配颜色 imagefill($this->dImage, 0, 0, $bg); //给图像用颜色进行填充 imagecolortransparent($this->dImage, $bg); //背景定义成透明色 $ratio_w = 1.0 * $dst_width / $this->src_width; //横向缩放的比例 $ratio_h = 1.0 * $dst_height / $this->src_height; //纵向缩放的比例 //var_dump($this); //不进行缩放,直接对图像进行裁剪 $ratio = 1.0; $tmp_w = (int)($dst_width / $ratio); $tmp_h = (int)($dst_height / $ratio); $tmp_img = imagecreatetruecolor($dst_width, $dst_height); //创建暂时保存的画布 imagecopy($tmp_img, $this->sImage, 0,0,$dst_x,$dst_y,$dst_width,$dst_height); //拷贝出图像的一部分,进行裁切 imagecopyresampled($this->dImage,$tmp_img,0,0,0,0,$dst_width,$dst_height,$tmp_w,$tmp_h); //把暂时缓存的图片,放到目标文件里面 imagedestroy($tmp_img); } } ?> ~~~ ### Use ### 裁剪图像 ~~~ $ic=new ImageCrop($pathToFile,'./pic/afterCrop'.time().'.jpg'); $ic->Cut(40,30,120,130); $ic->SaveImage(); //$ic->SaveAlpha();将补白变成透明像素保存 $ic->destory(); ~~~ ### 实现效果 原图 ![原图](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-03-17_56ea1b297b58e.jpg "") 裁剪之后的图 ![裁剪之后的图](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-03-17_56ea1b298c08c.jpg "") ### 缩放图像 原图 ![原图](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-03-17_56ea1b297b58e.jpg "") 缩略图 ![缩略图](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-03-17_56ea1b29a2f58.jpg "") ### 重点难点 重点在于使用图像处理函数 `imagecopy` 和 `imagecopyresampled` > bool imagecopy ( resource dstim,resourcesrc_im , int dstx,intdst_y , int srcx,intsrc_y , int srcw,intsrc_h ) 将 src_im 图像中坐标从 src_x,src_y 开始,宽度为 src_w,高度为 src_h 的一部分拷贝到 dst_im 图像中坐标为 dst_x 和 dst_y 的位置上。 ### 参考资料 - [http://www.php.net/manual/zh/function.imagecopy.php](http://www.php.net/manual/zh/function.imagecopy.php) - [http://php.net/manual/zh/function.imagecopyresampled.php](http://php.net/manual/zh/function.imagecopyresampled.php)
';

【PHP】PHP转换图片为ico格式源码

最后更新于:2022-04-01 09:56:14

### Class ~~~ <?php namespace App\Libs; class Iconv { function phpmake_ico() { return true; } function GDtoICOstr(&$gd_ico_array) { foreach ($gd_ico_array as $key => $gd_image) { $IcoWidths[$key] = ImageSX($gd_image); $IcoHeights[$key] = ImageSY($gd_image); $bpp[$key] = ImageIsTrueColor($gd_image) ? 32 : 24; $totalcolors[$key] = ImageColorsTotal($gd_image); $icXOR[$key] = ''; for ($y = $IcoHeights[$key] - 1; $y >= 0; $y--) { for ($x = 0; $x < $IcoWidths[$key]; $x++) { $argb = $this->gpc($gd_image, $x, $y); $a = round(255 * ((127 - $argb['alpha']) / 127)); $r = $argb['red']; $g = $argb['green']; $b = $argb['blue']; if ($bpp[$key] == 32) { $icXOR[$key] .= chr($b).chr($g).chr($r).chr($a); } elseif ($bpp[$key] == 24) { $icXOR[$key] .= chr($b).chr($g).chr($r); } if ($a < 128) { @$icANDmask[$key][$y] .= '1'; } else { @$icANDmask[$key][$y] .= '0'; } } while (strlen($icANDmask[$key][$y]) % 32) { $icANDmask[$key][$y] .= '0'; } } $icAND[$key] = ''; foreach ($icANDmask[$key] as $y => $scanlinemaskbits) { for ($i = 0; $i < strlen($scanlinemaskbits); $i += 8) { $icAND[$key] .= chr(bindec(str_pad(substr($scanlinemaskbits, $i, 8), 8, '0', STR_PAD_LEFT))); } } } foreach ($gd_ico_array as $key => $gd_image) { $biSizeImage = $IcoWidths[$key] * $IcoHeights[$key] * ($bpp[$key] / 8); $bfh[$key] = ''; $bfh[$key] .= "\x28\x00\x00\x00"; $bfh[$key] .= $this->le2s($IcoWidths[$key], 4); $bfh[$key] .= $this->le2s($IcoHeights[$key] * 2, 4); $bfh[$key] .= "\x01\x00"; $bfh[$key] .= chr($bpp[$key])."\x00"; $bfh[$key] .= "\x00\x00\x00\x00"; $bfh[$key] .= $this->le2s($biSizeImage, 4); $bfh[$key] .= "\x00\x00\x00\x00"; $bfh[$key] .= "\x00\x00\x00\x00"; $bfh[$key] .= "\x00\x00\x00\x00"; $bfh[$key] .= "\x00\x00\x00\x00"; } $icondata = "\x00\x00"; $icondata .= "\x01\x00"; $icondata .= $this->le2s(count($gd_ico_array), 2); $dwImageOffset = 6 + (count($gd_ico_array) * 16); foreach ($gd_ico_array as $key => $gd_image) { $icondata .= chr($IcoWidths[$key]); $icondata .= chr($IcoHeights[$key]); $icondata .= chr($totalcolors[$key]); $icondata .= "\x00"; $icondata .= "\x01\x00"; $icondata .= chr($bpp[$key])."\x00"; $dwBytesInRes = 40 + strlen($icXOR[$key]) + strlen($icAND[$key]); $icondata .= $this->le2s($dwBytesInRes, 4); $icondata .= $this->le2s($dwImageOffset, 4); $dwImageOffset += strlen($bfh[$key]); $dwImageOffset += strlen($icXOR[$key]); $dwImageOffset += strlen($icAND[$key]); } foreach ($gd_ico_array as $key => $gd_image) { $icondata .= $bfh[$key]; $icondata .= $icXOR[$key]; $icondata .= $icAND[$key]; } return $icondata; } function le2s($number, $minbytes=1) { $intstring = ''; while ($number > 0) { $intstring = $intstring.chr($number & 255); $number >>= 8; } return str_pad($intstring, $minbytes, "\x00", STR_PAD_RIGHT); } function gpc(&$img, $x, $y) { if (!is_resource($img)) { return false; } return @ImageColorsForIndex($img, @ImageColorAt($img, $x, $y)); } } ?> ~~~ ### Controller ~~~ if ( $error['text'] == "" && isset($_FILES['upimage']['tmp_name']) && $_FILES['upimage']['tmp_name'] && is_uploaded_file($_FILES['upimage']['tmp_name'])) { if ($_FILES['upimage']['type'] > 210000) { $error['text'] = "你上传的文件体积超过了限制 最大不能超过200k"; } else { $fileext = array("image/pjpeg", "image/gif", "image/x-png", "image/png", "image/jpeg", "image/jpg"); if (!in_array($_FILES['upimage']['type'], $fileext)) { $error['text'] = "你上传的文件格式不正确 仅支持 jpg,gif,png"; }else { if ($im = @imagecreatefrompng($_FILES['upimage']['tmp_name']) or $im = @imagecreatefromgif($_FILES['upimage']['tmp_name']) or $im = @imagecreatefromjpeg($_FILES['upimage']['tmp_name'])) { $imginfo = @getimagesize($_FILES['upimage']['tmp_name']); if (!is_array($imginfo)) { $error['text'] = "图形格式错误!"; }else { switch ($_POST['size']) { case 1; $resize_im = @imagecreatetruecolor(16, 16); $size = 16; break; case 2; $resize_im = @imagecreatetruecolor(32, 32); $size = 32; break; case 3; $resize_im = @imagecreatetruecolor(48, 48); $size = 48; break; case 4; $resize_im = @imagecreatetruecolor(64, 64); $size = 64; break; case 5; $resize_im = @imagecreatetruecolor(128, 128); $size = 128; break; default; $resize_im = @imagecreatetruecolor(64, 64); $size = 64; break; } imagecopyresampled($resize_im, $im, 0, 0, 0, 0, $size, $size, $imginfo[0], $imginfo[1]); $icon = new Iconv(); $gd_image_array = array($resize_im); $icon_data = $icon->GDtoICOstr($gd_image_array); $filename = "temp/" . date("Ymdhis") . rand(1, 1000) . ".ico"; if (file_put_contents($filename, $icon_data)) { // $output = "生成成功!请点右键->另存为 保存到本地<br><a href="/" mce_href="/""".$filename."/" target=/"_blank/">点击下载</a>"; // echo $filename; //数据展示 $icon_arr=[ 'class'=>'', 'time'=>date("Y-m-d H:i:s"), 'filename'=>$_FILES['upimage']['name'], 'filepath'=>$filename, 'size'=>$size ]; } } } else { $error['text'] = "生成错误请重试"; } } } }else{ $error['text'] = "请选择图片!"; } ~~~ ### 展示效果 ![这里写图片描述](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-03-17_56ea1b2957948.jpg "") ### 源码地址 ico在线转换工具已经集成到了开源项目 [https://github.com/diandianxiyu/ApiTesting](https://github.com/diandianxiyu/ApiTesting) 中 ,在线demo地址稍后再放出 ### 2016年新年快乐!
';

【CURL】PHP的CURL开发项目最佳实践

最后更新于:2022-04-01 09:56:11

### 前言 最近自己做了团队内部的http调试工具,github开源地址 [https://github.com/diandianxiyu/ApiTesting](https://github.com/diandianxiyu/ApiTesting) ,通过这个项目又重新操作了PHP的curl函数,通过本篇博客进行记录,和大家一起学习~ ### Code 本代码通过PHP7环境运行。 ~~~ function curl($url, $method='GET',$fields = [], $headers=[],$auth = false){ //如果是get的获取方式,拼接参数到url上 if($method == "GET"){ $fields_string = http_build_query($fields); $url=$url."?".$fields_string; } $curl = curl_init($url); //初始化 curl_setopt ($curl, CURLOPT_CUSTOMREQUEST, $method ); //设定HTTP请求方式 curl_setopt($curl, CURLOPT_USERAGENT, "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8.1.1) Gecko/20061204 Firefox/2.0.0.1"); curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1); curl_setopt($curl, CURLOPT_VERBOSE, 1); curl_setopt($curl, CURLOPT_HEADER, 1); $header[0] = "Accept: text/xml,application/xml,application/xhtml+xml,"; $header[0] .= "text/html;q=0.9,text/plain;q=0.8,image/png,*/*;q=0.5"; $header[] = "Cache-Control: max-age=0"; $header[] = "Connection: keep-alive"; $header[] = "Keep-Alive: 300"; $header[] = "Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7"; $header[] = "Accept-Language: en-us,en;q=0.5"; $header[] = "Pragma: "; // browsers keep this blank. curl_setopt($curl, CURLOPT_HTTPHEADER, array_merge($header,$headers)); //和参数中的header一起传递过去 if($auth){ curl_setopt($curl, CURLOPT_USERPWD, "$auth"); curl_setopt($curl, CURLOPT_HTTPAUTH, CURLAUTH_BASIC); } if($fields){ //POST if($method == "POST"){//单独对POST方法设置参数传递 $fields_string = http_build_query($fields); curl_setopt($curl, CURLOPT_POST, true); curl_setopt($curl, CURLOPT_BINARYTRANSFER, true); curl_setopt($curl, CURLOPT_POSTFIELDS, $fields_string); }else{ curl_setopt($curl, CURLOPT_RETURNTRANSFER, true) ; curl_setopt($curl, CURLOPT_BINARYTRANSFER, true) ; } } $response = curl_exec($curl); //执行curl $header_size = curl_getinfo($curl, CURLINFO_HEADER_SIZE); $header_string = substr($response, 0, $header_size); $body = substr($response, $header_size); $header_rows = explode(PHP_EOL, $header_string); foreach($header_rows as $key => $value){ $header_rows[$key]=trim($header_rows[$key]); } $i=0; foreach((array)$header_rows as $hr){ $colonpos = strpos($hr, ':'); $key = $colonpos !== false ? substr($hr, 0, $colonpos) : (int)$i++; $headers[$key] = $colonpos !== false ? trim(substr($hr, $colonpos+1)) : $hr; } $j=0; foreach((array)$headers as $key => $val){ $vals = explode(';', $val); if(count($vals) >= 2){ unset($headers[$key]); foreach($vals as $vk => $vv){ $equalpos = strpos($vv, '='); $vkey = $equalpos !== false ? trim(substr($vv, 0, $equalpos)) : (int)$j++; $headers[$key][$vkey] = $equalpos !== false ? trim(substr($vv, $equalpos+1)) : $vv; } } } curl_close($curl); return array($body, $headers); //最终返回 result[0]为body,result[1]为header } ~~~ ### 参考资料 [http://www.php.net/curl](http://www.php.net/curl)
';

【PHP】数组foreach引发的小问题

最后更新于:2022-04-01 09:56:09

### Code ~~~ $arr1 = [ 1, 2, 3, 4, 5 ]; $arr2 = [ 'a', 'b', 'c', 'd', 'e' ]; $arr3 = []; foreach ($arr1 as & $v){ $v += 10; } foreach ($arr2 as $k => $v){ //举例 $v = $v . $arr1[ $k ]; $arr3[ $k ] = $v; } echo implode(', ', $arr1) . "\n" . implode(', ', $arr2) . "\n" . implode(', ', $arr3); ~~~ ### Run ~~~ 11, 12, 13, 14, ee a, b, c, d, e a11, b12, c13, d14, ee ~~~ ### Result 出现问题的原因是第一次循环的结束后,对应的`$v`没有进行释放 ### Solve 在进行循环之前,通过`unset()`,对变量进行释放,就不会出现这个问题了 > 在两次循环之间,添加 unset($v); ~~~ 11, 12, 13, 14, 15 a, b, c, d, e a11, b12, c13, d14, e15 ~~~
';

【翻译】PHP7——新特性

最后更新于:2022-04-01 09:56:07

原文地址: [http://php.net/manual/zh/migration70.new-features.php](http://php.net/manual/zh/migration70.new-features.php) ### 新特性 ### 标量类型声明 标量类型声明 有两种模式: 强制 (默认) 和 严格模式。 现在可以使用下列类型参数(无论用强制模式还是严格模式): 字符串(string), 整数 (int), 浮点数 (float), 以及布尔值 (bool)。它们扩充了PHP5中引入的其他类型:类名,接口,数组和 回调类型 ~~~ <?php // Coercive mode function sumOfInts(int ...$ints) { return array_sum($ints); } var_dump(sumOfInts(2, '3', 4.1)); ~~~ 以上例程会输出: ~~~ int(9) ~~~ 要使用严格模式,一个 declare 声明指令必须放在文件的顶部。这意味着严格声明标量是基于文件可配的。 这个指令不仅影响参数的类型声明,也影响到函数的返回值声明(参见 返回值类型声明, 内置的PHP函数以及扩展中加载的PHP函数) 完整的标量类型声明文档和示例参见类型声明章节。 ### 返回值类型声明 PHP 7 增加了对返回类型声明的支持。 类似于参数类型声明,返回类型声明指明了函数返回值的类型。可用的类型与参数声明中可用的类型相同。 ~~~ <?php function arraysSum(array ...$arrays): array { return array_map(function(array $array): int { return array_sum($array); }, $arrays); } print_r(arraysSum([1,2,3], [4,5,6], [7,8,9])); ~~~ 以上例程会输出: ~~~ Array ( [0] => 6 [1] => 15 [2] => 24 ) ~~~ 完整的标量类型声明文档和示例可参见 返回值类型声明. ### null合并运算符 由于日常使用中存在大量同时使用三元表达式和 isset()的情况, 我们添加了null合并运算符 (??) 这个语法糖。如果变量存在且值不为NULL, 它就会返回自身的值,否则返回它的第二个操作数。 ~~~ <?php // Fetches the value of $_GET['user'] and returns 'nobody' // if it does not exist. $username = $_GET['user'] ?? 'nobody'; // This is equivalent to: $username = isset($_GET['user']) ? $_GET['user'] : 'nobody'; // Coalesces can be chained: this will return the first // defined value out of $_GET['user'], $_POST['user'], and // 'nobody'. $username = $_GET['user'] ?? $_POST['user'] ?? 'nobody'; ?> ~~~ ### 太空船操作符(组合比较符) 太空船操作符用于比较两个表达式。当a大于、等于或小于b时它分别返回-1、0或1。 比较的原则是沿用 PHP 的常规比较规则进行的。 ~~~ <?php // Integers echo 1 <=> 1; // 0 echo 1 <=> 2; // -1 echo 2 <=> 1; // 1 // Floats echo 1.5 <=> 1.5; // 0 echo 1.5 <=> 2.5; // -1 echo 2.5 <=> 1.5; // 1 // Strings echo "a" <=> "a"; // 0 echo "a" <=> "b"; // -1 echo "b" <=> "a"; // 1 ?> ~~~ ### 通过 define() 定义常量数组 Array 类型的常量现在可以通过 definedefine() 来定义。在 PHP5.6 中仅能通过 const 定义。 ~~~ <?php define('ANIMALS', [ 'dog', 'cat', 'bird' ]); echo ANIMALS[1]; // outputs "cat" ?> ~~~ ### 匿名类 现在支持通过new class 来实例化一个匿名类,这可以用来替代一些“用后即焚”的完整类定义 ~~~ <?php interface Logger { public function log(string $msg); } class Application { private $logger; public function getLogger(): Logger { return $this->logger; } public function setLogger(Logger $logger) { $this->logger = $logger; } } $app = new Application; $app->setLogger(new class implements Logger { public function log(string $msg) { echo $msg; } }); var_dump($app->getLogger()); ?> ~~~ 以上例程会输出: ~~~ object(class@anonymous)#2 (0) { } ~~~ 详细文档可以参考 匿名类. ### Unicode codepoint 转译语法 这接受一个以16进制形式的 Unicode codepoint,并打印出一个双引号或heredoc包围的 UTF-8 编码格式的字符串。 可以接受任何有效的 codepoint,并且开头的 0 是可以省略的。 ~~~ echo "\u{aa}"; echo "\u{0000aa}"; echo "\u{9999}"; ~~~ 以上例程会输出: ~~~ ª ª (same as before but with optional leading 0's) 香 ~~~ ### Closure::call() Closure::call() 现在有着更好的性能,简短干练的暂时绑定一个方法到对象上闭包并调用它。 ~~~ <?php class A {private $x = 1;} // Pre PHP 7 code $getXCB = function() {return $this->x;}; $getX = $getXCB->bindTo(new A, 'A'); // intermediate closure echo $getX(); // PHP 7+ code $getX = function() {return $this->x;}; echo $getX->call(new A); ~~~ 以上例程会输出: ~~~ 1 1 ~~~ ### 为unserialize()提供过滤 这个特性旨在提供更安全的方式解包不可靠的数据。它通过白名单的方式来防止潜在的代码注入。 ~~~ <?php // converts all objects into __PHP_Incomplete_Class object $data = unserialize($foo, ["allowed_classes" => false]); // converts all objects into __PHP_Incomplete_Class object except those of MyClass and MyClass2 $data = unserialize($foo, ["allowed_classes" => ["MyClass", "MyClass2"]); // default behaviour (same as omitting the second argument) that accepts all classes $data = unserialize($foo, ["allowed_classes" => true]); ~~~ ### IntlChar 新增加的 IntlChar 类旨在暴露出更多的 ICU 功能。这个类自身定义了许多静态方法用于操作多字符集的 unicode 字符。 ~~~ <?php printf('%x', IntlChar::CODEPOINT_MAX); echo IntlChar::charName('@'); var_dump(IntlChar::ispunct('!')); ~~~ 以上例程会输出: ~~~ 10ffff COMMERCIAL AT bool(true) ~~~ 若要使用此类,请先安装Intl扩展 ### 预期 预期是向后兼用并增强之前的 assert() 的方法。 它使得在生产环境中启用断言为零成本,并且提供当断言失败时抛出特定异常的能力。 老版本的API出于兼容目的将继续被维护,assert()现在是一个语言结构,它允许第一个参数是一个表达式,而不仅仅是一个待计算的 string或一个待测试的boolean。 ~~~ <?php ini_set('assert.exception', 1); class CustomError extends AssertionError {} assert(false, new CustomError('Some error message')); ?> ~~~ 以上例程会输出: ~~~ Fatal error: Uncaught CustomError: Some error message ~~~ 关于这个特性的完整说明,包括如何在开发和生产环境中配置它,可以在assert()的 expectations section章节找到。 ### Group use declarations 从同一 namespace 导入的类、函数和常量现在可以通过单个 use 语句 一次性导入了。 ~~~ <?php // Pre PHP 7 code use some\namespace\ClassA; use some\namespace\ClassB; use some\namespace\ClassC as C; use function some\namespace\fn_a; use function some\namespace\fn_b; use function some\namespace\fn_c; use const some\namespace\ConstA; use const some\namespace\ConstB; use const some\namespace\ConstC; // PHP 7+ code use some\namespace\{ClassA, ClassB, ClassC as C}; use function some\namespace\{fn_a, fn_b, fn_c}; use const some\namespace\{ConstA, ConstB, ConstC}; ?> ~~~ ### Generator Return Expressions 此功能是建立在引入PHP5.5发电机的功能。它能够为要在发电机内使用,以便为最终的表达式返回return语句(返回引用是不允许的)。该值可以使用新的发电机:: getReturn()方法,该方法只能使用一次发电机已完成收益值是牵强。 ~~~ <?php $gen = (function() { yield 1; yield 2; return 3; })(); foreach ($gen as $val) { echo $val, PHP_EOL; } echo $gen->getReturn(), PHP_EOL; ~~~ 以上例程会输出: ~~~ 1 2 3 ~~~ 能够从发电机明确地返回一个最终值是有一个方便的能力。这是因为它使供到由发电机被返回(从或许某种形式的协程计算),可以通过执行发生器客户代码进行具体处理的最终值。这比迫使客户端代码首先检查最终值是否已经产生了,然后如果是这样,专门负责处理该值简单。 ### Generator delegation 发电机现在可以委托给另一发生器,自动位移对象或数组,而无需使用来自结构屈服编写样板在最外面的发电机。 ~~~ <?php function gen() { yield 1; yield 2; yield from gen2(); } function gen2() { yield 3; yield 4; } foreach (gen() as $val) { echo $val, PHP_EOL; } ?> ~~~ 以上例程会输出: ~~~ 1 2 3 4 ~~~ ### Integer division with intdiv() 新intdiv()函数执行的操作数的整数除法并返回。 ~~~ <?php var_dump(intdiv(10, 3)); ?> ~~~ 以上例程会输出: ~~~ int(3) ~~~ ### Session options 在session_start()现在接受的选项,覆盖在php.ini中通常设置会话配置指令的数组。 这些选项也得到了扩展,以支持session.lazy_write,这是在默认情况下并导致PHP只覆盖任何会话文件,如果会话数据已经改变,read_and_close,这是一个只能传递给在session_start()的选项,以表明会话数据应该读,然后会议应立即关闭不变。 例如,要session.cache_limiter设置为私有,并立即阅读后关闭会话: ~~~ <?php session_start([ 'cache_limiter' => 'private', 'read_and_close' => true, ]); ?> ~~~ ### preg_replace_callback_array() 新preg_replace_callback_array()函数使代码编写更干净使用preg_replace_callback()函数时。在此之前PHP7,这需要每个正则表达式执行回调需要回调函数被污染,有很多分支。 现在,回调可以注册使用一个关联数组,其中最关键的是一个正则表达式的值是一个回调的每个正则表达式。 ### CSPRNG Functions 两个新的功能已被添加到生成加密安全整数和字符串的跨平台的方式:random_bytes()和random_int()。 ### list() can always unpack objects implementing ArrayAccess 此前,列表()是不能保证与实施了ArrayAccess对象的正常运行。这已得到修复。
';

【PHP】编译安装 PHP5.6.13遇到问题以及解决方案

最后更新于:2022-04-01 09:56:04

### 问题 在执行 `./configure`的时候报错 > configure: error: xml2-config not found. Please check your libxml2 installation. ### 解决 `yum install libxml2-devel` ### 问题 在执行 `make && make install`的时候遇到的问题 > virtual memory exhausted: 无法分配内存 make: *** [ext/fileinfo/libmagic/apprentice.lo] 错误 1 ### 解决 这是内存不够1g 的时候出现的问题。。。。。。 > ./configure --disable-fileinfo ### 参考资料 - [http://segmentfault.com/q/1010000000260961](http://segmentfault.com/q/1010000000260961) - [http://wudi.in/archives/284.html](http://wudi.in/archives/284.html)
';

【PHP】PHP5.4.0版本ChangeLog详解(上)

最后更新于:2022-04-01 09:56:02

### 前言 随着大量的框架使用composer和namespace,渐渐的线上环境也从之前的5.3变成了5.4或者5.5甚至5.6,随着7月份PHP7的发布,会有更多的公司采用新版本。 之前好久就想写这样的一片文章,来说明下各个版本的差异,这次算是拿出时间了。 这次的是第一篇,目前规划写三篇 - PHP5.4.0 - PHP5.5.0 - PHP5.6.0 一方面是对自己的知识的整理,一方面是对自己的一次提升。 ### 官方说明 官方文档地址 [http://php.net/ChangeLog-5.php#5.4.0](http://php.net/ChangeLog-5.php#5.4.0) ### 详细说明 ### 01 Mar 2012 原文 > autoconf 2.59+ is now supported (and required) for generating the configure script with ./buildconf. Autoconf 2.60+ is desirable otherwise the configure help order may be incorrect. 翻译 > autoconf 2.59 +现在支持(需要)生成配置脚本/ buildconf。autoconf 2.60 +是理想的配置,否则有可能是不正确的。 ### autoconf php编译安装的时候需要的依赖软件,所以新版本对应配套的软件也要换成最新的对性能来讲才保险啊~ ### Removed legacy features 移除的特性 原文 > - break/continue $var syntax. > - Safe mode and all related ini options. > - register_globals and register_long_arrays ini options. > - import_request_variables(). > - allow_call_time_pass_reference. > - define_syslog_variables ini option and its associated function. > - highlight.bg ini option. > - Session bug compatibility mode (session.bug_compat_42 and session.bug_compat_warn ini options). > - session_is_registered(), session_register() and session_unregister() functions. > - y2k_compliance ini option. > - magic_quotes_gpc, magic_quotes_runtime and magic_quotes_sybase ini options. get_magic_quotes_gpc, get_magic_quotes_runtime are kept but always return false, set_magic_quotes_runtime raises an E_CORE_ERROR. > - Removed support for putenv(“TZ=..”) for setting the timezone. > - Removed the timezone guessing algorithm in case the timezone isn’t set with date.timezone or date_default_timezone_set(). Instead of a guessed timezone, “UTC” is now used instead. 翻译 > - break/continue$ var语法。 > - 安全模式和所有相关的INI选项。 > - register_globals和register_long_arrays INI选项。 > - import_request_variables()。 > - allow_call_time_pass_reference。 > - define_syslog_variables INI选项及其相关的功能。 > - highlight.bg INI选项。 > - 会话错误兼容模式(session.bug_compat_42和session.bug_compat_warn INI选项)。 > - session_is_registered(),session_register()和session_unregister()功能。 > - y2k_compliance INI选项。 > - magic_quotes_gpc,magic_quotes_runtime和magic_quotes_sybase INI选项。get_magic_quotes_gpc,get_magic_quotes_runtime保存但始终返回false,set_magic_quotes_runtime引发e_core_error。 > - 不再支持putenv(“TZ = ..”)设置时区。 > - 如果不设置时区与时区date.timezone或date_default_timezone_set()除去猜测算法。而不是猜测的时区,“UTC”现在是用来代替。 我是拿百度翻译来的我会乱说吗? =_= ### break/continue 移除了break/continue $var语法 在5.4之前,我们可以通过传递后面的参数来控制跳出或者停止若干层的循环,然而在5.4.0的版本之后,就去除了这个特性。 ~~~ break $c; continue $c; ~~~ > break and continue accepts a number, that specify the number of nested loops, that should be breaked up, or continued. 参考资料 - [http://stackoverflow.com/questions/6517401/what-is-the-break-continue-var-syntax-will-be-removed-in-php-5-4](http://stackoverflow.com/questions/6517401/what-is-the-break-continue-var-syntax-will-be-removed-in-php-5-4) - [http://php.net/control-structures.break](http://php.net/control-structures.break) ### Safe mode and all related ini options. 去除安全模式以及在配置文件的选项 PHP 的安全模式是为了试图解决共享服务器(shared-server)安全问题而设立的。在结构上,试图在 PHP 层上解决这个问题是不合理的,但修改 web 服务器层和操作系统层显得非常不现实。因此许多人,特别是 ISP,目前使用安全模式。 语言的发展是在不断的进步的啊,也是一个不断试错改错的过程。^_^ - 保安措施和安全模式,也就是移除了php.ini中所有safe_mode相关的配置项 - 被安全模式限制或屏蔽的函数 。 在安全限制模式下,有些函数不能被使用。这个限制也将被移除 参考资料 - [http://php.net/manual/zh/features.safe-mode.php](http://php.net/manual/zh/features.safe-mode.php) ### register_globals and register_long_arrays ini options. 这两个配置项因为性能关系被移除了。 参考资料 - [http://php.net/manual/zh/ini.core.php#ini.register-globals](http://php.net/manual/zh/ini.core.php#ini.register-globals) ### import_request_variables() >import_request_variables — 将 GET/POST/Cookie 变量导入到全局作用域中 >bool import_request_variables ( string types[,stringprefix ] ) 将 GET/POST/Cookie 变量导入到全局作用域中。如果你禁止了 register_globals,但又想用到一些全局变量,那么此函数就很有用。 > 你可以使用 types 参数指定需要导入的变量。可以用字母‘G’、‘P’和‘C’分别表示 GET、POST 和 Cookie。这些字母不区分大小写,所以你可以使用‘g’、‘p’和‘c’的任何组合。POST 包含了通过 POST 方法上传的文件信息。注意这些字母的顺序,当使用“gp”时,POST 变量将使用相同的名字覆盖 GET 变量。任何 GPC 以外的字母都将被忽略。 > prefix 参数作为变量名的前缀,置于所有被导入到全局作用域的变量之前。所以如果你有个名为“userid”的 GET 变量,同时提供了“pref_”作为前缀,那么你将获得一个名为 $pref_userid 的全局变量。 > 如果你对导入其它全局变量(例如 SERVER 变量)感兴趣,请考虑使用 extract()。 参考资料 - [http://php.net/manual/zh/function.import-request-variables.php](http://php.net/manual/zh/function.import-request-variables.php) ### allow_call_time_pass_reference > 是否启用在函数调用时强制参数被按照引用传递。此方法已不被赞成并在 PHP/Zend 未来的版本中很可能不再支持。鼓励使用的方法是在函数定义中指定哪些参数应该用引用传递。鼓励大家尝试关闭此选项并确保脚本能够正常运行,以确保该脚本也能在未来的版本中运行(每次使用此特性都会收到一条警告,参数会被按值传递而不是按照引用传递)。 > 在函数调用时通过引用传递参数是不推荐的,因为它影响到了代码的整洁。如果函数的参数没有声明作为引用传递,函数可以通过未写入文档的方法修改其参数。要避免其副作用,最好仅在函数声明时指定那个参数需要通过引用传递。 参考资料 - [http://php.net/manual/zh/ini.core.php#ini.allow-call-time-pass-reference](http://php.net/manual/zh/ini.core.php#ini.allow-call-time-pass-reference) - [http://blog.csdn.net/shimch/article/details/630158](http://blog.csdn.net/shimch/article/details/630158) ### define_syslog_variables 初始化syslog相关的设置项,从这个版本进行了移除。 > define_syslog_variables()只定义了全局变量。常数已经永远的定义,如果日志模块加载。你*do not*需要调用这个使用syslog常数。 也就是我们如果想要使用syslog相关的参数,直接调用就行,不需要进行手动初始化。 参考资料 - [http://cn2.php.net/manual/zh/function.define-syslog-variables.php](http://cn2.php.net/manual/zh/function.define-syslog-variables.php) ### highlight.bg ini option. > Colors for Syntax Highlighting mode. Anything that’s acceptable in would work. 和这个高亮相关配置项还有下面几个,对代码高亮的颜色进行配置 - highlight.comment - highlight.default - highlight.html - highlight.keyword - highlight.string 参考资料 - [http://php.net/manual/en/misc.configuration.php#ini.syntax-highlighting](http://php.net/manual/en/misc.configuration.php#ini.syntax-highlighting) ### Session bug compatibility mode > php.ini中有说明 这是php4.3.0以后才有的安全设置。 出于安全的考虑php不建议你打开register_globals开关 但若关闭了register_globals(默认)时,session变量将不被自动转换成全局变量 此时传统的session变量注册方式session_register就失去意义了(session_register是把一个全局变量注册成session变量),因为访问session变量需要使用SESSION数组。因此只需直接操作_SESSION数组就可以了,而无须再用session_register注册了。以免产生混乱 > 开关session.bug_compat_42 和 session.bug_compat_warn 就是为了检查此类情况而设置的 参考资料 - [http://bbs.csdn.net/topics/40340235](http://bbs.csdn.net/topics/40340235) ### session_is_registered(), session_register() and session_unregister() functions. 这里提到的三个session相关的函数 - session_is_registered() - session_register() - session_unregister() 这些是session相关的注册相关的函数。 *参考资料* - [http://php.net/manual/en/function.session-is-registered.php](http://php.net/manual/en/function.session-is-registered.php) - [http://php.net/manual/en/function.session-register.php](http://php.net/manual/en/function.session-register.php) - [http://php.net/manual/en/function.session-unregister.php](http://php.net/manual/en/function.session-unregister.php) ### y2k_compliance ini option. 这。。。是关于2000的时候的千年虫的配置项。 参考资料 - [http://www.bkjia.com/PHPjc/852740.html](http://www.bkjia.com/PHPjc/852740.html) ### magic_quotes_gpc magic_quotes_gpc,magic_quotes_runtime和magic_quotes_sybase INI选项。get_magic_quotes_gpc,get_magic_quotes_runtime保存但始终返回false,set_magic_quotes_runtime引发e_core_error。 这个配置被撤销之后,如果再使用就会引发错误。 ### Removed support for putenv(“TZ=..”) for setting the timezone 不再支持putenv(“TZ = ..”)设置时区,也就是不能再通过这个函数来设置时区相关的环境配置了. > 添加 setting 到服务器环境变量。 环境变量仅存活于当前请求期间。 在请求结束时环境会恢复到初始状态。 > 设置特定的环境变量也有可能是一个潜在的安全漏洞。 safe_mode_allowed_env_vars 包含了一个以逗号分隔的前缀列表。 在安全模式下,用户可以仅能修改用该指令设定的前缀名称的指令。 默认情况下,用户仅能够修改以 PHP_ 开头的环境变量(例如 PHP_FOO=BAR)。 注意:如果此指令是空的,PHP允许用户设定任意环境变量! 可见这个函数真是危险啊。。。 参考资料 - [http://php.net/manual/zh/function.putenv.php](http://php.net/manual/zh/function.putenv.php) ~~~ Removed the timezone guessing algorithm in case the timezone isn’t set with date.timezone or date_default_timezone_set(). Instead of a guessed timezone, “UTC” is now used instead. ~~~ 如果不设置时区与时区date.timezone或date_default_timezone_set()除去猜测算法。而不是猜测的时区,“UTC”现在是用来代替。 > date_default_timezone_set() 设定用于所有日期时间函数的默认时区。 > Note: 自 PHP 5.1.0 起(此版本日期时间函数被重写了),如果时区不合法则每个对日期时间函数的调用都会产生一条 E_NOTICE 级别的错误信息,如果使用系统设定或 TZ 环境变量则还会产生 E_STRICT 级别的信息。 参考资料 - [http://php.net/manual/zh/function.date-default-timezone-set.php](http://php.net/manual/zh/function.date-default-timezone-set.php) ### Moved extensions to PECL 移动扩展PECL 原文 - ext/sqlite. (Note: the ext/sqlite3 and ext/pdo_sqlite extensions are not affected) 翻译 - EXT / SQLite。(注:EXT / sqlite3和EXT / pdo_sqlite扩展不受影响) ### ext/sqlite > This package is not maintained anymore and has been superseded. Package has moved to channel [http://php.net/sqlite](http://php.net/sqlite), package . 这个包是不是保持了与已被取代。包已经转移到渠道[http://php.net/sqlite](http://php.net/sqlite),包。 也就是说这个sqlite从pecl转移到了SQLite的扩展中。 参考资料 - [http://pecl.php.net/package/SQLite](http://pecl.php.net/package/SQLite) - [http://php.net/sqlite](http://php.net/sqlite) ### General improvements 一般的改进 原文 - Added short array syntax support ([1,2,3]), see UPGRADING guide for full details. - Added binary numbers format (0b001010). - Added support for Class::{expr}() syntax. - Added multibyte support by default. Previously php had to be compiled with –enable-zend– multibyte. Now it can be enabled or disabled through zend.multibyte directive in php.ini. - Removed compile time dependency from ext/mbstring. - Added support for Traits. - Added closure $this support back. - Added array dereferencing support. - Added callable typehint. - Added indirect method call through array. #47160. - Added DTrace support. - Added class member access on instantiation (e.g. (new foo)->bar()) support. - `<?=`is now always available regardless of the short_open_tag setting. - Implemented Zend Signal Handling (configurable option –enable-zend-signals, off by default). - Improved output layer, see README.NEW-OUTPUT-API for internals. - lmproved unix build system to allow building multiple PHP binary SAPIs and one SAPI module the same time. #53271, #52419. - Implemented closure rebinding as parameter to bindTo. - Improved the warning message of incompatible arguments. - Improved ternary operator performance when returning arrays. - Changed error handlers to only generate docref links when the docref_root INI setting is not empty. - Changed silent conversion of array to string to produce a notice. - Changed default value of “default_charset” php.ini option from ISO-8859-1 to UTF-8. - Changed silent casting of null/”/false into an Object when adding a property into a warning. - Changed E_ALL to include E_STRICT. - Disabled windows CRT warning by default, can be enabled again using the ini directive windows_show_crt_warnings. - Fixed bug #55378: Binary number literal returns float number though its value is small enough. 翻译 - 添加短数组语法支持([1,2,3]),详情见升级指南。 - 添加二进制格式(0b001010)。 - 增加支持类::{ }()表达式的语法。 - 添加多字节默认支持。以前的PHP必须编译——使Zend字节。现在可以启用或禁用通过zend.multibyte指令在php.ini。 - 从EXT / mbstring编译时依赖。 - 增加支持的特征。 - 添加关闭美元的支持。 - 添加数组引用的支持。 - 添加可赎回typehint。 - 增加间接方法调用通过阵列。# 47160。 - 加入DTrace支持。 - 添加类成员访问实例(例如(新富)-> bar())支持。 - `<?=`永远是现在可用的short_open_tag设置。 - 实现Zend信号处理(可配置的选项——启用Zend信号,默认关闭)。 - 改进的输出层,看到readme.new-output-api内部。 - 改进的UNIX系统允许建立建设多个PHP二进制SAPIs和SAPI模块相同的时间。# 53271,# 52419。 - 实施关闭绑定参数的结合。 - 改进的相互矛盾的警告信息。 - 三元运算符返回时阵列性能改进。 - 改变错误处理程序只产生docref链接时,docref_root ini设置不空。 - 改变数组字符串生成通知无声的转换。 - 改变默认值“default_charset”的选项从ISO-8859-1为UTF-8。 - 改变沉默铸造空/”/假为对象添加属性到一个警告。 - 改变e_all包括e_strict。 - 禁用Windows CRT警告默认情况下,可以再次启用使用INI指令windows_show_crt_warnings。 - 固定的错误# 55378:二进制数的文本返回浮点数的值足够小,虽然。 *发现这么翻译还不如不翻译看的明白。。。。* ### short array syntax support 短数组支持 ~~~ <?php $array = array( "foo" => "bar", "bar" => "foo", ); // 自 PHP 5.4 起 $array = [ "foo" => "bar", "bar" => "foo", ]; ?> ~~~ 参考资料 - [http://cn.php.net/manual/zh/language.types.array.php](http://cn.php.net/manual/zh/language.types.array.php) ### binary numbers format 二进制直接量 从PHP5.4开始, 我们可以直接在代码中书写二进制直接量了. 这个在定义一些标志位的时候, 尤为方便. ~~~ $bin = 0b1101; echo $bin; //13 ~~~ 参考资料 - [http://www.laruence.com/2011/10/10/2232.html](http://www.laruence.com/2011/10/10/2232.html) ### support for Class::{expr}() syntax Makes PHP more flexible, when calling class/object methods. ~~~ $method = 'method'; $test = new Test(); $test->method(); $test->$method(); $test->{'method'}(); Test::method(); Test::$method(); Test::{'method'}(); ~~~ 参考资料 - [http://yogurt.iteye.com/blog/1447483](http://yogurt.iteye.com/blog/1447483) ### multibyte support 多字节支持 添加多字节默认支持。以前的PHP必须编译——使Zend字节。现在可以启用或禁用通过zend.multibyte指令在php.ini。 参考资料 - [http://www.laruence.com/2011/11/18/2305.html](http://www.laruence.com/2011/11/18/2305.html) - [http://serverfault.com/questions/145413/php-what-is-enable-zend-multibyte-configure-option-for](http://serverfault.com/questions/145413/php-what-is-enable-zend-multibyte-configure-option-for) ### Removed compile time dependency from ext/mbstring 从EXT / mbstring编译时依赖 ### Added support for *Traits * > 自 PHP 5.4.0 起,PHP 实现了代码复用的一个方法,称为 traits。 > Traits 是一种为类似 PHP 的单继承语言而准备的代码复用机制。Trait 为了减少单继承语言的限制,使开发人员能够自由地在不同层次结构内独立的类中复用方法集。Traits 和类组合的语义是定义了一种方式来减少复杂性,避免传统多继承和混入类(Mixin)相关的典型问题。 > Trait 和一个类相似,但仅仅旨在用细粒度和一致的方式来组合功能。Trait 不能通过它自身来实例化。它为传统继承增加了水平特性的组合;也就是说,应用类的成员不需要继承 参考资料 - [http://php.net/manual/zh/language.oop5.traits.php](http://php.net/manual/zh/language.oop5.traits.php) ### Added closure $this support back > 用于代表 匿名函数 的类. > 匿名函数(在 PHP 5.3 中被引入)会产生这个类型的对象。在过去,这个类被认为是一个实现细节,但现在可以依赖它做一些事情。自 PHP 5.4 起,这个类带有一些方法,允许在匿名函数创建后对其进行更多的控制。 > 除了此处列出的方法,还有一个 __invoke 方法。这是为了与其他实现了 __invoke()魔术方法 的对象保持一致性,但调用匿名函数的过程与它无关。 待续。。 参考资料 - [http://php.net/manual/zh/class.closure.php](http://php.net/manual/zh/class.closure.php) - [http://stackoverflow.com/questions/5734011/php-5-4-closure-this-support](http://stackoverflow.com/questions/5734011/php-5-4-closure-this-support) - [https://eval.in/private/f2fb0986b99669](https://eval.in/private/f2fb0986b99669) - [https://wiki.php.net/rfc/closures](https://wiki.php.net/rfc/closures) ### Added array dereferencing support 可以说上是直接获取数组中的元素吧,对于我们来说还是很方便的,能省下一个变量。 > 在以前, 我们如果定义一个返回数组的函数: ~~~ <?php function foo() { return array(1, 2, 3); } ~~~ > 那么, 如果我要获取返回数组中的第二个元素, 就只能: ~~~ <?php list(, $mid, ) = foo(); //或者: $tmp = $foo(); $mid = $tmp[1]; ~~~ > 而从5.4开始, 我们就不需要这么麻烦了, 只需要: ~~~ <?php $mid = foo()[1]; ~~~ > 另外, 也可以使用引用: ~~~ <?php function &getTable() { return $GLOBALS; } getTable()["foo"] = "laruence"; echo $foo; //laruence ~~~ 参考资料 - [http://www.laruence.com/2011/10/10/2212.html](http://www.laruence.com/2011/10/10/2212.html) ### 函数类型提示(Callable typehint) 要想了解这个首先需要了解的是类型约束 > PHP 5 可以使用类型约束。函数的参数可以指定必须为对象(在函数原型里面指定类的名字),接口,数组(PHP 5.1 起)或者 callable(PHP 5.4 起)。不过如果使用 NULL 作为参数的默认值,那么在调用函数的时候依然可以使用 NULL 作为实参。 > 如果一个类或接口指定了类型约束,则其所有的子类或实现也都如此。 > 类型约束不能用于标量类型如 int 或 string。Traits 也不允许 ~~~ /** * 测试函数 * 第一个参数必须为 OtherClass 类的一个对象 */ public function test(OtherClass $otherclass) { echo $otherclass->var; } ~~~ 其中的OtherClass 就是我们的类型约束 在PHP5.4版本中,新增了Callable类型的类型约束 ~~~ <?php function foo(callable $callback) { } ~~~ ~~~ <?php foo("false"); //Catchable fatal error: Argument 1 passed to foo() must be callable * foo("printf"); //okey foo(function(){}); //okey class A { static function show() { } } foo(array("A", "show")); //okey ~~~ 参考资料 - [http://www.laruence.com/2011/10/10/2229.html](http://www.laruence.com/2011/10/10/2229.html) - [http://www.laruence.com/2011/07/02/2102.html](http://www.laruence.com/2011/07/02/2102.html) - [http://php.net/manual/zh/language.oop5.typehinting.php](http://php.net/manual/zh/language.oop5.typehinting.php) ### indirect method call through array 通过间接方法调用的数组 这里在后面还有一个#47160的bug. ~~~ <?php // For 5.2.x as well. class Thing { static function DoesStuff() { echo 'Hello, World'; } } $f = array('Thing', 'DoesStuff'); $f(); //返回 Hello, World ?> ~~~ 按照bug页面上的,之前的版本就会返回错误,现在已经好啦~ ~~~ <?php class Hello { //这是一个静态的方法 static public function world($x) { echo "Hello, $x\n"; } } function hello_world($x) { echo "Hello, $x\n"; } //数组中包含了三个,第一个数组,第二个匿名函数,第三个字符串 $callbacks = array( array('Hello', 'world'), function ($x) { echo "Hello, $x\n"; }, 'hello_world' ); //循环了数组 foreach ($callbacks as $k => $callback) { if (is_callable($callback)) { //检测参数是否为合法的可调用结构 $callback($k); //然后就把自己的key值作为参数传递过去了 } } //RESULT: //Hello, 0 指向了Hello的world静态方法 //Hello, 1 参数本身就是匿名函数,是可以直接执行的 //Hello, 2 作为字符串的参数可以找到相同名字的方法,所以执行了 //CalvinLee ?> ~~~ 上面的第一个栗子说明了我们可以通过数组的形式直接调用方法,确认回调函数,通过`array('类','方法')`的方式进行直接调用。 这是一个因为bug造成的新特性。 参考资料 - [https://bugs.php.net/bug.php?id=47160](https://bugs.php.net/bug.php?id=47160) - [https://wiki.php.net/rfc/indirect-method-call-by-array-var](https://wiki.php.net/rfc/indirect-method-call-by-array-var) - [http://php.net/manual/zh/function.is-callable.php](http://php.net/manual/zh/function.is-callable.php) ### DTrace 支持 > DTrace(全称Dynamic Tracing),也称为动态跟踪,是由 Sun™ 开发的一个用来在生产和试验性生产系统上找出系统瓶颈的工具,可以对内核(kernel)和用户应用程序(user application)进行动态跟踪并且对系统运行不构成任何危险的技术。在任何情况下它都不是一个调试工具, 而是一个实时系统分析寻找出性能及其他问题的工具。 也就是这个调试工具可以直接支持PHP辣!可以进行更深层次的代码调试。 有时间可以研究一下这个怎么用。 。。。 参考资料 - [https://blogs.oracle.com/shanti/entry/dtrace_support_for_php](https://blogs.oracle.com/shanti/entry/dtrace_support_for_php) - [http://php.net/manual/zh/features.dtrace.dtrace.php](http://php.net/manual/zh/features.dtrace.dtrace.php) - [http://baike.baidu.com/view/3223769.htm](http://baike.baidu.com/view/3223769.htm) - [http://blog.experimentalworks.net/2010/04/php-5-3-99-dev-and-dtrace-part-i/](http://blog.experimentalworks.net/2010/04/php-5-3-99-dev-and-dtrace-part-i/) ### 在实例化类成员的访问支持 ~~~ class Test { public function foo() { return $this; } public function bar() { return 'oh hai'; } } $t = (new Test)->foo(); print $t->bar(); ~~~ 我们可以直接调用啦啦啦~ 很方便的样子! 参考资料 - [http://stackoverflow.com/questions/9551251/php-class-member-access-on-instantiation](http://stackoverflow.com/questions/9551251/php-class-member-access-on-instantiation) ### <?= 短标签 PHP5.4里默认开启了短标签设置,支持了行内的短标签 `<?= ?>` ~~~ <?php $a = 2; ?> <?=$a?> ~~~ 这个短标签直接输出了,所以是用于行内的。 参考资料 - [http://php.net/manual/zh/language.basic-syntax.phptags.php](http://php.net/manual/zh/language.basic-syntax.phptags.php) ### Zend Signal Handling 实现Zend Signal Handling(可配置的选项——–enable-zend-signals,默认关闭) > 新的机制, 叫做zend signal, 它的理念, 来自Yahoo的”延迟信号处理”(Yahoo signal deferring mechanism), 而后, facebook把这套理念加入了PHP中, 为了提升PHP+Apache 1.X下PHP调用ap_block/ap_unblock的性能 参考资料 - [http://www.laruence.com/2011/10/19/2247.html](http://www.laruence.com/2011/10/19/2247.html) - [http://www.laruence.com/2008/12/31/647.html](http://www.laruence.com/2008/12/31/647.html) - [http://www.laruence.com/2011/01/27/1854.html](http://www.laruence.com/2011/01/27/1854.html) - [https://wiki.php.net/rfc/zendsignals](https://wiki.php.net/rfc/zendsignals) ### Improved output layer, see README.NEW-OUTPUT-API for internals 改进的输出层,看到readme.new-output-api内部 看起来像是内核的输出层改动,但是实在是找不到资料,不知道怎么理解这一条。QAQ ### multiple PHP binary SAPIs and one SAPI module 多个PHP二进制SAPIs和SAPI模块 改进的UNIX系统允许建立建设多个PHP二进制SAPIs和SAPI模块相同的时间。#53271, #52419. 这里在后面提到了两个bug。 > Using configure options –enable-cgi and –enable-fpm together will not produce the php-cgi binary. 两个配置一起的时候就不会产生php-cgi的二进制。 两个模块作为配置项的时候会编译失败。 参考资料 - [https://bugs.php.net/bug.php?id=53271](https://bugs.php.net/bug.php?id=53271) - [https://bugs.php.net/bug.php?id=52419](https://bugs.php.net/bug.php?id=52419) - [http://php.net/manual/en/install.pecl.php-config.php](http://php.net/manual/en/install.pecl.php-config.php) - [http://blog.sina.com.cn/s/blog_7cc2d3440100v6mf.html](http://blog.sina.com.cn/s/blog_7cc2d3440100v6mf.html) - [http://php.find-info.ru/php/016/ch23lev1sec1.html](http://php.find-info.ru/php/016/ch23lev1sec1.html) - [http://www.cnblogs.com/zl0372/articles/php_17.html](http://www.cnblogs.com/zl0372/articles/php_17.html) - [http://www.laruence.com/2008/08/12/180.html](http://www.laruence.com/2008/08/12/180.html) ### Implemented closure rebinding as parameter to bindTo 实施关闭重新绑定的参数结合 > Closure::bind — 复制一个闭包,绑定指定的$this对象和类作用域。 Closures: Object extension 关闭对象扩展 这里需要理解一个Closure的概念,Closure 类,匿名函数类。 > 匿名函数(在 PHP 5.3 中被引入)会产生这个类型的对象。在过去,这个类被认为是一个实现细节,但现在可以依赖它做一些事情。自 PHP 5.4 起,这个类带有一些方法,允许在匿名函数创建后对其进行更多的控制 ~~~ <?php class APP { public $var = 25; public function __construct() { } public function get($callback) { if (!is_callable($callback)) { throw new InvalidArgumentException('Paran must be callable.'); } // $callback->bindTo($this); // $callback->bindTo($this, $this); // $callback(); //上面的回调方法找不到绑定的对象,下面的方法是用一个新的变量来做绑定函数的结果,然后执行 $callback1 = $callback->bindTo($this, $this); $callback1(); } } $app = new APP(); $app->get(function() use ($app) {//作为自己的匿名函数 echo '<pre>'; var_dump($app); echo '<br />'; var_dump($this); }); ?> ~~~ 参考资料 - [http://blog.csdn.net/iefreer/article/details/8927045](http://blog.csdn.net/iefreer/article/details/8927045) - [http://php.net/manual/zh/closure.bindto.php](http://php.net/manual/zh/closure.bindto.php) - [http://php.net/manual/zh/closure.bind.php](http://php.net/manual/zh/closure.bind.php) - [https://wiki.php.net/rfc/closures](https://wiki.php.net/rfc/closures) ### Improved the warning message of incompatible arguments 改进的不兼容的参数的警告信息 就是字面上的意思。。。 ### Improved ternary operator performance when returning arrays 三元运算符返回时数组性能改进 优化了数组的时候的性能,当返回值是array的时候速度得到了提升。 参考资料 - [http://www.laruence.com/2011/11/04/2258.html](http://www.laruence.com/2011/11/04/2258.html) - [http://grokbase.com/t/php/php-internals/11aeyhp2ek/ternary-operator-performance-improvements](http://grokbase.com/t/php/php-internals/11aeyhp2ek/ternary-operator-performance-improvements) - [http://php.net/manual/en/language.operators.comparison.php](http://php.net/manual/en/language.operators.comparison.php) ### Changed error handlers 改变错误处理程序只产生docref链接时,docref_root ini设置不空 当配置文件 php.ini 中的 docref_root 的值为空的时候,更改了 docref links 指向的链接。 也就是对默认的指向的错误提醒的页面连接进行了修改. 修改默认值不属于很重要的功能,对于这种更新对项目来说不是特别的重要。 > 新的错误信息格式包含了对应的参考页面,该页面对错误进行具体描述,或者描述了导致该错误发生的函数。为了提供手册的页面,你可以在PHP官方站点下载对应语言的手册,并在ini中设置网址到本地对应的地址。如果你的本地手册拷贝可以使用”/manual/” 访问,你就可以简单的设置 docref_root=/manual/。另外你还需要设置 docref_ext 匹配你本地文件的后缀名 docref_ext=.html。当然也可以设置一个外部的参考地址。例如你可以设置 docref_root=[http://manual/en/](http://manual/en/) 或者 docref_root=”http://landonize.it/?how=url&theme=classic&filter=Landon &url=http%3A%2F%2Fwww.php.net%2F” > 通常需要在 docref_root 后面以 “/”结尾, 但是在以上的第二种示例情况中不必这么设置。 > Note: > 因为这么做可以快速定位和查看到函数的说明,所以它对你的开发会非常有用。建议永远不要再生产系统中使用 (例如系统被连接到互联网对外提供服务)。 参考资料 - [http://php.net/manual/zh/errorfunc.configuration.php#ini.docref-root](http://php.net/manual/zh/errorfunc.configuration.php#ini.docref-root) - [http://php.net/manual/en/function.main.php](http://php.net/manual/en/function.main.php) - [https://perishablepress.com/advanced-php-error-handling-via-htaccess/](https://perishablepress.com/advanced-php-error-handling-via-htaccess/) ### Changed silent conversion of array to string to produce a notice 改变了数组转换字符串的提醒 木有看明白。。。。 参考资料 - [http://stackoverflow.com/questions/3389582/notice-array-to-string-conversion-why](http://stackoverflow.com/questions/3389582/notice-array-to-string-conversion-why) - [http://stackoverflow.com/questions/20117856/php-array-to-string-as-parameters](http://stackoverflow.com/questions/20117856/php-array-to-string-as-parameters) - [http://stackoverflow.com/questions/7244564/notice-array-to-string-conversion](http://stackoverflow.com/questions/7244564/notice-array-to-string-conversion) - [http://grokbase.com/t/php/php-bugs/11b2a951bt/php-bug-bug-60198-new-array-to-string-notice-from-array-functions](http://grokbase.com/t/php/php-bugs/11b2a951bt/php-bug-bug-60198-new-array-to-string-notice-from-array-functions) ### Changed default value of “default_charset” php.ini option from ISO-8859-1 to UTF-8 改变默认值“default_charset”的选项从ISO-8859-1为UTF-8 默认设置是UTF-8. > PHP always outputs a character encoding by default in the Content-type: header. To disable sending of the charset, simply set it to be empty. 有趣的是这次发现了国内的工程师的提交的bug~ 参考资料 - [https://bugs.php.net/bug.php?id=61354](https://bugs.php.net/bug.php?id=61354) - [http://grokbase.com/t/php/php-internals/123cfv42tq/default-charset-confusion](http://grokbase.com/t/php/php-internals/123cfv42tq/default-charset-confusion) - [http://news.php.net/php.internals/58853](http://news.php.net/php.internals/58853) ### Changed silent casting of null/”/false into an Object when adding a property into a warning 当一个对象中有空的属性时加入了一个警告 当给一个对象加入一个属性的时候,扔掉null或者false会返回一个警告 ### Changed E_ALL to include E_STRICT E_ALL中包括了E_STRICT 参考资料 - [http://www.zhuwenbo.net/?p=146](http://www.zhuwenbo.net/?p=146) ### Disabled windows CRT warning by default, can be enabled again using the ini directive windows_show_crt_warnings 禁用Windows CRT警告默认情况下,可以再次启用使用INI指令windows_show_crt_warnings windows CRT > Visual Studio 2012 更新 1 支持的 Windows 8,Windows Server 2012,Windows 7,Windows Server 2008中,Windows Vista,Windows XP Service Pack 3 (SP3) C 运行库,x86 的 Windows XP Service Pack 2 (SP2) x64 和 Windows Server 2003 Service Pack 2 (SP2) x86 和 x64 的。 所有这些操作系统支持 Windows 应用程序编程接口 (API) (API) 提供和 Unicode 支持。 此外,所有 Win32 应用程序中使用多字节字符集 (MBCS)。 This directive shows the Windows CRT warnings when enabled. These warnings were displayed by default until PHP 5.4.0. > This directive shows the Windows CRT warnings when enabled. These warnings were displayed by default until PHP 5.4.0. 参考资料 - [http://blog.csdn.net/wwl33695/article/details/8472291](http://blog.csdn.net/wwl33695/article/details/8472291) - [http://cn.php.net/manual/zh/ini.core.php#ini.windows-show-crt-warning](http://cn.php.net/manual/zh/ini.core.php#ini.windows-show-crt-warning) ### Fixed bug #55378: Binary number literal returns float number though its value is small enough 固定的错误# 55378:二进制数的文本返回浮点数虽然其值足够小 上面提到过这个版本支持了直接的二进制的输出,所以这条就是修复返回二进制转换的浮点数的错误。 ~~~ Test script: --------------- <?php var_dump(0b1111111); var_dump(0b1111111111111111); Expected result: ---------------- int(127) int(65535) Actual result: -------------- int(127) float(65535) ~~~ 参考资料 - [https://bugs.php.net/bug.php?id=55378](https://bugs.php.net/bug.php?id=55378) ### Improved Zend Engine memory usage 改进的内存使用Zend引擎 原文 - Improved parse error messages. - Replaced `zend_function.pass_rest_by_reference` by `ZEND_ACC_PASS_REST_BY_REFERENCE` in zend_function.fn_flags. - Replaced `zend_function.return_reference` by `ZEND_ACC_RETURN_REFERENCE` in zend_function.fn_flags. - Removed `zend_arg_info.required_num_args` as it was only needed for internal functions. Now the first arg_info for internal functions (which has special meaning) is represented by `zend_internal_function_info` structure. - Moved `zend_op_array.size`, `size_var`, `size_literal`, `current_brk_cont`, backpatch_count into CG(`context`) as they are used only during compilation. - Moved `zend_op_array.start_op` into EG(`start_op`) as it’s used only for ‘interactive’ execution of single top-level op-array. - Replaced `zend_op_array.done_pass_two` by `ZEND_ACC_DONE_PASS_TWO` in `zend_op_array.fn_flags`. op_array.vars array is trimmed (reallocated) during pass_two. - Replaced `zend_class_entry.constants_updated` by `ZEND_ACC_CONSTANTS_UPDATED` in `zend_class_entry.ce_flags`. - Reduced the size of `zend_class_entry` by sharing the same memory space by different information for internal and user classes. See `zend_class_entry.info` union. - Reduced size of temp_variable. 翻译 - 改进的解析错误消息。 - 通过更换zend_function.pass_rest_by_reference zend_acc_pass_rest_by_reference在zend_function.fn_flags。 - 通过更换zend_function.return_reference zend_acc_return_reference在zend_function.fn_flags。 - 删除zend_arg_info.required_num_args因为这只是内部功能的需要。现在内部功能的第一arg_info(具有特殊意义的zend_internal_function_info结构表示)。 - 移动zend_op_array.size,size_var,size_literal,current_brk_cont,backpatch_count为CG(上下文)作为他们在编译过程中只使用。 - 移动zend_op_array.start_op成如(start_op)它只用于“单顶级运算阵列交互执行。 - 通过更换zend_op_array.done_pass_two zend_acc_done_pass_two在zend_op_array.fn_flags。 - op_array.vars阵列在pass_two修剪(重新分配)。 - 通过更换zend_class_entry.constants_updated zend_acc_constants_updated在zend_class_entry.ce_flags。 - 减少zend_class_entry大小由内部和用户类不同信息共享相同的内存空间。看到zend_class_entry.info联盟。 - temp_variable缩小。 这部分的说明是关于zend引擎相关的,按目前我的水平还不是能很明白的理解这些的含义。 ### Improved Zend Engine, performance tweaks and optimizations 改进的Zend引擎,性能调整和优化 原文 - Inlined most probable code-paths for arithmetic operations directly into executor. - Eliminated unnecessary iterations during request startup/shutdown. - Changed `$GLOBALS` into a JIT autoglobal, so it’s initialized only if used. (this may affect opcode caches!) - Improved performance of @ (silence) operator. - Simplified string offset reading. `$str[1][0]` is now a legal construct. - Added caches to eliminate repeatable run-time bindings of functions, classes, constants, methods and properties. - Added concept of interned strings. All strings constants known at compile time are allocated in a single copy and never changed. - `ZEND_RECV` now always has `IS_CV` as its result. - `ZEND_CATCH` has to be used only with constant class names. - `ZEND_FETCH_DIM_?` may fetch array and dimension operands in different order. - Simplified `ZEND_FETCH_*_R`operations. They can’t be used with the `EXT_TYPE_UNUSED`flag any more. This is a very rare and useless case. `ZEND_FREE` might be required after them instead. - Split `ZEND_RETURN` into two new instructions `ZEND_RETURN` and `ZEND_RETURN_BY_REF`. - Optimized access to global constants using values with pre-calculated hash_values from the literals table. - Optimized access to static properties using executor specialization. A constant class name may be used as a direct operand of `ZEND_FETCH_*` instruction without previous `ZEND_FETCH_CLASS`. - zend_stack and zend_ptr_stack allocation is delayed until actual usage. 翻译 - 内联最可能的代码路径,直接进入执行算术运算。 - 消除不必要的迭代请求启动/关机时。 - 改变成一个JIT autoglobal =美元,所以它的初始化,如果使用。(这可能会影响操作码缓存!) - 改进的性能”(沉默)算子。 - 简化的字符串偏移阅读。$str [ 1 ] [ 0 ]现在的法律构建。 - 消除重复的运行时绑定的功能,添加缓存类,常量,方法和属性。 - 拘留字符串添加的概念。所有字符串常量在编译时被分配在一个单拷贝,永远都不会改变的。 - zend_recv现在总是is_cv作为结果。 - zend_catch现在只需要进行不断的类名称。 - zend_fetch_dim_?可以把不同排列和尺寸数。 - 简化zend_fetch_ * _r操作。他们不能用任何ext_type_unused旗。这是一个非常难得的和无用的情况下。- zend_free可能在他们的要求。 - zend_return分裂为两个新的指令zend_return和zend_return_by_ref。 - 优化访问全局常量使用的值与预先计算的hash_values从文字表。 - 优化访问静态属性用遗嘱执行人专业化。一个恒定的类的名称可以作为直接操作数指令没有以前的zend_fetch_class zend_fetch_ *。 - zend_stack和zend_ptr_stack分配延迟到实际使用。 - 改进的Zend引擎,性能调整和优化 机翻好渣。。。。。等我长发及腰,再来看这个可好QAQ ### Other improvements to Zend Engine 在Zend引擎改进 原文 - Added an optimization which saves memory and emalloc/efree calls for empty HashTables. - Added ability to reset user opcode handlers. - Changed the structure of op_array.opcodes. The constant values are moved from opcode operands into a separate literal table. - Fixed (disabled) inline-caching for ZEND_OVERLOADED_FUNCTION methods. - Fixed bug #43200 (Interface implementation / inheritence not possible in abstract classes). 翻译 - 增加了一个优化,节省内存和emalloc /饱和需要空表。 - 新增能力重置用户操作处理程序。 - 改变了op_array.opcodes结构。该常数的值是从操作码操作数为一个单独的文字表。 - 固定(禁用)为zend_overloaded_function方法内联缓存。 - 固定的错误# 43200(接口的实现/继承抽象类不可能)。 ![PHP结构](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-03-17_56ea1b293701b.jpg "") zend引擎作为底层,还是需要我理解更深入再去看啦~ ### 后记 ### 关于PHP PHP作为流行的脚本语言,上手非常快,但是这并不代表这个一个糟糕的语言,从这个版本的更新记录,我也看到了每次的改进,以及社区内大家的努力。 这次做ChangeLog的整理大概会写三个文章共六篇,由于这个Log实在是太长了还是写一半先发出去比较好~ 引用的资料在每个小结后面都有,方便自己和大家查阅。 如果发现描述错误,请务必评论或者私信我,如果有错,发现了就不能再错下去~ ### 关于整理资料 我们依靠网络,每天在接触着很多的新闻和资料,对我们来讲,从这些里面找出有用的知识并吸收还是有一定难度的,特别是国内糟糕的博客环境,一个文章发布出来之后会有好多网站抄袭抓取,内容还不全,对于初学者会造成负面影响,且珍惜。 ### 关于个人成长 当有一个大目标的时候,才可以转化成小目标进行执行。 执行力永远放在第一位。
';

【phpMyAdmin】修改配置文件连接到其他服务器

最后更新于:2022-04-01 09:56:00

默认的phpMyAdmin在安装后会访问本机的mysql,但是有的时候我们需要访问其他的服务器的mysql数据库,所以我们需要配置来做。 果然,phpMyAdmin已经为我们做了配置的选项,但是需要我们进行一些手动的操作。 ~~~ http:/yourphpmyadmin.com/setup/index.php ~~~ 进入配置界面,这时候会出现提示  ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-03-17_56ea1b28d43d3.jpg) 找到对应的文档 ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-03-17_56ea1b28eaf1a.jpg) 复制出一份配置文件,并且赋予修改的权限。 ~~~ [root@ip-0 phpMyAdmin-4.4.0-beta1-all-languages]# mkdir config [root@ip-0 phpMyAdmin-4.4.0-beta1-all-languages]# chmod o+rw config [root@ip-0 phpMyAdmin-4.4.0-beta1-all-languages]# cp config.inc.php config/ [root@ip-0 phpMyAdmin-4.4.0-beta1-all-languages]# chmod o+w config/config.inc.php ~~~ 接下来就可以正常修改配置连接其他mysql服务器了。
';

【PHP】阿里云升级PHP到5.5详解

最后更新于:2022-04-01 09:55:57

### 目的 使用新版本PHP,提高代码执行效率 ### 和线下环境的不同 数据库采用RDS服务,本地不需要安装MYSQL 使用缓存服务,需要安装官方的memcached扩展 ### 需要安装的扩展 memcached,yar,memcached,apc,mycrypt ### 安装 ### 升级php ~~~ [root@iZ28vpjayxiZ ~]# yum remove php php-bcmath php-cli php-common php-devel php-fpm php-gd php-imap php-ldap php-mbstring php-mcrypt php-mysql php-odbc php-pdo php-pear php-pecl-igbinary php-xml php-xmlrpc ~~~ ~~~ [root@iZ28vpjayxiZ ~]# rpm -Uvh http://mirror.webtatic.com/yum/el6/latest.rpm ~~~ ~~~ [root@iZ28vpjayxiZ ~]# yum install php55w php55w-bcmath php55w-cli php55w-common php55w-devel php55w-fpm php55w-gd php55w-imap php55w-ldap php55w-mbstring php55w-mcrypt php55w-mysql php55w-odbc php55w-pdo php55w-pear php55w-pecl-igbinary php55w-xml php55w-xmlrpc php55w-opcache php55w-intl php55w-pecl-memcache ~~~ ~~~ [root@iZ28vpjayxiZ ~]# service httpd restart Stopping httpd: [ OK ] Starting httpd: [ OK ] ~~~ ### 安装扩展 ### MemcacheSASL ~~~ [root@iZ28vpjayxiZ html]# yum install gcc+ gcc-c++ Loaded plugins: security Setting up Install Process No package gcc+ available. Package gcc-c++-4.4.7-11.el6.x86_64 already installed and latest version Nothing to do [root@iZ28vpjayxiZ html]# yum install cyrus-sasl-plain cyrus-sasl cyrus-sasl-devel cyrus-sasl-lib [root@iZ28vpjayxiZ ~]# wget https://launchpad.net/libmemcached/1.0/1.0.16/+download/libmemcached-1.0.16.tar.gz [root@iZ28vpjayxiZ ~]# tar zxvf libmemcached-1.0.16.tar.gz [root@iZ28vpjayxiZ ~]# cd libmemcached-1.0.16 [root@iZ28vpjayxiZ libmemcached-1.0.16]# ./configure --prefix=/usr/local/libmemcached --enable-sasl * CPP Flags: -fvisibility=hidden * LIB Flags: * Assertions enabled: no * Debug enabled: no * Shared: yes * Warnings as failure: no * SASL support: yes * make -j: 2 * VCS checkout: no [root@iZ28vpjayxiZ libmemcached-1.0.16]# make && make install [root@iZ28vpjayxiZ libmemcached-1.0.16]# cd ../ [root@iZ28vpjayxiZ ~]# yum install zlib-devel Loaded plugins: security Setting up Install Process Package zlib-devel-1.2.3-29.el6.x86_64 already installed and latest version Nothing to do [root@iZ28vpjayxiZ ~]# wget http://pecl.php.net/get/memcached-2.1.0.tgz [root@iZ28vpjayxiZ ~]# tar zxvf memcached-2.1.0.tgz [root@iZ28vpjayxiZ ~]# cd memcached-2.1.0 [root@iZ28vpjayxiZ memcached-2.1.0]# phpize [root@iZ28vpjayxiZ memcached-2.1.0]# ./configure --with-libmemcached-dir=/usr/local/libmemcached --enable-memcached-sasl [root@iZ28vpjayxiZ memcached-2.1.0]# make && make install 最后修改php.ini文件(locate找该文件,yum安装的一般在/etc/php.ini 如果系统中有两套PHP环境,需找到使用OCS的PHP环境路径,对应修改之),增加extension=memcached.so memcached.use_sasl = 1 执行php –m |grep memcached 如显结果有 memcache 表示环境已支持memcache ~~~ ### yar ~~~ [root@iZ28vpjayxiZ ~]# pecl install channel://pecl.php.net/msgpack-0.5.5 #修改php.ini 增加 extension=msgpack.so [root@iZ28vpjayxiZ ~]# pecl install yar yes #修改php.ini 增加 extension=yar.so #由于yar需要json支持,所以需要先加载json.so ~~~
';

【MYSQL】PHPMYADMIN出现的问题以及解决方案

最后更新于:2022-04-01 09:55:55

这次遇到的问题是,当下载使用最新版的PhpMyAdmin时,出现了一系列的使用问题,逐一解决掉。 ### 一、session ~~~ phpMyAdmin - Error Error during session start; please check your PHP and/or webserver log file and configure your PHP installation properly. Also ensure that cookies are enabled in your browser. ~~~ 问题session权限问题 ~~~ [root@localhost ~]# chmod -R 777 /var/lib/php/session/ ~~~ ### 二、升级mysql 接下的出现的提示是 ~~~ phpMyAdmin - 错误 您应升级到 MySQL 5.5.0 或更高版本。 ~~~ 升级mysql ~~~ wget http://dev.mysql.com/get/mysql-community-release-el6-5.noarch.rpm yum localinstall mysql-community-release-el6-5.noarch.rpm yum install mysql-community-server [root@localhost mysql]# service mysqld restart停止 mysqld: [确定] MySQL Daemon failed to start. 正在启动 mysqld: [失败] [root@localhost mysql]# ~~~ MySQL Daemon failed to start. 解决方案查找中。。。。
';

【PHP扩展】centos给PHP安装扩展

最后更新于:2022-04-01 09:55:53

本文由点点点细雨原创,禁止转载。 ###Memcache ~~~ [root@localhost ~]# yum install libmemcached [root@localhost ~]# yum install memcached [root@localhost ~]# memcached -m 512 -u nobody -vv slab class 1: chunk size 96 perslab 10922 slab class 2: chunk size 120 perslab 8738 slab class 3: chunk size 152 perslab 6898 slab class 4: chunk size 192 perslab 5461 slab class 5: chunk size 240 perslab 4369 slab class 6: chunk size 304 perslab 3449 slab class 7: chunk size 384 perslab 2730 slab class 8: chunk size 480 perslab 2184 slab class 9: chunk size 600 perslab 1747 slab class 10: chunk size 752 perslab 1394 [root@localhost ~]# chkconfig --add memcached [root@localhost ~]# pecl install memcache checking for the location of zlib... configure: error: memcache support requires ZLIB. Use --with-zlib-dir=<DIR> to specify prefix where ZLIB include and library are located ERROR: `/var/tmp/memcache/configure --enable-memcache-session=yes' failed [root@localhost ~]# yum install zlib-devel [root@localhost ~]# pecl install memcache Build process completed successfully Installing '/usr/lib64/php/modules/memcache.so' install ok: channel://pecl.php.net/memcache-2.2.7 configuration option "php_ini" is not set to php.ini location You should add "extension=memcache.so" to php.ini [root@localhost ~]# vi /etc/php.ini [root@localhost ~]# service php-fpm restart 停止 php-fpm: [确定] 正在启动 php-fpm: [确定] ~~~ ###APC ~~~ [root@localhost ~]# pecl install apc 在包含自 /var/tmp/APC/apc.c:45 的文件中: /usr/include/php/ext/pcre/php_pcre.h:29:18: 错误:pcre.h:没有那个文件或目录 In file included from /var/tmp/APC/apc.c:45: /usr/include/php/ext/pcre/php_pcre.h:37: 错误:expected ‘=’, ‘,’, ‘;’, ‘asm’ or ‘__attribute__’ before ‘*’ token /usr/include/php/ext/pcre/php_pcre.h:38: 错误:expected ‘=’, ‘,’, ‘;’, ‘asm’ or ‘__attribute__’ before ‘*’ token /usr/include/php/ext/pcre/php_pcre.h:44: 错误:expected specifier-qualifier-list before ‘pcre’ [root@localhost ~]# yum install pcre-devel [root@localhost ~]# pecl install apc Build process completed successfully Installing '/usr/lib64/php/modules/apc.so' Installing '/usr/include/php/ext/apc/apc_serializer.h' install ok: channel://pecl.php.net/APC-3.1.13 configuration option "php_ini" is not set to php.ini location You should add "extension=apc.so" to php.ini [root@localhost ~]# vi /etc/php.ini [root@localhost ~]# service php-fpm restart 停止 php-fpm: [确定] 正在启动 php-fpm: [确定] ~~~ ###Mcrypt ~~~ [root@localhost ~]# rpm -ivh http://mirrors.sohu.com/fedora-epel/6/i386/epel-release-6-8.noarch.rpm [root@localhost ~]# yum update Complete! [root@localhost ~]# yum repolist 已加载插件:fastestmirror Loading mirror speeds from cached hostfile * base: mirrors.cug.edu.cn * epel: mirrors.zju.edu.cn * extras: mirrors.cug.edu.cn * updates: mirrors.cug.edu.cn 仓库标识 仓库名称 状态 base CentOS-6 - Base 6,518 *epel Extra Packages for Enterprise Linux 6 - x86_64 11,188 extras CentOS-6 - Extras 36 nginx nginx repo 69 updates CentOS-6 - Updates 530 repolist: 18,341 [root@localhost ~]# yum install php-mcrypt [root@localhost ~]# service php-fpm restart 停止 php-fpm: [确定] 正在启动 php-fpm: [确定] ~~~ ###关闭selinux ~~~ /usr/sbin/setenforce 0 ~~~
';

【Yaf】Yaf的环境安装遇到的问题以及解决方案

最后更新于:2022-04-01 09:55:50

【本文原创,禁止转载】 ###一、前言 用了半年的Yii框架,发现封装的类太多太多,虽然使用起来**效率很高**但是**学习成本比较高**并且**自由度不高**,本着学习的态度,想试试新的框架尝尝鲜。 因为一直在用鸟哥写的yar做接口封装,所以也就想试试他用C写的PHP框架 ###二、下载 Yaf其实算是PHP官方的一个扩展,我们可以直接在PHP官网下载。 http://pecl.php.net/package/yaf 也可以在github上找到。 https://github.com/laruence/php-yaf 还有,Yaf的官网,虽然说明文档一直木有更新。。。 http://www.yafdev.com/ ###三、安装 其实这就是一个安装PHP扩展的过程。 Yaf和Yii的区别就是Yaf把框架写成了PHP扩展,能更深一层的执行,这样也就是他为什么这么快的原因。 **1、下载** ~~~ wget http://pecl.php.net/get/yaf-2.3.2.tgz #直接从PHP官网下载正式版本会比较稳定 ~~~ **2、解压** ~~~ tar zxvf yaf-2.3* #好吧我偷懒了。。 cd yaf* ~~~ **3、预处理** ~~~ phpize #这里我还没完全搞懂所以就没有加参数 ~~~ **4、make** ~~~ make #提示大家最好用 make && make test ~~~ ### 1)问题 然后就在make这里出现了问题,没有,博主每次装点东西总会出现问题,这也就是写博客记录的理由哈~ ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-03-17_56ea1b27f2055.jpg) 很明显没有 php_pcre.h 这个文件 ### 2)解决 当然粗线了问题肯定就能解决,然后博主就去问鸟哥了QAQ【下次一定自己先找方法QAQ 结果就是需要“安装pcre dev包” 开始我是这样 ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-03-17_56ea1b2811791.jpg) 显然执行之后没有起作用啦! 然后急中生智。。。。 ~~~ yum install pcre*dev* #直接去搜惹。。。 ~~~ 结果! ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-03-17_56ea1b282af61.jpg) 装上惹!!!  ### 3)继续make 经过上面的问题解决,下面当然木有问题了! ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-03-17_56ea1b283d37c.jpg) **5、修改php.ini** 给你的php.ini添加一行让他能加载这个扩展 ~~~ extension=yaf.so # 加上扩展!萌萌哒!!! ~~~ **6、重启httpd** ~~~ service httpd restart ~~~ **7、查看phpinfo()** ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-03-17_56ea1b284e6e4.jpg) 至此,PHP的Yaf扩展安装完成! ###四、框架目录结构 这里要提一下,因为Yaf的官方网站 http://yaf.laruence.com/manual/index.html 的文档的更新时间是**2012**年,所以一定要小心。博主按照这个配置,果然不行! 然后,博主就机智的想到了社区,毕竟人多力量的大,然后。。。 ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-03-17_56ea1b2862d3b.jpg) 。。。 这是排名最靠前的论坛好咩?这样的回帖数是闹哪样啊?2012年是怎么回事啊? 然后博主又机智的找到了置顶的QQ群! 然后博主又机智的找到了群共享里的文件! ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-03-17_56ea1b288612b.jpg) 然后。。。 ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-03-17_56ea1b28999cc.jpg) 成功了有木有!!! 心里很是激动啊!!! 所以最新的目录结构是这样的 ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-03-17_56ea1b28a9b9f.jpg) ###五、总结 1)感谢鸟哥 2)人多力量大,没有文档还有QQ群 3)遇到足够多的错误才能进步 4)自己认为这样的方式【二次元语言】写技术博客挺萌的~ ###六、参考资料 1)[Yaf官网](http://www.yafdev.com/) http://www.yafdev.com/ 2)[github项目](https://github.com/laruence/php-yaf) https://github.com/laruence/php-yaf 3)[PHP官方扩展下载](http://pecl.php.net/package/yaf)  http://pecl.php.net/package/yaf 4)[PHP官方说明函数参考](http://php.net/manual/zh/book.yaf.php) http://php.net/manual/zh/book.yaf.php 5)[鸟哥博客](http://www.laruence.com/2012/07/06/2649.html) http://www.laruence.com/2012/07/06/2649.html 6)Yaf的QQ群 5134185
';

Yii配合Yar在php5.3.3环境下的错误以及解决方案

最后更新于:2022-04-01 09:55:48

首先感谢[鸟哥](http://weibo.com/laruence),解决这个问题!这里做个简单的总结。 ### 问题 在阿里云服务器上,安装了最新版本的yar和yii,上传了项目代码,但是调用yar封装的接口时,始终提示错误。 ~~~ curl exec failed 'Server returned nothing (no headers, no data)' ~~~ ### 分析 查看错误日志,发现这样的问题。 ~~~ GET /path/to/url HTTP/1.1" 500 16933 "-" "Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:24.0) Gecko/20100101 Firefox/24.0 ~~~ 服务器的500错误,再检查server的日志,httpd下的error_log。 ~~~ [Thu Jan 02 14:08:22 2014] [notice] child pid 29414 exit signal Segmentation fault (11) ~~~ 发现的情况是这样的。 服务器没有打开coredump,所以暂时还没有core产生。 ### 解决 然后,经过鸟哥4个小时的排查错误,发现,这是由于php5.3.3的bug导致的。 gdb作为测试工具,测试脚本。 修改了yii框架的代码。 ~~~ /framework/web/actions/CInlineAction.php ~~~ 原来是这样的 ~~~ public function runWithParams($params) { $methodName='action'.$this->getId(); $controller=$this->getController(); $method=new ReflectionMethod($controller, $methodName); if($method->getNumberOfParameters()>0) return $this->runWithParamsInternal($controller, $method, $params); else return $controller->$methodName(); } ~~~ 修改后 ~~~ public function runWithParams($params) { $methodName='action'.$this->getId(); $controller=$this->getController(); $method=new ReflectionMethod($controller, $methodName); if($method->getNumberOfParameters()>0) $ret = $this->runWithParamsInternal($controller, $method, $params); else $ret = $controller->$methodName(); return $ret; } ~~~ 这样就ok啦。 ### 后记 鸟哥对自己的作品负责的态度真是佩服,连夜为我们测试,十分感动,谢谢鸟哥的帮助。 对于自己的知识体系来说,在linux上的测试环节和管理都是不熟悉的,一定会把这部分缺口补齐的! 加了个油!![奋斗](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-02-17_56c446a99dec4.gif)
';

PHPCMS广告模块详细分析——广告的生成

最后更新于:2022-04-01 09:55:46

本文章为原创内容,转载请注明出处。 上周班上的小范同学问我广告模块怎么设计,我说你去参考phpcms啊,他上面的广告模块设计的很不错呢。 那么,就让我们开始吧。 ## PHPCMS广告模块详细分析——广告的生成 ### 一、功能。 我们首先从功能开始,这里用的是最新下载的 **[phpcms_v9.5.2_UTF8](http://www.phpcms.cn/index.php?m=content&c=down&a_k=59feBgIEUgIBVFEDA1UBAQBYBFIBU1EHAgUDC1EIBA0HQkALFFlfAxcCXFtHEUUIFhZRWRQNXwkHUBxIDRFaVUVKUFgdQlsdCEpUHEMNRVFUSmpAWk0GSFRrZ2wjWRdCXxQVUg8ERF9eAARfWgEIAR9aVEIKBw5XXw)** ,有兴趣的同学可以下载下来。 跳过安装步骤,我们进入后台,直接看广告模块。 广告位列表 ![广告位列表](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-03-17_56ea1b270d1f6.jpg) 广告列表 ![广告列表](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-03-17_56ea1b27250a5.jpg) 广告统计 ![广告统计](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-03-17_56ea1b276741f.jpg) 那么,我们就很清楚phpcms广告模块的功能了。 每个广告位最多显示一个广告,但是可以设置多个广告进行时间排序的播放,每一个广告都会有自己的统计信息,统计点击量和显示量。 ### 二、数据库分析。 让我们打开phpcms的数据库,分析下数据是怎么存储的。 打开数据库,我们会发现三个名字中带有poser的表,没错!这(至少)三个表就是负责存储广告相关数据的。 广告位 poster_space ![广告位](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-03-17_56ea1b2778bfd.jpg) 广告 poster ![广告](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-03-17_56ea1b278c072.jpg) 广告浏览IP统计 poster_201312 ![广告ip](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-03-17_56ea1b27a17ec.jpg) 这样的话,数据统计也是很明确的啦!  poster_space表中存储着广告位,poster中存储每条广告的信息,包含统计信息的点击量,poster_201312存放着2013年12月的广告IP统计,因为每个用户的IP都不一样,数据量会非常大,所以要分月存放。 ### 三,代码分析。 上面的内容都是铺垫,对于程序员们来说,源代码才是真刀实枪! 上码! ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-03-17_56ea1b27b3211.jpg) 广告模块存放于phpcms\modules\poster ,是作为一个phpcms的模块的存在。 我们按流程分析,按照 **广告位->广告->前台调用** 这个顺序,把源代码撸一遍! 1.space.php 先贴个几个图 ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-03-17_56ea1b27c16bf.jpg) 广告模版 ![广告模版](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-03-17_56ea1b27d4869.jpg) ~~~ <?php /** * 这里是小雨的注释 * * 广告模块的代码量其实不大,也就不到300行,除去官方注释和空行之外也就没有多少了。 * */ defined('IN_PHPCMS') or exit('No permission resources.'); pc_base::load_app_class('admin', 'admin', 0); pc_base::load_sys_class('form', '', 0); /** * 这里是小雨的注释 * * 这里继承了admin类,为的是不允许前台调用 * * 写这个注释是为了和后面的index.pphp进行区分 */ class space extends admin { private $M, $db; /** * 这里是小雨的注释 * * 构造函数,因为phpcms的多站点管理,所以在构造函数中获取了当前站点的id并放入M中,方便下面的方法调用。 */ function __construct() { parent::__construct(); $setting = new_html_special_chars(getcache('poster', 'commons')); $this->M = $setting[$this->get_siteid()]; $this->db = pc_base::load_model('poster_space_model'); } public function init() { $TYPES = $this->template_type(); $page = max(intval($_GET['page']), 1); $infos = $this->db->listinfo(array('siteid' => $this->get_siteid()), '`spaceid`', $page); $pages = $this->db->pages; $big_menu = array('javascript:window.top.art.dialog({id:\'add\',iframe:\'?m=poster&c=space&a=add\', title:\'' . L('add_space') . '\', width:\'540\', height:\'320\'}, function(){var d = window.top.art.dialog({id:\'add\'}).data.iframe;var form = d.document.getElementById(\'dosubmit\');form.click();return false;}, function(){window.top.art.dialog({id:\'add\'}).close()});void(0);', L('add_space')); include $this->admin_tpl('space_list'); } /** * 添加广告版块 */ public function add() { if (isset($_POST['dosubmit'])) { $space = $this->check($_POST['space']); $space['setting'] = array2string($_POST['setting']); $space['siteid'] = $this->get_siteid(); $spaceid = $this->db->insert($space, true); if ($spaceid) { if ($space['type'] == 'code') { $path = '{show_ad(' . $space['siteid'] . ', ' . $spaceid . ')}'; } else { $path = 'poster_js/' . $spaceid . '.js'; } $this->db->update(array('path' => $path), array('siteid' => $this->get_siteid(), 'spaceid' => $spaceid)); showmessage(L('added_successful'), '?m=poster&c=space', '', 'add'); } } else { $TYPES = $this->template_type(); /** * 这里是小雨的注释 * * 没错!这里是添加广告版位的控制器,那么我们在上面的图中看到的广告位的下拉菜单来自哪里呢 * 让我们继续分析下面的函数 getcache */ $poster_template = getcache('poster_template_' . $this->get_siteid(), 'commons'); $show_header = $show_validator = true; include $this->admin_tpl('space_add'); } } /** * 编辑广告版位 */ public function edit() { $_GET['spaceid'] = intval($_GET['spaceid']); if (!$_GET['spaceid']) showmessage(L('illegal_operation'), HTTP_REFERER); if (isset($_POST['dosubmit'])) { $space = $this->check($_POST['space']); $space['setting'] = array2string($_POST['setting']); /** * 这里是小雨的注释 * * 修改提交的时候,通过判断表单中的广告位类型,写入了不同的值到了路径这个参数 */ if ($space['type'] == 'code') { $space['path'] = '{show_ad(' . $this->get_siteid() . ', ' . $_GET['spaceid'] . ')}'; } else { $space['path'] = 'poster_js/' . $_GET['spaceid'] . '.js'; } if (isset($_POST['old_type']) && $_POST['old_type'] != $space['type']) { $poster_db = pc_base::load_model('poster_model'); $poster_db->delete(array('spaceid' => $_GET['spaceid'])); $space['items'] = 0; } if ($this->db->update($space, array('spaceid' => $_GET['spaceid']))) showmessage(L('edited_successful'), '?m=poster&c=space', '', 'testIframe' . $_GET['spaceid']); } else { $info = $this->db->get_one(array('spaceid' => $_GET['spaceid'])); /** * 这里是小雨的注释 * * 修改的时候将存入数据库的 setting字段转化为数组 */ $setting = string2array($info['setting']); $TYPES = $this->template_type(); /** * 这里是小雨的注释 * * 拿到了广告模版的缓存,注意,是缓存,也就是存在原始文件,因为在上面的数据库中并没有存储模版的信息 */ $poster_template = getcache('poster_template_' . $this->get_siteid(), 'commons'); $show_header = $show_validator = true; include $this->admin_tpl('space_edit'); } } /** * 广告版位调用代码 */ public function public_call() { $_GET['sid'] = intval($_GET['sid']); if (!$_GET['sid']) showmessage(L('illegal_action'), HTTP_REFERER, '', 'call'); $r = $this->db->get_one(array('spaceid' => $_GET['sid'], 'siteid' => $this->get_siteid())); include $this->admin_tpl('space_call'); } /** * 广告预览 */ public function public_preview() { if (is_numeric($_GET['spaceid'])) { $_GET['spaceid'] = intval($_GET['spaceid']); $r = $this->db->get_one(array('spaceid' => $_GET['spaceid'], 'siteid' => $this->get_siteid())); $scheme = $_SERVER['SERVER_PORT'] == '443' ? 'https://' : 'http://'; /** * 这里是小雨的注释 * * 在这里,同样的对 广告位 类型是 代码 的进行了特殊待遇 * */ if ($r['type'] == 'code') { $db = pc_base::load_model('poster_model'); $rs = $db->get_one(array('spaceid' => $r['spaceid'], 'siteid' => $this->get_siteid()), 'setting', '`id` ASC'); if ($rs['setting']) { $d = string2array($rs['setting']); $data = $d['code']; } } else { $path = APP_PATH . 'caches/' . $r['path']; } include $this->admin_tpl('space_preview'); } } private function template_type() { pc_base::load_app_func('global', 'poster'); return get_types(); } /** * 删除广告版位 * @param intval $sid 广告版位的ID,当批量删除时系统会递归删除 */ public function delete() { if ((!isset($_GET['spaceid']) || empty($_GET['spaceid'])) && (!isset($_POST['spaceid']) || empty($_POST['spaceid']))) { showmessage(L('illegal_parameters'), HTTP_REFERER); } else { if (is_array($_POST['spaceid'])) { array_map(array($this, _del), $_POST['spaceid']); //如果是批量操作,则递归数组 } elseif ($_GET['spaceid']) { $_GET['spaceid'] = intval($_GET['spaceid']); $db = pc_base::load_model('poster_model'); $db->delete(array('siteid' => $this->get_siteid(), 'spaceid' => $_GET['spaceid'])); $this->db->delete(array('siteid' => $this->get_siteid(), 'spaceid' => $_GET['spaceid'])); } showmessage(L('operation_success'), HTTP_REFERER); } } /** * 广告位删除 * @param intval $spaceid 专题ID */ private function _del($spaceid = 0) { $spaceid = intval($spaceid); if (!$spaceid) return false; $db = pc_base::load_model('poster_model'); $db->delete(array('siteid' => $this->get_siteid(), 'spaceid' => $spaceid)); $this->db->delete(array('siteid' => $this->get_siteid(), 'spaceid' => $spaceid)); return true; } /** * 广告模块配置 */ public function setting() { if (isset($_POST['dosubmit'])) { //读取了缓存 $setting = getcache('poster', 'commons'); $setting[$this->get_siteid()] = $_POST['setting']; setcache('poster', $setting, 'commons'); //设置缓存 $m_db = pc_base::load_model('module_model'); //调用模块数据模型 $setting = array2string($_POST['setting']); $m_db->update(array('setting' => $setting), array('module' => ROUTE_M)); //将配置信息存入数据表中 showmessage(L('setting_updates_successful'), HTTP_REFERER, '', 'setting'); } else { /** * 这里是小雨的注释 * * 注意这个函数 * extract() 函数从数组中把变量导入到当前的符号表中 * 也就是将构造函数中的,从缓存中取出的设置的数组直接打散作为变量 * @ 的符号是防止报错的 */ @extract($this->M); include $this->admin_tpl('setting'); } } /** * 配置模板 */ public function poster_template() { /** * 这里是小雨的注释 * * 这里配置了模版,也就是从文件中读取 * */ $tpl_root = pc_base::load_config('system', 'tpl_root'); $templatedir = PC_PATH . $tpl_root . pc_base::load_config('system', 'tpl_name') . DIRECTORY_SEPARATOR . 'poster' . DIRECTORY_SEPARATOR; /** * * 这里的$templatedir 为 phpcms\templates/default\poster\ * */ $poster_template = getcache('poster_template_' . get_siteid(), 'commons'); /** * 找到所有的html的文件,循环得到不包含扩展名的文件名,作为配置项 */ $templates = glob($templatedir . '*.html'); if (is_array($templates) && !empty($templates)) { foreach ($templates as $k => $tem) { $templates[$k] = basename($tem, ".html"); } } $big_menu = array('javascript:window.top.art.dialog({id:\'add\',iframe:\'?m=poster&c=space&a=add\', title:\'' . L('add_space') . '\', width:\'540\', height:\'320\'}, function(){var d = window.top.art.dialog({id:\'add\'}).data.iframe;var form = d.document.getElementById(\'dosubmit\');form.click();return false;}, function(){window.top.art.dialog({id:\'add\'}).close()});void(0);', L('add_space')); include $this->admin_tpl('poster_template'); } /** * 删除模板配置 */ public function public_tempate_del() { if (!isset($_GET['id'])) showmessage(L('illegal_parameters'), HTTP_REFERER); $siteid = $this->get_siteid(); $poster_template = getcache('poster_template_' . $siteid, 'commons'); /** * * 这里在删除的时候只是修改了缓存文件中的,并没有修改原来的哦 * */ if ($poster_template[$_GET['id']]) { unset($poster_template[$_GET['id']]); } setcache('poster_template_' . $siteid, $poster_template, 'commons'); showmessage(L('operation_success'), HTTP_REFERER); } /** * 配置模板 * * 注:这里只能对 'iscore' => 0, 的模版进行设置哦 */ public function public_tempate_setting() { $siteid = $this->get_siteid(); $poster_template = getcache('poster_template_' . $siteid, 'commons'); if (isset($_POST['dosubmit'])) { if (is_array($_POST['info']['type']) && !empty($_POST['info']['type'])) { $type2name = array('images' => L('photo'), 'flash' => L('flash'), 'text' => L('title')); $type = array(); foreach ($_POST['info']['type'] as $t) { if (in_array($t, array('images', 'flash', 'text'))) { $type[$t] = $type2name[$t]; } else { continue; } } } unset($_POST['info']['type']); $_POST['info']['type'] = $type; $poster_template[$_POST['template']] = $_POST['info']; /** * * 这里设置了模版的缓存,放在了 * caches/caches_commons/caches_data/poster_template_1.cache * 中,特佩服phpcms的缓存 */ setcache('poster_template_' . $siteid, $poster_template, 'commons'); showmessage(L('setting_success'), '', '', 'testIframe'); } else { if (!isset($_GET['template'])) { showmessage(L('illegal_parameters')); } else { $template = $_GET['template']; } if ($poster_template[$template]) { $info = $poster_template[$template]; if (is_array($info['type']) && !empty($info['type'])) { $type = array(); $type = array_keys($info['type']); unset($info['type']); $info['type'] = $type; } } include $this->admin_tpl('template_setting'); } } /** * 更新js */ public function create_js($page = 0) { $page = max(intval($_GET['page']), 1); if ($page == 1) { /** * 这里是小雨的注释 * * 获取了当前站点下能用的广告做了数量的分页 * * */ $result = $this->db->get_one(array('disabled' => 0, 'siteid' => get_siteid()), 'COUNT(*) AS num'); if ($result['num']) { $total = $result['num']; $pages = ceil($total / 20); } } else { $pages = $_GET['pages'] ? intval($_GET['pages']) : 0; } $offset = ($page - 1) * 20; $data = $this->db->listinfo(array('disabled' => 0, 'siteid' => get_siteid()), 'spaceid ASC', $page); /** * * 其实这个方法只是个套子,真正的更新js在下面 * * 读取了html的类 * 使用了html中的create_js,来更新了js */ $html = pc_base::load_app_class('html'); foreach ($data as $d) { if ($d['type'] != 'code') { $html->create_js($d['spaceid']); } else { continue; } } $page++; if ($page > $pages) { showmessage(L('update_js_success'), '?m=poster&c=space&a=init'); } else { showmessage(L('update_js') . '<font style="color:red">' . ($page - 1) . '/' . $pages . '</font>', '?m=poster&c=space&a=create_js&page=' . $page . '&pages=' . $pages); } } /** * 检测版位名称是否存在 */ public function public_check_space() { if (!$_GET['name']) exit(0); if (pc_base::load_config('system', 'charset') == 'gbk') { $_GET['name'] = iconv('UTF-8', 'GBK', $_GET['name']); } $name = $_GET['name']; if ($_GET['spaceid']) { $spaceid = intval($_GET['spaceid']); $r = $this->db->get_one(array('spaceid' => $spaceid, 'siteid' => $this->get_siteid())); if ($r['name'] == $name) { exit('1'); } } $r = $this->db->get_one(array('siteid' => $this->get_siteid(), 'name' => $name), 'spaceid'); if ($r['spaceid']) { exit('0'); } else { exit('1'); } } /** * 检查表单数据 * @param Array $data 表单传递过来的数组 * @return Array 检查后的数组 */ private function check($data = array()) { if ($data['name'] == '') showmessage(L('name_plates_not_empty')); $info = $this->db->get_one(array('name' => $data['name'], 'siteid' => $this->get_siteid()), 'spaceid'); if (($info['spaceid'] && $info['spaceid'] != $_GET['spaceid']) || ($info['spaceid'] && !isset($_GET['spaceid']))) { showmessage(L('space_exist'), HTTP_REFERER); } if ((!isset($data['width']) || $data['width'] == 0) && in_array($data['type'], array('banner', 'fixure', 'float', 'couplet', 'imagechange', 'imagelist'))) { showmessage(L('plate_width_not_empty'), HTTP_REFERER); } else { $data['width'] = intval($data['width']); } if ((!isset($data['height']) || $data['height'] == 0) && in_array($data['type'], array('banner', 'fixure', 'float', 'couplet', 'imagechange', 'imagelist'))) { showmessage(L('plate_height_not_empty'), HTTP_REFERER); } else { $data['height'] = intval($data['height']); } $TYPES = $this->template_type(); return $data; } } ?> ~~~ 这里的总结。 广告位模版配置文件在缓存中,广告的模版存在于phpcms\templates/default\poster\ 中,它和更新js功能有及其密切的关系。 下面开始分析广告的js是怎么生成的。 首先看位于 cache/poster_js下的一个已经生成的js文件 名为1.js的文件时对应的数据,位于poster_space表中id为1的记录,因为这条记录中path的值为 poster_js/1.js ~~~ function PCMSAD(PID) { this.ID = PID; this.PosID = 0; this.ADID = 0; this.ADType = ""; this.ADName = ""; this.ADContent = ""; this.PaddingLeft = 0; this.PaddingTop = 0; this.Wspaceidth = 0; this.Height = 0; this.IsHitCount = "N"; this.UploadFilePath = ""; this.URL = ""; this.SiteID = 0; this.ShowAD = showADContent; this.Stat = statAD; } function statAD() { var new_element = document.createElement("script"); new_element.type = "text/javascript"; new_element.src="http://localhost/phpcms952/index.php?m=poster&c=index&a=show&siteid="+this.SiteID+"&spaceid="+this.ADID+"&id="+this.PosID; document.body.appendChild(new_element); } function showADContent() { var content = this.ADContent; var str = ""; var AD = eval('('+content+')'); if (this.ADType == "images") { if (AD.Images[0].imgADLinkUrl) str += "<a href='"+this.URL+'&a=poster_click&sitespaceid='+this.SiteID+"&id="+this.ADID+"&url="+AD.Images[0].imgADLinkUrl+"' target='_blank'>"; str += "<img title='"+AD.Images[0].imgADAlt+"' src='"+this.UploadFilePath+AD.Images[0].ImgPath+"' width='"+this.Width+"' height='"+this.Height+"' style='border:0px;'>"; if (AD.Images[0].imgADLinkUrl) str += "</a>"; }else if(this.ADType == "flash"){ str += "<object classid='clsid:D27CDB6E-AE6D-11cf-96B8-444553540000' width='"+this.Width+"' height='"+this.Height+"' id='FlashAD_"+this.ADID+"' codebase='http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=8,0,0,0'>"; str += "<param name='movie' value='"+this.UploadFilePath+AD.Images[0].ImgPath+"' />"; str += "<param name='quality' value='autohigh' />"; str += "<param name='wmode' value='opaque'/>"; str += "<embed src='"+this.UploadFilePath+AD.Images[0].ImgPath+"' quality='autohigh' wmode='opaque' name='flashad' swliveconnect='TRUE' pluginspage='http://www.macromedia.com/shockwave/download/index.cgi?P1_Prod_Version=ShockwaveFlash' type='application/x-shockwave-flash' width='"+this.Width+"' height='"+this.Height+"'></embed>"; str += "</object>"; } str += ""; document.write(str); } var cmsAD_1 = new PCMSAD('cmsAD_1'); cmsAD_1.PosID = 1; cmsAD_1.ADID = 1; cmsAD_1.ADType = "images"; cmsAD_1.ADName = "banner"; cmsAD_1.ADContent = "{'Images':[{'imgADLinkUrl':'http%3A%2F%2Fwww.phpcms.cn','imgADAlt':'','ImgPath':'http://localhost/phpcms952/uploadfile/poster/2.png'}],'imgADLinkTarget':'New','Count':'1','showAlt':'Y'}"; cmsAD_1.URL = "http://localhost/phpcms952/index.php?m=poster&c=index"; cmsAD_1.SiteID = 1; cmsAD_1.Width = 430; cmsAD_1.Height = 63; cmsAD_1.UploadFilePath = ''; cmsAD_1.ShowAD(); var isIE=!!window.ActiveXObject; if (isIE){ if (document.readyState=="complete"){ cmsAD_1.Stat(); } else { document.onreadystatechange=function(){ if(document.readyState=="complete") cmsAD_1.Stat(); } } } else { cmsAD_1.Stat(); } ~~~ 这是一个类型为banner的广告模型,我们拿出它的模版文件 ~~~ function PCMSAD(PID) { this.ID = PID; this.PosID = 0; this.ADID = 0; this.ADType = ""; this.ADName = ""; this.ADContent = ""; this.PaddingLeft = 0; this.PaddingTop = 0; this.Wspaceidth = 0; this.Height = 0; this.IsHitCount = "N"; this.UploadFilePath = ""; this.URL = ""; this.SiteID = 0; this.ShowAD = showADContent; this.Stat = statAD; } function statAD() { var new_element = document.createElement("script"); new_element.type = "text/javascript"; new_element.src="{APP_PATH}index.php?m=poster&c=index&a=show&siteid="+this.SiteID+"&spaceid="+this.ADID+"&id="+this.PosID; document.body.appendChild(new_element); } function showADContent() { var content = this.ADContent; var str = ""; var AD = eval('('+content+')'); if (this.ADType == "images") { if (AD.Images[0].imgADLinkUrl) str += "<a href='"+this.URL+'&a=poster_click&sitespaceid='+this.SiteID+"&id="+this.ADID+"&url="+AD.Images[0].imgADLinkUrl+"' target='_blank'>"; str += "<img title='"+AD.Images[0].imgADAlt+"' src='"+this.UploadFilePath+AD.Images[0].ImgPath+"' width='"+this.Width+"' height='"+this.Height+"' style='border:0px;'>"; if (AD.Images[0].imgADLinkUrl) str += "</a>"; }else if(this.ADType == "flash"){ str += "<object classid='clsid:D27CDB6E-AE6D-11cf-96B8-444553540000' width='"+this.Width+"' height='"+this.Height+"' id='FlashAD_"+this.ADID+"' codebase='http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=8,0,0,0'>"; str += "<param name='movie' value='"+this.UploadFilePath+AD.Images[0].ImgPath+"' />"; str += "<param name='quality' value='autohigh' />"; str += "<param name='wmode' value='opaque'/>"; str += "<embed src='"+this.UploadFilePath+AD.Images[0].ImgPath+"' quality='autohigh' wmode='opaque' name='flashad' swliveconnect='TRUE' pluginspage='http://www.macromedia.com/shockwave/download/index.cgi?P1_Prod_Version=ShockwaveFlash' type='application/x-shockwave-flash' width='"+this.Width+"' height='"+this.Height+"'></embed>"; str += "</object>"; } str += ""; document.write(str); } var cmsAD_{$spaceid} = new PCMSAD('cmsAD_{$spaceid}'); cmsAD_{$spaceid}.PosID = {$spaceid}; cmsAD_{$spaceid}.ADID = {$p_id}; cmsAD_{$spaceid}.ADType = "{$p_type}"; cmsAD_{$spaceid}.ADName = "{$p_name}"; cmsAD_{$spaceid}.ADContent = "{'Images':[{'imgADLinkUrl':'{urlencode($p_setting[1]['linkurl'])}','imgADAlt':'{$p_setting[1]['alt']}','ImgPath':'<?php echo $p_type=='images' ? $p_setting[1]['imageurl'] : $p_setting[1]['flashurl'];?>'}],'imgADLinkTarget':'New','Count':'1','showAlt':'Y'}"; cmsAD_{$spaceid}.URL = "{APP_PATH}index.php?m=poster&c=index"; cmsAD_{$spaceid}.SiteID = {$siteid}; cmsAD_{$spaceid}.Width = {$width}; cmsAD_{$spaceid}.Height = {$height}; cmsAD_{$spaceid}.UploadFilePath = ''; cmsAD_{$spaceid}.ShowAD(); var isIE=!!window.ActiveXObject; if (isIE){ if (document.readyState=="complete"){ cmsAD_{$spaceid}.Stat(); } else { document.onreadystatechange=function(){ if(document.readyState=="complete") cmsAD_{$spaceid}.Stat(); } } } else { cmsAD_{$spaceid}.Stat(); } ~~~ 这样,给我们的认识就是,模版上的变量被替换了,并重新生成了js文件,放到了相应的文件夹。 ~~~ <?php /** * * @param 广告生成js类 */ defined('IN_PHPCMS') or exit('No permission resources.'); class html { private $db, $s_db, $queue; /** * * 类的构造函数读取了三个模型作为了类的内部变量 * 广告位,广告,队列 * * 这里提一下队列模型 * * phpcms的队列模型,就是在任务太多的情况下 * 将其存入名为queue的表中 * 处理完一个删除一个 * 可以理解为排队机制 * */ public function __construct() { $this->s_db = pc_base::load_model('poster_space_model'); $this->db = pc_base::load_model('poster_model'); $this->queue = pc_base::load_model('queue_model'); } /** * 生成广告js文件 * @param intval $id 广告版位ID * @return boolen 成功返回true */ public function create_js($id = 0) { $id = intval($id); if (!$id) { $this->msg = L('no_create_js'); return false; } $siteid = get_siteid(); /** * * 这里的生成js文件就是单一的 * 在上文提到的调用中循环采用了这个 * 所以下面拿到的是当前站点id下的广告位的数据 * */ $r = $this->s_db->get_one(array('siteid' => $siteid, 'spaceid' => $id)); $now = SYS_TIME; //将系统时间写入变量 if ($r['setting']) $space_setting = string2array($r['setting']); //如果存在广告位的设置,就转化成数组,其实肯定存在的 if ($r['type'] == 'code') return true; //代码类型的就直接返回了,因为不用生产js文件 $poster_template = getcache('poster_template_' . $siteid, 'commons'); //读取了广告模版设置的缓存 /** * * 下面进行一个判断 * * 判断广告位的类型配置是不是存在option一项 * * */ if ($poster_template[$r['type']]['option']) { /** * 如果存在 * 获取 * 当前站点 当前广告位 能使用 设置时间在当前时间内 , 按照 人为排序正序 id倒序 * 的所有广告 * * 并且打散数组 */ $where = "`spaceid`='" . $id . "' AND `siteid`='" . $siteid . "' AND `disabled`=0 AND `startdate`<='" . $now . "' AND (`enddate`>='" . $now . "' OR `enddate`=0) "; $pinfo = $this->db->select($where, '*', '', '`listorder` ASC, `id` DESC'); if (is_array($pinfo) && !empty($pinfo)) { foreach ($pinfo as $k => $rs) { if ($rs['setting']) { $rs['setting'] = string2array($rs['setting']); $pinfo[$k] = $rs; } else { unset($pinfo[$k]); } } extract($r); } else { return true; } } else { /** * 如果不存在 * * 取出数据的方式和上面一致 * * 但是在打散的数组的每个变量前面都加上了 P * * 所以对于该广告模块来说,充分使用了extract这个函数 * * 有兴趣的同学可以研究下 * */ $where = " `spaceid`='" . $id . "' AND `siteid`='" . $siteid . "' AND `disabled`=0 AND `startdate`<='" . $now . "' AND (`enddate`>='" . $now . "' OR `enddate`=0)"; $pinfo = $this->db->get_one($where, '*', '`listorder` ASC, `id` DESC'); if (is_array($pinfo) && $pinfo['setting']) { $pinfo['setting'] = string2array($pinfo['setting']); } extract($r); if (!is_array($pinfo) || empty($pinfo)) return true; extract($pinfo, EXTR_PREFIX_SAME, 'p'); } $file = CACHE_PATH . $path; /** * * 这里用的ob函数进行输出 * * 优点:不会因为php文件提前输出header而出错,又可以及时刷新缓存区而不浪费资源 */ ob_start(); /** * * 这里在文件输出流中引入了广告模版文件 * 而在原始的模版文件中存在着大量的php变量 * 这些变量和上面被打散的数组中的变量是一致的 * 也就是说在这一步 * 变量被巧妙的替换了 * 很自然的转化成了js文件 */ include template('poster', $type); $data = ob_get_contents(); /** * * 将合并后的文件内容存进变量后清空了ob文件流 */ ob_end_clean(); /** * * 最后根据路径写入文件 */ $strlen = pc_base::load_config('system', 'lock_ex') ? file_put_contents($file, $data, LOCK_EX) : file_put_contents($file, $data); @chmod($file, 0777); return true; } } ?> ~~~ ### 四、总结 根据上面的图文注释,小伙伴们都可以清楚的知道phpcms的广告是怎么产生的了吧。 配置文件+模版文件+数据库中具体数据=js广告文件 ### 五、后记 用了一晚上的时间,又重新分析了一下phpcms,这个功能原来在大连实训的时候写过,也是参考phpcms的,这回也算是复习吧。 温故知新,回头再看phpcms,还是有很多值得学习的。 看来有空还要研究下它的队列机制了。![微笑](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-01-18_569ca449c5105.gif)
';

ubuntu 上给PHP安装扩展 Msgpack 和 Yar

最后更新于:2022-04-01 09:55:44

本文为原创作品,转载请注明出处! 首先说明Yar是干什么的。 新浪著名的大神级人物鸟哥,开发的一个支持并行的PHP扩展。 源地址 http://www.laruence.com/2012/09/15/2779.html 其特点就是可以高效的封装好供外部访问的接口,用途嘛,![偷笑](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-01-18_569ca4488de4a.gif) ,你懂的。 下面开始实况直播,如何才能把大神的yar用上。 ### 一、下载。 恩,没错,在那个文章的底部,鸟哥提供了github的[下载地址](https://github.com/laruence/yar)。 但是,这是不够的,因为这个框架需要 一个名为 Msgpack 的[扩展](https://github.com/msgpack/msgpack-php),同样的,这个也是鸟哥维护的,再次膜拜!! ### 二、msgpack。 恩。。。。。 貌似下载好发现里面都是写.c .h 的文件,没错,我们需要自己来编译! **1.msgpack** 解压压缩包,直接看 README.md  ~~~ ## Install ### Install from PECL Msgpack is an PECL extension, thus you can simply install it by: ```` pecl install msgpack ```` ### Compile Msgpack from source ```` $/path/to/phpize $./configure $make && make install ```` ~~~ 恩,我们发现原来这个可以通过pecl在线安装 打开一个终端,输入 ~~~ pecl install msgpack ~~~ 发现没有成功,给的提示是这样的 ~~~ Failed to download pecl/msgpack within preferred state "stable", latest release is version 0.5.5, stability "beta", use "channel://pecl.php.net/msgpack-0.5.5" to install install failed ~~~ 这是由于msgpack还没有稳定版本,按照上面的提示,我们这样输入 ~~~ pecl install channel://pecl.php.net/msgpack-0.5.5 ~~~ 还是没有成功,但是提示变了 ~~~ WARNING: configuration download directory "/build/buildd/php5-5.5.3+dfsg/pear-build-download" is not writeable. Change download_dir config variable to a writeable dir to avoid this warning Cannot install, php_dir for channel "pecl.php.net" is not writeable by the current user ~~~ 看来是我们对文件夹没有写入权限,下面我们切换到root用户后重新执行上面的命令 ![大笑](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-01-19_569e21abc5518.gif) 内容太多,截下最后的一段吧。 ~~~ Build process completed successfully Installing '/usr/lib/php5/20121212/msgpack.so' Installing '/usr/include/php5/ext/msgpack/php_msgpack.h' install ok: channel://pecl.php.net/msgpack-0.5.5 configuration option "php_ini" is not set to php.ini location You should add "extension=msgpack.so" to php.ini ~~~ 下面的操作就是打开配置文件,把扩展写到文件中去 ~~~ sudo gedit /etc/php5/apache2/php.ini ~~~ 然后重启apache ~~~ sudo /etc/init.d/apache2 restart ~~~ 查看phpinfo ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-03-17_56ea1b26e3aaf.jpg) ![大笑](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-01-19_569e21abc5518.gif) 到此为止,我们就安装完了msgpack的PHP扩展。 ### 三、Yar 解压下载的 yar-master.zip 我们还是先看 README.md 这个文件,其实直接在github上看也是一样的。。。。 安装要求,要求安装一下的php扩展,这就是上一步的重要性! ~~~ ## Requirement - PHP 5.2+ - Curl - Json - Msgpack (Optional) ~~~ 安装yar ~~~ ### Install Yar Yar is an PECL extension, thus you can simply install it by: ``` pecl install yar ``` ~~~ 看来我们也可以通过pecl命令直接进行安装啊,貌似不是那么顺利 ~~~ downloading yar-1.2.1.tgz ... Starting to download yar-1.2.1.tgz (35,174 bytes) .........done: 35,174 bytes 28 source files, building running: phpize Configuring for: PHP Api Version: 20121113 Zend Module Api No: 20121212 Zend Extension Api No: 220121212 building in /tmp/pear/temp/pear-build-rootoSsn5u/yar-1.2.1 running: /tmp/pear/temp/yar/configure checking for grep that handles long lines and -e... /bin/grep checking for egrep... /bin/grep -E checking for a sed that does not truncate output... /bin/sed checking for cc... cc checking whether the C compiler works... yes checking for C compiler default output file name... a.out checking for suffix of executables... checking whether we are cross compiling... no checking for suffix of object files... o checking whether we are using the GNU C compiler... yes checking whether cc accepts -g... yes checking for cc option to accept ISO C89... none needed checking how to run the C preprocessor... cc -E checking for icc... no checking for suncc... no checking whether cc understands -c and -o together... yes checking for system library directory... lib checking if compiler supports -R... no checking if compiler supports -Wl,-rpath,... yes checking build system type... x86_64-unknown-linux-gnu checking host system type... x86_64-unknown-linux-gnu checking target system type... x86_64-unknown-linux-gnu checking for PHP prefix... /usr checking for PHP includes... -I/usr/include/php5 -I/usr/include/php5/main -I/usr/include/php5/TSRM -I/usr/include/php5/Zend -I/usr/include/php5/ext -I/usr/include/php5/ext/date/lib checking for PHP extension directory... /usr/lib/php5/20121212 checking for PHP installed headers prefix... /usr/include/php5 checking if debug is enabled... no checking if zts is enabled... no checking for re2c... no configure: WARNING: You will need re2c 0.13.4 or later if you want to regenerate PHP parsers. checking for gawk... no checking for nawk... nawk checking if nawk is broken... no checking whether to enable yar support... yes, shared checking for curl protocol support... yes, shared checking for msgpack packager support... no checking for cURL in default path... not found configure: error: Please reinstall the libcurl distribution - easy.h should be in <curl-dir>/include/curl/ ERROR: `/tmp/pear/temp/yar/configure' failed ~~~ 在这里我们可以看到是由于我们缺少一个 re2c 0.13.4 或者更新的版本才行,还有,我们的curl模块也不太符合要求,要求重装一下。 下面开始解决问题! 我在这个地址里找到了 re2c http://download.csdn.net/download/morre/5702707 ,在下面的解决过程中跳过了re2c的安装,看来上面的只是警告,没有太大问题。 让我们回到yar的编译 编译需要 phpize,所以我们要安装 phpize,安装phpize需要运行 ~~~ yum install php-devel ~~~ 返回的提示是 ~~~ 程序“yum”尚未安装。 您可以使用以下命令安装: sudo apt-get install yum ~~~ 恩,所以先安装yum,在安装phpize,注意,安装phpize的时候要以**root**用户执行! 然后重新安装了curl库,重启apache ~~~ sudo apt-get install curl libcurl3 libcurl3-dev php5-curl ~~~ sudo /etc/init.d/apache2 restart 下面再次执行pecl的安装 pecl install yar 然后就没有问题啦,经过短暂的等待,显示下面的提示,就安装完成啦! ~~~ Build process completed successfully Installing '/usr/lib/php5/20121212/yar.so'install ok: channel://pecl.php.net/yar-1.2.1configuration option "php_ini" is not set to php.ini locationYou should add "extension=yar.so" to php.ini ~~~ 下面的步骤和上次一样,修改配置文件,重启apache。 ~~~ sudo gedit /etc/php5/apache2/php.ini sudo /etc/init.d/apache2 restart ~~~ 重启之后,在phpinfo中并没有看见对应的扩展。
';

PHP编写rss源(续)

最后更新于:2022-04-01 09:55:41

本文为原创,转载请注明出处 编写完rss之后我们就拥有了一个rss源了,这样用户就可以通过浏览器或者rss阅读器来订阅rss源了。 Rss源的提 这里推荐百度的rss源提交地址 [http://ping.baidu.com/ping.html](http://ping.baidu.com/ping.html) 页面上的优化 在你的网站页面添加这样的一个引用就可以啦,  ~~~ <link rel="alternate" type="application/rss+xml" href="[http://rss.sina.com.cn/news/marquee/ddt.xml](http://rss.sina.com.cn/news/marquee/ddt.xml)" title="新闻中心_新浪网" /> ~~~
';

php编写RSS源

最后更新于:2022-04-01 09:55:39

#### 记编写rss源 点点细雨     2013年11月26日星期二 为了提高搜索引擎的收录速度,今天开始编写rss源来增加对搜索引擎的友好。 废话就不多打了,毕竟我打字速度也不快(O(∩_∩)O哈哈~)。 本文为原创,转载请注明出处! ### 一、开始解析rss文件。 下面是百度国内新闻rss的地址: [http://news.baidu.com/n?cmd=1&class=civilnews&tn=rss](http://news.baidu.com/n?cmd=1&class=civilnews&tn=rss) 下面是源文件 ![rss源文件](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-03-17_56ea1b25c5c8e.jpg) 很显然这就是一个xml文件 (~ o ~)~zZ ### 二、浏览器的解析 那么对于这样的一个rss文件,浏览器是怎样解析的呢? ie8: ![ie8的rss解析](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-03-17_56ea1b25ef364.jpg) QQ浏览器: ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-03-17_56ea1b261b8d5.jpg) 傲游: ![傲游](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-03-17_56ea1b263d08f.jpg) 谷歌: ![谷歌](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-03-17_56ea1b266bee8.jpg) 火狐: ![火狐](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-03-17_56ea1b268e352.jpg) 从上边看来,源文件为xml的rss源被浏览器解析成rss源,就直接可以通过浏览器订阅啦,请无视那个放弃rss功能的谷歌吧! T_T ### 三、编写: 分析源代码,掌握结构 ![注释](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-03-17_56ea1b26a957b.jpg) 我们要做的就是从我们的网站上获取到新闻并添加到rss中。 我们参考的方法是phpcms中百度网站地图的生成方式 下面分析下流程 1.创建xml文件头 2.写入新闻 3.加上xml文件结尾 这是创建的步骤,那么我们提交的rss网址的控制器流程呢,当然不能每次打开rss都要进行一次查询数据库,所以我们把rss存入文件中,让控制器直接打开文件,减少服务器压力。 我的项目是基于thinkphp的,下面是我的控制器,大家一看就明白了 代码 ~~~ <?php /** * 网站rss * */ class RssAction extends HomeAction { public function _initialize() { parent::_initialize(); //RBAC 验证接口初始化 $this->header = "<\x3Fxml version=\"1.0\" encoding=\"utf-8\"\x3F>\n<rss version=\"2.0\"><channel>"; $this->footer = "</channel>\n</rss>\n"; $this->rss=""; } public function rss(){ $config= require './config.php'; //网站配置 $rss_file = $rss_path . 'rss.xml'; if(file_exists($rss_file)){ $rss= file_get_contents($rss_file); echo $rss; }else{ $put= $this->index(); $this->rss(); } } public function index() { $config= require './config.php'; //网站配置 //var_dump($config); $this_domain=$config['web_url']; //获取rss配置信息 $rss_path=$config['rss_path']; $title=$config['rss_title']; $img_title=$config['rss_img_title']; $img_link=$config['rss_img_link']; $img_url=$config['rss_img_url']; $description=$config['rss_description']; $link=$config['rss_link']; $language=$config['rss_language']; $docs=$config['rss_docs']; $generator=$config['rss_generator']; $ttl=$config['rss_ttl']; //文章数量 $NewsDB=D("News"); $newsList=$NewsDB->getAllNews("","news_id desc",$ttl); //var_dump($newsList); //循环每条新闻,分别放入数组 $SourceDB = D("Source"); $items=array(); foreach ($newsList as $key => $value) { $date= date("Y:m-d H:i:s",$value['news_publish_time']); //获取来源 $sourceL=$SourceDB->getSource("so_id = ".$value['so_id']); $source=$sourceL['so_name']; $url=$this_domain.U('/Home/Index/content',array('id'=>$value['news_id'])); $item= $this->item($value['news_title'],$url,$date,$source,$value['news_author'],$value['news_intro']); // var_dump($item); $items[]=$item; } //var_dump($this->items); // var_dump($_SERVER['DOCUMENT_ROOT']); $rss_file = $_SERVER['DOCUMENT_ROOT'].$rss_path . 'rss.xml'; // echo $rss_file; @mkdir($dir, 0777, true); $result= $this->rss_build($items,$rss_file, $title, $img_title, $img_link, $img_url, $description, $link, $language, $docs, $generator, $ttl); // $this->success("生成站点地图成功"); //$file=fopen($rss_file,"r") or exit("Unable to open file!"); // var_dump($result); // echo $result; } /** * rss源的结构 * @param type $title * @param type $link * @param type $pubDate * @param type $source * @param type $author * @param type $description * @return type 数组 */ private function item($title, $link = '', $pubDate = '', $source = '', $author= '', $description = '') { $data = array(); $data['title'] = $title; $data['link'] = $link; $data['description'] = $description; $data['author'] = $author; $data['source'] = $source; $data['pubDate'] = $pubDate; return $data; } /** * 生成xml * @param type $file_name * @param type $this_domain * @param type $email * @param type $time * @return type */ private function rss_build($items,$file_name = null,$title="",$img_title='',$img_link='',$img_url='',$description='',$link='', $language='zh-cn',$docs='', $generator='', $ttl='') { //百度头部 $this->rss = ''; $this->rss = $this->header; $this->rss .= "<title>" . $title . "</title>\n"; $this->rss .= "<image>\n<title>".$img_title."\n</title>\n<link>".$img_link ."\n</link><url>". $img_url ."</url></image>\n"; $this->rss .= "<description>".$description."</description>\n"; $this->rss .= "<link>".$link."</link>\n"; $this->rss .= "<language>" . $language . "</language>\n"; $this->rss .= "<docs>" . $docs . "</docs>\n"; $this->rss .= "<generator>". $generator . "</generator>\n"; $this->rss .= "<ttl>" . $ttl . "</ttl>\n"; foreach ($items as $item) { $this->rss .= "<item>\n"; $this->rss .= "<title><![CDATA[" . $item['title'] . "]]></title>\n"; $this->rss .= "<link><![CDATA[" . $item['link'] . "]]></link>\n"; $this->rss .= "<pubDate> <![CDATA[" . $item['pubDate'] . "]]></pubDate>\n"; $this->rss .= "<source><![CDATA[" . $item['source'] . "]]></source>\n"; $this->rss .= "<author><![CDATA[" . $item['author'] . "]]></author>\n"; $this->rss .= "<description><![CDATA[" . $item['description'] . "]]></description>\n"; $this->rss .= "</item>\n"; } $this->rss .= $this->footer . "\n"; if (!is_null($file_name)) { return file_put_contents($file_name, $this->rss); } else { return $this->rss; } } } ~~~ ### 四、完善功能 当然,做完上面的还不算完整,为了保证可扩展性,我把rss的标题之类的都做成了配置文件,可以直接通过后台来修改。 ~~~ 'rss_path'=>'/tisumoon/', 'rss_title'=>'天树网新闻站', 'rss_img_title'=>'天树网', 'rss_img_link'=>'http://www.tisumoon.com/', 'rss_img_url'=>'', 'rss_description'=>'自媒体新闻网站。', 'rss_link'=>'http://www.tisumoon.com/', 'rss_language'=>'zh-cn', 'rss_docs'=>'', 'rss_generator'=>'http://www.tisumoon.com/', 'rss_ttl'=>'10', ~~~ ~~~ <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <title>网站RSS设置</title> <meta http-equiv="Content-Type" content="text/html; charset=utf-8"> <link rel='stylesheet' type='text/css' href='__PUBLIC__/Admin/css/admin_style.css' /> <script type="text/javascript" src="__PUBLIC__/js/jquery.min.js"></script> <script type="text/javascript" src="__PUBLIC__/js/formValidator.js"></script> <script type="text/javascript" src="__PUBLIC__/js/formValidatorRegex.js"></script> <script type="text/javascript"> $(document).ready(function(){ $.formValidator.initConfig({formid:"myform",autotip:true,onerror:function(msg,obj){ window.top.art.dialog({content:msg,lock:true,width:250,height:100,ok:function(){$(obj).focus();}}); }}); $("#rss_title").formValidator({onshow:"请输入订阅标题",onfocus:"请输入订阅标题"}).regexValidator({regexp:"ps_username",datatype: "enum",onerror:"应为 中文、字母、数字 或 _ 组成"}); $("#rss_img_title").formValidator({empty:true,onshow:"请输入图片提示",onfocus:"请输入图片提示"}); $("#rss_img_url").formValidator({empty:true,onshow:"请选择图片",onfocus:"请选择图片"}); $("#rss_img_link").formValidator({empty:true,onshow:"请输入图片链接,如:http://www.xxx.com/",onfocus:"请输入图片链接,如:http://www.xxx.com/"}).regexValidator({regexp:"^http[s]?:\/\/(.+)\/$",onerror:"格式应该为 http://www.xxx.com/,请以‘/’结束"}); $("#rss_link").formValidator({onshow:"请输入网站链接,如:http://www.xxx.com/",onfocus:"请输入网站链接,如:http://www.xxx.com/"}).regexValidator({regexp:"^http[s]?:\/\/(.+)\/$",onerror:"格式应该为 http://www.xxx.com/,请以‘/’结束"}); $("#rss_path").formValidator({onshow:"安装在根目录请使用:/",onfocus:"安装在根目录请使用:/"}).inputValidator({regexp:"^/\\w*",onerror:"格式应该为 /[xxx]"}); $("#rss_language").formValidator({empty:true,onshow:"请输入rss语言",onfocus:"默认为‘zh-CN’"}).inputValidator({max:10,onerror:"不能超过10个字符,请确认"}); $("#rss_docs").formValidator({empty:true,onshow:"请输入docs",onfocus:"请输入docs"}).inputValidator({max:30,onerror:"不能超过30个字符,请确认"}); $("#rss_description").formValidator({empty:true,onshow:"请输入网站描述",onfocus:"请输入网站描述"}).inputValidator({max:50,onerror:"不能超过20个字符,请确认"}); $("#rss_ttl").formValidator({onshow:"rss中展示的新闻条数",onfocus:"rss中展示的新闻条数"}).regexValidator({regexp:"num1",datatype: "enum",onerror:"应为正数"}); }); $("#rss_generator").formValidator({onshow:"请输入源网站,如:http://www.xxx.com/",onfocus:"请输入网站链接,如:http://www.xxx.com/"}).regexValidator({regexp:"^http[s]?:\/\/(.+)\/$",onerror:"格式应该为 http://www.xxx.com/,请以‘/’结束"}); </script> </head> <body> <form action="?s=Admin/Rss/update" method="post" id="myform"> <table width="98%" border="0" cellpadding="4" cellspacing="1" class="table"> <tr class="table_title"><td colspan="2">RSS订阅信息设置</td></tr> <tr class="ji"> <td class="left">订阅标题</td> <td><input type="text" name="con[rss_title]" id="rss_title" size="35" maxlength="50" value="{$con.rss_title}"> </td> </tr> <tr class="ji"> <td class="left">图片提示</td> <td><input type="text" name="con[rss_img_title]" id="rss_img_title" size="35" maxlength="50" value="{$con.rss_img_title}"> </td> </tr> <tr class="tr"> <td class="left">图片链接</td> <td ><input type="text" name="con[rss_img_link]" id="rss_img_link" size="35" maxlength="50" value="{$con.rss_img_link}" > </td> </tr> <tr class="tr"> <td class="left">图片路径</td> <td ><input type="file" name="img_url" id="rss_img_url" size="35" maxlength="50" ><img style="height: 100px;width: auto;" src="{$con.rss_img_url}"></img> </td> </tr> <tr class="tr"> <td class="left">网站链接</td> <td> <input type="text" name="con[rss_link]" id="rss_link" size="35" maxlength="50" value="{$con.rss_link}" > </td> </tr> <tr class="tr"> <td class="left">网站描述</td> <td> <textarea name="con[rss_description]" id="rss_description" style="width:500px;height:50px">{$con.rss_description}</textarea></td> </tr> <tr class="ji"> <td class="left">语言</td> <td><input type="text" name="con[rss_language]" id="rss_language" size="35" maxlength="50" value="{$con.rss_language}" > </td> </tr> <tr class="tr"> <td class="left">docs</td> <td><input type="text" name="con[rss_docs]" id="rss_docs" size="35" value="{$con.rss_docs}"> </td> </tr> <tr class="ji"> <td class="left">源网站</td> <td><input type="text" name="con[rss_generator]" id="rss_generator" size="35" maxlength="50" value="{$con.rss_generator}" ></td> </td> </tr> <tr class="tr"> <td class="left">新闻条数</td> <td> <input type="text" name="con[rss_ttl]" id="rss_ttl" size="35" maxlength="50" value="{$con.rss_ttl}"> </td> </tr> <tr class="tr"> <td class="left">Rss文件存放路径</td> <td> <input type="text" name="con[rss_path]" id="rss_path" size="35" maxlength="50" value="{$con.rss_path}"> </td> </tr> <tr class="ji"> <td colspan="2"> <input class="bginput" type="submit" name="dosubmit" value="提交"> <input class="bginput" type="reset" name="Input" value="重置" > </td> </tr> </table> </form> <include file="Index:footer" /> </body> </html> ~~~ ### 五、后记 本来想在网上找些资料把功能做出来,但是国内技术网站相互抄袭,一个文章内容只要标题一样在所有的网站上都是一样的,这种现象很不好,严重阻碍的技术型网站的进步,所以呢,还是自己研究写出来吧,本着开源的精神跟大家分享,如果那里不好请一定要指出来啊! 谢谢。
';

前言

最后更新于:2022-04-01 09:55:37

> 原文出处:[PHP问题集锦](http://blog.csdn.net/column/details/xiaoyu-php-qa.html) > 作者:[diandianxiyu_geek](http://blog.csdn.net/diandianxiyu_geek) **本系列文章经作者授权在看云整理发布,未经作者允许,请勿转载!** # PHP问题集锦 > 从不同角度解决开发过程中遇到的PHP的相关问题
';