月度归档:2013年02月

PHP SimpleXMLElement的陷阱

PHP 使用SimpleXMLElement的addChild方法添加另一个SimpleXMLElement对象的时候老是取不到完整的对象。原本参考了网上的例子以为可以直接添加,示例代码如下

1
2
3
4
5
6
7
8
9
10
11
12
13
<?php
$orders=new SimpleXMLElement('<?xml version="1.0" encoding="UTF-8"?><orders></orders> ');
for($i=1;$i<=5;$i++){
    $order=new SimpleXMLElement('<?xml version="1.0" encoding="UTF-8"?><order></order> ');
    $item=$order->addChild('item');
    $item->addChild('id',$i);
    $item->addChild('name','shoes');
    $item->addChild('price','110.00');
    //echo $order->asXML();
    $orders->addChild($order->getName(),$order);
    //$orders->{$order->getName()}[]=$order;
}
echo $orders->asXML();

发现$orders中的order子元素总是为空,不会包含item项等,但是在循环中调试打印出$order却又是完整。后来找到了这个,据说是因为SimpleXMLElement没有对要添加的对象做深复制,解决方法之一便是借助DOM。 继续阅读

PHP并发操作加锁

有时候在PHP程序中同时只允许一个进程在操作或者只想让一个进程去执行,这时就需要加锁,在网络上找到了phplock这个项目。phplock用于多进程模式下PHP并发操作加锁,以防止并发对同一文件的读写操作错误和缓存失效时,大量请求直接穿透到数据库,造成数据库压力宕机。
继续阅读

PHP异步执行长时间任务

长时间执行的任务不适合放在PHP中执行应当放在任务调度系统或消息系统中由后台程序去执行,但是有时候还是需要在PHP中执行下长时间的任务 ,并且客户端不需要返回值。实现的思路大体如下:首先客户端发起一个不需要等待返回的请求,服务器端则需要忽略请求中断和执行时间,以免中途退出。

当有请求到达时,服务器端执行任务,在这里会产生一个文件。服务器端文件:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
<?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");
&#91;/php&#93;
 
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&#91;'port'&#93;)? $url_array&#91;'port'&#93; : 80;        
    $fp = fsockopen($url_array&#91;'host'&#93;, $port, $errno, $errstr, 30);        
    if (!$fp){                
        return FALSE;        
    }        
    $getPath = $url_array&#91;'path'&#93; ."?". $url_array&#91;'query'&#93;;        
    if(!empty($post_data)){                
        $method = "POST";        
    }        
    $header = $method . " " . $getPath;        
    $header .= " HTTP/1.1\r\n";        
    $header .= "Host: ". $url_array&#91;'host'&#93; . "\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;
}
triggerRequest($url);

2.使用curl来发起请求,可以方便的设置传递参数,cookie等,比fsockopen简洁许多,需要安装php_curl扩展

1
2
3
4
5
6
7
8
9
<?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做简单的反向代理

Nginx是一个HTTP和反向代理服务器,可做为反向代理实现负载均衡的例子,也可以作为代理服务器,也经常作为web服务器使用。如果一台服务器装有多个web服务器则必须监听多个端口,对于用户的访问将是不友好,则需要一个统一的前端来进行分发。本文只是简单的利用Nginx作为前端代理服务器,代理不同的后端服务器:IIS和Apache,实现不同的域名解析至不同的服务器。

首先更改IIS的监听端口为8000,Apache的监听端口为9000,保证Nginx占有80端口和443端口。然后更改nginx.conf添加以下内容 继续阅读

JasperReports flash打印实现

JasperReports是一个基于Java的开源报表工具,可以在ireport中进行设计后,输出HTML,PDF,Excell,OpenOffice和Word格式。JasperReports支持applet方式打印,但是flash方式却是注释掉的。在net\sf\jasperreports\flex\view\Viewer.mxml文件中

1
2
3
4
5
6
7
8
9
10
<!--
<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文件上面的文字修改为

1
2
3
4
5
6
7
8
9
10
<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函数,启用打印按钮,将

1
2
3
4
5
6
7
8
9
10
11
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;
}

修改为

1
2
3
4
5
6
7
8
9
10
11
12
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文件,以支持打印

1
import net.sf.jasperreports.flex.view.PrintManager;

在Viewer.mxml增加打印函数btnPrintReport

1
2
3
4
public function  btnPrintReport():void
{
    PrintManager.printAll(jrpxmlUrl,pageFetchSize,report);
}

net\sf\jasperreports\flex\view\PrintMananger.as文件内容

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
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