有时候在PHP程序中同时只允许一个进程在操作或者只想让一个进程去执行,这时就需要加锁,在网络上找到了phplock这个项目。phplock用于多进程模式下PHP并发操作加锁,以防止并发对同一文件的读写操作错误和缓存失效时,大量请求直接穿透到数据库,造成数据库压力宕机。
继续阅读
作者归档:admin
PHP异步执行长时间任务
长时间执行的任务不适合放在PHP中执行应当放在任务调度系统或消息系统中由后台程序去执行,但是有时候还是需要在PHP中执行下长时间的任务 ,并且客户端不需要返回值。实现的思路大体如下:首先客户端发起一个不需要等待返回的请求,服务器端则需要忽略请求中断和执行时间,以免中途退出。
当有请求到达时,服务器端执行任务,在这里会产生一个文件。服务器端文件:
<?php //ob_start(); //header('Content-Type:text/html;charset=utf-8'); //header('Connection:close'); //flush(); ignore_user_abort(true);//忽略客户端连接中断 set_time_limit(0);//忽略页面执行超时 //Todo:do something here sleep(10); fopen(dirname( __FILE__ ).'\\'.time(), "w"); [/php] 1.使用<a href="http://php.net/manual/en/function.fsockopen.php">fsockopen</a>来请求服务端执行任务,该方法需要自己拼凑header,包括参数等 <?php function triggerRequest($url, $post_data = array(), $cookie = array()){ $method = "GET"; //可以通过POST或者GET传递一些参数给要触发的脚本 $url_array = parse_url($url); //获取URL信息,以便平凑HTTP HEADER $port = isset($url_array['port'])? $url_array['port'] : 80; $fp = fsockopen($url_array['host'], $port, $errno, $errstr, 30); if (!$fp){ return FALSE; } $getPath = $url_array['path'] ."?". $url_array['query']; if(!empty($post_data)){ $method = "POST"; } $header = $method . " " . $getPath; $header .= " HTTP/1.1\r\n"; $header .= "Host: ". $url_array['host'] . "\r\n "; //HTTP 1.1 Host域不能省略 $header .= "Connection:Close\r\n\r\n"; if(!empty($cookie)){ $_cookie = strval(NULL); foreach($cookie as $k =--> $v){ $_cookie .= $k."=".$v."; "; } $cookie_str = "Cookie: " . base64_encode($_cookie) ." \r\n";//传递Cookie $header .= $cookie_str; } if(!empty($post_data)){ $_post = strval(NULL); foreach($post_data as $k => $v){ $_post .= $k."=".$v."&"; } $post_str = "Content-Type: application/x-www-form-urlencoded\r\n";//POST数据 $post_str .= "Content-Length: ". strlen($_post) ." \r\n";//POST数据的长度 $post_str .= $_post."\r\n\r\n "; //传递POST数据 $header .= $post_str; } fwrite($fp, $header); fclose($fp); return true; } $url='http://127.0.0.1/learn/asyn/server.php'; triggerRequest($url);
2.使用curl来发起请求,可以方便的设置传递参数,cookie等,比fsockopen简洁许多,需要安装php_curl扩展
<?php $ch = curl_init(); $data = array('param' => '1'); curl_setopt($ch, CURLOPT_URL, 'http://127.0.0.1/learn/asyn/server.php'); curl_setopt($ch, CURLOPT_POST, 1); curl_setopt($ch, CURLOPT_POSTFIELDS, $data); curl_setopt($ch, CURLOPT_TIMEOUT, 1);//1秒后立即执行 curl_exec($ch); curl_close($ch);
也可以采用popen,ajax发起请求,详见参考链接。
参考链接
fsockopen函数用法
使用fscok实现异步调用PHP
PHP实现异步调用方法研究
说说php的异步请求
php curl常用的5个例子
Nginx做简单的反向代理
JasperReports flash打印实现
JasperReports是一个基于Java的开源报表工具,可以在ireport中进行设计后,输出HTML,PDF,Excell,OpenOffice和Word格式。JasperReports支持applet方式打印,但是flash方式却是注释掉的。在net\sf\jasperreports\flex\view\Viewer.mxml文件中
<!-- <mx:Button width="22" toolTip="Print Report" id="btnPrintReport0" buttonMode="true"enabled="false" > <mx:icon>@Embed(source='images/print.GIF')</mx:icon> </mx:Button> <mx:Button width="22" toolTip="Print Report" id="btnReload" buttonMode="true" enabled="true" click="btnReloadClick()"> <mx:icon>@Embed(source='images/reload.GIF')</mx:icon> </mx:Button> -->
本文主要完成JasperReports的flash打印功能,是基于JasperReports Flash Viewer 4.0.0修改,参考了网络上基于3.0版本的修改。将Viewer.mxml文件上面的文字修改为
<mx:Button width="22" toolTip="Print Report" id="btnPrintReport0" buttonMode="true" enabled="false" click="btnPrintReport()"> <mx:icon>@Embed(source='images/print.GIF')</mx:icon> </mx:Button> <!-- <mx:Button width="22" toolTip="Print Report" id="btnReload" buttonMode="true" enabled="true" click="btnReloadClick()"> <mx:icon>@Embed(source='images/reload.GIF')</mx:icon> </mx:Button> -->
在Viewer.mxml中找到refreshPage函数,启用打印按钮,将
if (report.pageCount > 0) { var pageCanvas:PageCanvas = new PageCanvas(report.pages[pageIndex]); pageCanvas.scaleX = zoomRatio; pageCanvas.scaleY = zoomRatio; pageBox.visible = false; pageBox.removeAllChildren(); pageBox.addChild(pageCanvas); pageBox.visible = true; }
修改为
if (report.pageCount > 0) { var pageCanvas:PageCanvas = new PageCanvas(report.pages[pageIndex]); pageCanvas.scaleX = zoomRatio; pageCanvas.scaleY = zoomRatio; pageBox.visible = false; pageBox.removeAllChildren(); pageBox.addChild(pageCanvas); pageBox.visible = true; btnPrintReport0.enabled = true; }
在Viewer.mxml中引入net\sf\jasperreports\flex\view\PrintMananger.as文件,以支持打印
import net.sf.jasperreports.flex.view.PrintManager;
在Viewer.mxml增加打印函数btnPrintReport
public function btnPrintReport():void { PrintManager.printAll(jrpxmlUrl,pageFetchSize,report); }
net\sf\jasperreports\flex\view\PrintMananger.as文件内容
package net.sf.jasperreports.flex.view { import flash.events.EventDispatcher; import flash.events.SecurityErrorEvent; import flash.events.Event; import flash.events.ProgressEvent; import mx.core.UIComponent; import mx.collections.IList; import mx.collections.ArrayCollection; import net.sf.jasperreports.flex.view.PageCanvas; import net.sf.jasperreports.flex.model.Report; import net.sf.jasperreports.flex.xml.ReportFactory; import flash.events.HTTPStatusEvent; import flash.net.URLLoader; import flash.net.URLRequest; import flash.events.IOErrorEvent; import mx.printing.FlexPrintJobScaleType; import mx.printing.FlexPrintJob; import mx.core.Application; import mx.containers.VBox; import mx.events.FlexEvent; public class PrintManager extends EventDispatcher { private var url:String; private var urlLoader:URLLoader; private var report:Report; private var pageIndex:int = 0; private var pageFetchSize:int = 1; private var componentsToBeInitialized:int = 0; private var pagesPrint:Array = []; public const LOAD_PAGE:String="loadPage"; public const ALL_PAGE:String = "allPageLoader"; public function PrintManager(){ super(); } public function get url():String { return url; } public function set url(value:String):void { url=value; } public function set fetchSize(fetchSize:int):void { pageFetchSize = fetchSize; } public static function printAll(url:String,fetchSize:int,report:Report):void { var pm:PrintManager = new PrintManager(); pm.url = url; pm.pageFetchSize = fetchSize; pm.report = report; pm.loadAll(); } private function loadAll():void { this.addEventListener(LOAD_PAGE, onLoadPage); this.addEventListener(ALL_PAGE, onAllPageLoaded); pageIndex=0; if (report) { var loadFlag:Boolean=false; while (pageIndex < report.pageCount) { if (!report.pages[pageIndex]) { loadFlag=true; break; } pageIndex++; } } if (loadFlag) { loadPage(); } else{ removeEventListener(LOAD_PAGE, onLoadPage); dispatchEvent(new Event(ALL_PAGE)); } } private function onLoadPage(e:Event):void { pageIndex++; if (pageIndex < report.pageCount) { if(!report.pages[pageIndex]){ loadPage(); } } else{ removeEventListener(LOAD_PAGE, onLoadPage); dispatchEvent(new Event(ALL_PAGE)); } } public function onAllPageLoaded(event:Event):void { var cur:int; var uc:UIComponent; var pj:*; if (report != null){ pj = new FlexPrintJob(); pj.printAsBitmap = false; if (pj.start()){ cur = 0; while (cur < report.pageCount) { uc = processPage(new PageCanvas(report.pages[cur])); Application.application.addChild(uc); pj.addObject(uc); Application.application.removeChild(uc); cur++; }; pj.send(); }; } else { }; } private function processPage(param1:PageCanvas):UIComponent{ var vbox:* = new VBox(); vbox.horizontalScrollPolicy = "off"; vbox.verticalScrollPolicy = "off"; vbox.width = report.pageWidth; vbox.height = report.pageHeight; vbox.setStyle("backgroundColor", "#FFFFFF"); vbox.addChild(param1); return (vbox); } private function loadPage():void { urlLoader=new URLLoader(); urlLoader.addEventListener(Event.COMPLETE, completeHandler); urlLoader.addEventListener(Event.OPEN, openHandler); urlLoader.addEventListener(ProgressEvent.PROGRESS, progressHandler); urlLoader.addEventListener(SecurityErrorEvent.SECURITY_ERROR, securityErrorHandler); urlLoader.addEventListener(HTTPStatusEvent.HTTP_STATUS, httpStatusHandler); urlLoader.addEventListener(IOErrorEvent.IO_ERROR, ioErrorHandler); if (report) { var goRight:Boolean = true; var goLeft:Boolean = true; var right:int = 0; var left:int = 0; while(goRight || goLeft) { if ( goRight && left + right + 1 < pageFetchSize && pageIndex + right + 1 < report.pageCount && !report.pages[pageIndex + right + 1] ) { right++; } else { goRight = false; } if ( goLeft && left + right + 1 < pageFetchSize && pageIndex - left - 1 >= 0 && !report.pages[pageIndex - left - 1] ) { left++; } else { goLeft = false; } } urlLoader.load(new URLRequest(url + "&startPage=" + (pageIndex - left) + "&endPage=" + (pageIndex + right))); } else { //first load; pageIndex == 0 urlLoader.load(new URLRequest(url + "&page=" + pageIndex)); } } private function completeHandler(event:Event):void { var newReport:Report = ReportFactory.create(XML(urlLoader.data)); var i:int; var pages:IList; if (report) { pages = report.pages; } else { //first load report = newReport; pages = new ArrayCollection(new Array(report.pageCount)); } for(i = newReport.startPageIndex; i <= newReport.endPageIndex; i++) { pages[i] = newReport.pages[i - newReport.startPageIndex]; } report.pages = pages; report.startPageIndex = Math.min(report.startPageIndex, newReport.startPageIndex); report.endPageIndex = Math.max(report.endPageIndex, newReport.endPageIndex); refreshPage(); } private function openHandler(event:Event):void { trace("openHandler: " + event); } private function progressHandler(event:ProgressEvent):void { trace("progressHandler loaded:" + event.bytesLoaded + " total: " + event.bytesTotal); } private function securityErrorHandler(event:SecurityErrorEvent):void { trace("securityErrorHandler: " + event); } private function httpStatusHandler(event:HTTPStatusEvent):void { trace("httpStatusHandler: " + event); } private function ioErrorHandler(event:IOErrorEvent):void { trace("ioErrorHandler: " + event); } private function refreshPage():void { if (report) { this.dispatchEvent(new Event(this.LOAD_PAGE)); } } } }
编译Main.mxml运行,即实现打印功能,但是包含图片的打印依然打印不出来。对于这种动态图片的打印添加了等待事件完成,仍能无效,不知道有没有好的实现。
参考链接:
JasperReports Library
完成Flex报表设计、生成、打印功能
Flex 4 Printing Problem with dynamic components
PHP/Java Bridge笔记
PHP/Java Bridge是基于xml的网络协议的实现,该协议使得本地脚本语言引擎( 比如PHP,Python)能够连接Java虚拟机。它比通过SOAP的RPC调用更快,更节省服务器资源;比直接的Java本地接口通信要更快和更可靠,不需要额外的组件。Java应用比PHP要多,组件和类库也比PHP要多,比如JasperReports,通过PHP/Java Bridge可以为PHP 所用,当然也可以采用其他方式进行调用,比如官方的SOAP示例。
网上的关于JavaBridge安装文章较旧,现在的JavaBridge安装已经不需要java.so或php_java.dll,只需要php安装版本大于5.0,JDK版本大于1.4.2。本文是将JavaBridge放在Tomcat下运行的,独立运行参照此文设置。 继续阅读