├── .gitignore
├── README.md
├── _lp
├── core
│ ├── config
│ │ └── core.config.php
│ ├── controller
│ │ └── core.class.php
│ ├── lib
│ │ ├── core.function.php
│ │ ├── db.function.php
│ │ └── db.sae.function.php
│ ├── model
│ │ └── README
│ └── view
│ │ └── layout
│ │ └── web
│ │ ├── main
│ │ └── default
│ │ │ └── index.tpl.html
│ │ └── side
│ │ └── default
│ │ └── index.tpl.html
├── lp.init.php
├── simpletest
│ ├── VERSION
│ ├── arguments.php
│ ├── authentication.php
│ ├── autorun.php
│ ├── browser.php
│ ├── collector.php
│ ├── compatibility.php
│ ├── cookies.php
│ ├── default_reporter.php
│ ├── detached.php
│ ├── dumper.php
│ ├── eclipse.php
│ ├── encoding.php
│ ├── errors.php
│ ├── exceptions.php
│ ├── expectation.php
│ ├── extensions
│ │ ├── pear_test_case.php
│ │ ├── testdox.php
│ │ └── testdox
│ │ │ └── test.php
│ ├── form.php
│ ├── frames.php
│ ├── http.php
│ ├── invoker.php
│ ├── mock_objects.php
│ ├── page.php
│ ├── php_parser.php
│ ├── recorder.php
│ ├── reflection_php4.php
│ ├── reflection_php5.php
│ ├── remote.php
│ ├── reporter.php
│ ├── scorer.php
│ ├── selector.php
│ ├── shell_tester.php
│ ├── simpletest.php
│ ├── socket.php
│ ├── tag.php
│ ├── test_case.php
│ ├── tidy_parser.php
│ ├── unit_tester.php
│ ├── url.php
│ ├── user_agent.php
│ ├── web_tester.php
│ └── xml.php
└── st.init.php
├── config
├── app.config.php
└── db.config.php
├── controller
├── app.class.php
└── default.class.php
├── index.php
├── lib
└── app.function.php
├── local
└── zh_cn.lang.php
├── model
└── README
├── static
├── css
│ ├── bootstrap-responsive.min.css
│ ├── bootstrap.min.css
│ ├── ie6.min.css
│ └── style.css
├── image
│ ├── cross.png
│ ├── glyphicons-halflings-white.png
│ └── glyphicons-halflings.png
└── script
│ ├── app.js
│ ├── bootstrap.js
│ ├── bootstrap.min.js
│ ├── html5.js
│ └── ie6.min.js
├── test
├── index.html
├── index.php
├── js.unit.js
└── phptest
│ ├── core.test.php
│ ├── fast.test.php
│ └── sae.test.php
└── view
└── layout
├── ajax
├── default.tpl.html
├── default
│ └── test.tpl.html
└── info.tpl.html
├── mobile
├── default.tpl.html
└── default
│ ├── index.tpl.html
│ └── mobile.tpl.html
├── rest
└── default.tpl.html
└── web
├── default.tpl.html
├── footer.tpl.html
├── header.tpl.html
├── info.tpl.html
├── main
└── default
│ ├── index.tpl.html
│ └── test.tpl.html
└── side
└── default
└── index.tpl.html
/.gitignore:
--------------------------------------------------------------------------------
1 | .DS_Store
2 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # LAZYPHP简介
2 |
3 | LazyPHP(以下简称LP)是一个轻框架.
4 |
5 | 之所以开发这么一个框架,是因为其他框架给的太多。在高压力的情况下,ORM和盘根错节的对象树反而将简单的页面请求处理复杂化,在调试和性能上带来反面效果。
6 |
7 | LP采用函数式接口封装对象,对内通过面向对象实现代码重用,对外则提供简明扼要的操作函数。开发者甚至不用理解面向对象就能很好的使用,这让一些初级程序员很容易就开发出强壮的应用。
8 |
9 | 在数据库等模块的加载上,LP采用LazyLoad方式,并用$GLOBALS实现全局单件,在方便和高效之间找到了一个平衡点。这也是LP框架名字中Lazy的来源。
10 | LP在新浪大量使用已经将近3年,每天承载的请求达千万级别。由于LP易读易学,使用LP的开发者之间沟通非常容易,而新同事也可以很快融入进来。
11 |
12 | LP3是LP最新的版本,最主要的调整是重新定义了Layout规则,以应对日益增多的Ajax,Mobile和Rest请求。同样是由于这个原因,LP3和之前的版本不兼容,我们建议大家在新项目中采用LP3。
13 |
14 | # LP3 实例
15 | 基于LP3的全平台开源项目 团队效率工具 TeamToy http://teamtoy.net/
16 |
17 | # LP3简明教程
18 |
19 | LP是一个轻框架。它只是打算帮你处理掉每个Web应用都需要重新开始的那部分东西,并不打算成为一个大而全的Lib(我说的真的不是ZendFrameWork)。
20 |
21 | LP只包含一个FrontController+Layout系统+20个常用函数。你只需要花上10分钟了解这些东西,就能完全得掌握LP。
22 |
23 | ## FRONTCONTROLLER
24 | FrontController(以下简称FC)翻译过来叫前端控制器,在LP中,所有的动态请求(不包括静态文件)都会经过FC。使用FC的好处是可以统一控制全部请求,举例而言,你只需要在FC中添加几行代码,就可以精确控制哪些controller和action不可以访问。
25 |
26 | LP3的FC你可以看成就是ROOT/index.php(实际上分发逻辑在_lp/lp.init.php),所有的请求都在这里处理。不管你是用户登录还是浏览文章,在LP上用户访问的页面都是index.php。
27 |
28 | FC根据Controller和Action对请求进行分组,并调用对应的模块来进行处理。如何定义Controller和Action?最简单的办法是把一个数据表对应到一个Controller,而对这个数据表的相关操作自然就成为了Action。
29 |
30 | 比如,我们会定义一个叫做User的Controller,而把Login,Logout,Detail 作为User的Action。
31 |
32 | 我们在访问LP时,把要请求的Controller和Action通过参数c和a传递给FC。
33 |
34 | ```php
35 | /index.php?c=user&a=login
36 | ```
37 |
38 | 上边这个访问告诉FC去加载名为User的Controller,并调用名为Login的方法。
39 |
40 | 在实现上,Controller被放到AROOT.controller目录下,以Class形式存在,而Action就是这个Class的一个方法。
41 |
42 | 下边几行伪代码描述了这个其实很简单的过程:
43 |
44 | ```php
45 | // FC取得参数
46 | $c = $_REQUEST['c'] ;
47 | $a = $_REQUEST['a'] ;
48 |
49 | // controller文件名和Class名
50 | $cont_file = AROOT . ‘controller/’ . $c . ‘/’ . $a . ‘.class.php’;
51 | $class_name =$c .’Controller’ ;
52 |
53 | // 载入文件
54 | require_once( $cont_file );
55 |
56 | // 调用方法
57 | $o = new $class_name;
58 | call_user_func( array( $o , $a ) );
59 | ```
60 |
61 | 实际上,编写应用的过程就是不断的添加Controller和Action并把它实现。
62 |
63 | 下边是一个Controller Class的样子:
64 |
65 | ```php
66 | class defaultController extends appController
67 | {
68 | function __construct()
69 | {
70 | parent::__construct();
71 | }
72 |
73 | function index()
74 | {
75 | $data['title'] = $data['top_title'] = ‘首页’;
76 | render( $data );
77 | }
78 | }
79 | ```
80 |
81 | ## MVC和LAYOUT
82 | LP是遵循MVC模式的,它的业务逻辑和显示逻辑是完全分离的。Controller处理了业务逻辑,我们使用模板来处理显示逻辑。
83 |
84 | LP所有的模板都被放在AROOT.view下边,通过在Controller中使用Render函数来渲染模板。
85 |
86 | 以下是Render函数的伪代码:
87 |
88 | ```php
89 | function render( $data = NULL , $layout = NULL , $sharp = ‘default’ )
90 | {
91 | $layout_file = AROOT . ‘view/layout/’ . $layout . ‘/’ . $sharp . ‘.tpl.html’;
92 | @extract( $data );
93 | require( $layout_file );
94 | }
95 | ```
96 |
97 | 可以看到,Render接受一个$data数组,然后将数组中的数据extract出来,这样一个原本是$data['user']的数据在模板里边就能通过$user访问了。而载入模板部分更简单,只是直接require。这是因为LP直接使用PHP来做模板的解释引擎。我们推荐大家在模板中采用PHP的短标签语法以保持高的可读性:
98 |
99 | ```php
100 | = 9 ): ?>
101 | 亲,你是鹳狸猿
102 |
103 | 亲,你是平民,天黑请闭眼
104 |
105 | ```
106 |
107 | 上边是一个使用短标签的模板的例子。if,foreach都可以这样写。切忌在模板中使用{},这会让你的模板看起来很奇葩。
108 |
109 | 为了实现模板的重用,我们引入了Layout系统。
110 |
111 | 来看一个经常遇到的例子,网站头部导航和页脚版权部分的重用。
112 |
113 | 最简单和最容易想到的处理办法是这样的:将头部保存为header.tpl.html,将页脚保存为footer.tpl.html。然后直接在模板中用include函数载入即可。
114 |
115 | 这样很OK,但是当我们有10个模板要处理的时候,你会发现每个模板都要去include header和footer。而在这些模板中,header和footer其实是不变的,变的是中间的部分。
116 |
117 | 于是我们为这些相同模板建立一个通用的模板文件,叫做sharpA.tpl.html,在styleA中我们指定好header和footer,然后sharpA根据FC接收到的C和A变量(还记得吧)去加载对应子目录下模板。这样我们只需要创建C和A对应的模板就可以了。下边是一个典型的sharp模板。
118 |
119 | <html>
120 | <body>
121 | <div id="hd" ><?php @include_once( dirname(__FILE__) ) . DS . 'header.tpl.html'; ?></div>
122 |
123 | <div id="bd">
124 | <div id="side">
125 | <?php
126 | include( AROOT . 'view' . DS . 'layout' . DS . g('layout') . DS . 'side' . DS . g('c') . DS . g('a') . '.tpl.html' );
127 |
128 | ?>
129 | </div>
130 | <div id="main">
131 | <?php
132 | include( AROOT . 'view' . DS . 'layout' . DS . g('layout') . DS . 'main' . DS . g('c') . DS . g('a') . '.tpl.html' );
133 | ?>
134 | </div>
135 | </div>
136 | </div>
137 | <div id="ft"><?php @include_once( dirname(__FILE__) ) . DS . 'footer.tpl.html'; ?></div>
138 |
139 | </body>
140 | </html>
141 |
142 |
143 | 当一个sharp满足不了需求时,我们可以再创建sharpB.tpl.html。styleB可以选择性的共享sharpA的header和footer,也可以载入自己特定的header。我们把sharpA,sharpB…等通用模板放到一个目录下,叫做一个Layout。
144 |
145 | 目前Layout按照访问方式分为Web,Ajax,Mobile和Rest四种。当你为你的游戏机或者电视机创建一组特定风格的sharp模板时,你可以创建一个名叫TV或者PFP的Layout目录。
146 |
147 | 切换Sharp和Layout非常简单,只需要修改Render函数中第二和第三个参数就可以了。在没有指定的情况下,LP3会启用Layout下的default sharp模板,同时还会根据请求的方式,自动加载Web,Mobile或者Ajax Layout。
148 |
149 | 再回过头来说MVC,我们已经了解了C和V在LP的使用。而M就是根据请求参数,从数据库或者其他地方取得数据的过程。在LP3之前,数据是直接在Controller中查询数据库取得的。
150 |
151 | ```php
152 | function show()
153 |
154 | {
155 |
156 | $uid = intval($_REQUEST['uid']);
157 |
158 | if( $uid < 1 ) return info_page(‘错误的uid’);
159 |
160 | $data['user'] = get_line( “SELECT * FROM `user` WHERE `uid` = ‘” . $uid . “‘ LIMIT 1″ );
161 |
162 | render( $data );
163 |
164 | }
165 |
166 | ```
167 |
168 | 这种方式将SQL散落在各个Action中,不利于重用和修改。所以在LP3中,我们采用专门的model文件来放置Controller中用到的数据操作函数。还是用上边的例子,我们假设这是一个名为User的Controller的Show Action。那么在LP3中我们推荐的做法如下:
169 |
170 | 首先在 AROOT/model目录下创建一个名为user.function.php的文件。
171 |
172 | 然后在文件中写入获取用户信息的函数:
173 |
174 | ```php
175 | function get_user_info_by_id( $uid )
176 |
177 | {
178 |
179 | return get_line( “SELECT `name` ,`email` , `bod` FROM `user` WHERE `uid` = ” . intval($uid) . ” LIMIT 1 ” )
180 |
181 | }
182 | ```
183 |
184 | user.function.php将在请求参数包含?c=user 时自动加载。所以我们可以把show改为下边的样子:
185 |
186 | ```php
187 | function show()
188 |
189 | {
190 |
191 | $uid = intval($_REQUEST['uid']);
192 |
193 | if( $uid < 1 ) return info_page(‘错误的uid’);
194 |
195 | $data['user'] = get_user_info_by_id( $uid );
196 |
197 | render( $data );
198 |
199 | }
200 | ```
201 |
202 | 这样在其他的Action,比如User/settings 中,我们可以通过get_user_info_by_id 函数重用代码。通过函数封装重复SQL还有一个好处是方便对SQL进行统一处理,加手工Cache就是一个经常能遇到的需求。
203 |
204 | ## 常用函数
205 | LP3中的函数主要有3类,迅捷函数,功能函数和数据库函数,一共20个左右。
206 |
207 | ### 迅捷函数
208 |
209 | 迅捷函数是一系列的函数缩写:
210 |
211 |
212 | function c( $str ) // 读取配置文件中$str为key的对应的value
213 | function v( $str ) // 取得 $_REQUEST[$str] 的数据,不存在不会报warning
214 | function z( $str ) // strip_tags
215 | function g( $str ) // 取得 $GLOBALS[$str] 的数据
216 | function t( $str ) // trim
217 | function u( $str ) // urlencode
218 |
219 |
220 | ### 功能性函数
221 |
222 |
223 | function render( $data = NULL , $layout = NULL , $style = ‘default’ ) // Layout
224 | function info_page( $info ) // 系统提示信息
225 | function ajax_echo( $info ) // 输出提示信息,包含永不过期的header
226 | function uses( $file ); // 载入lib目录下的文件
227 |
228 |
229 | ### 数据库函数
230 |
231 |
232 | function s( $str , $db = NULL ) // mysql_real_escape_string
233 | function prepare( $sql , $array ) // 将数组中的变量顺序替换SQL中的?
234 | function db() // 使用config目录下的数据库设置,创建并返回数据库链接
235 | function get_data( $sql , $db = NULL ) // 以二维数组的方式返回$sql对应的结果
236 | function get_line( $sql , $db = NULL ) // 以一维数组的方式返回$sql对应的单行结果
237 | function get_var( $sql , $db = NULL ) // 以变量的方式返回一个数值
238 | function last_id( $db = NULL ) // last id
239 | function run_sql( $sql , $db = NULL ) // 运行sql,不返回结果集
240 | function db_error() // 数据库错误信息
241 | function db_errno() // 数据库错误编号
242 | function close_db( $db ) // 显式关闭数据库链接
243 |
244 |
245 | ### 特别说明
246 |
247 | 其中要详细说明的有两个:
248 |
249 | #### C($KEY)和配置文件
250 |
251 | LP将应用配置信息保存在AROOT/config/app.config.php下,使用$GLOBALS['config']超全局变量以数组形式保存。使用c($key)的方式,可以在MVC各个地方获取。
252 |
253 | #### PREPARE()函数
254 |
255 | 这个函数是LP3新引入的,主要是希望减少SQL注入的问题。使用方式如下:
256 |
257 |
258 | echo $sql = prepare( “SELECT * FROM `user` WHERE `name` = ?s AND `uid` = ?i AND `level` = ?s LIMIT 1″ , array( “Easy’” , ‘-1′, ’9.56′ ) );
259 |
260 |
261 | 输出结果为:
262 |
263 |
264 | SELECT * FROM `user` WHERE `name` = ‘Easy\” AND `uid` = ‘-1′ AND `level` = ’9.56′ LIMIT 1
265 |
266 |
267 | 使用prepare函数时要注意:SQL必须使用双引号,【?i】表示整数,【?s】表示整数以外的其他值。prepare会无例外的mysql_real_escape_string,然后在两边加上单引号。
268 |
269 | ## CSS,JAVASCRIPT和AJAX
270 |
271 | LP3采用BootStrap这个流行的前端框架,[你可以从这里看到它的详细介绍](http://twitter.github.com/bootstrap/)。
272 |
273 | JavaScript库上,LP3开始换为JQuery。[这里是JQuery API的参考手册](http://api.jquery.com/)。
274 |
275 | 为了方便不熟悉的同学也能使用好Ajax,LP3自己实现了Ajax传输数据的JS函数。这些函数都放在AROOT/static/script/app.js中。
276 |
277 | ```javascript
278 | $(‘#标签ID’).load(‘URL’); // 是由JQuery自身实现的,可以方便的无刷新载入页面。
279 |
280 | send_form_in( ‘FROMID’ ); // 将form表单中的数据通过Ajax提交(file类型除外),并将服务器返回的HTML显示在Form表单顶部
281 |
282 | send_form_pop(‘FROMID’); // 将form表单中的数据通过Ajax提交(file类型除外),并将服务器返回的HTML显示在浮动图层中
283 | ```
284 |
285 | 好了,这里就是关于LP3 的一切了,希望LP3能让你更快的完成工作。
286 |
--------------------------------------------------------------------------------
/_lp/core/config/core.config.php:
--------------------------------------------------------------------------------
1 | $value) {
9 | if (is_array($value)) {
10 | $decodedKey = ($isMagic && !$aIsTopLevel)?stripslashes($key):$key;
11 | $decodedValue = transcribe($value, false);
12 | } else {
13 | $decodedKey = stripslashes($key);
14 | $decodedValue = ($isMagic)?stripslashes($value):$value;
15 | }
16 | $gpcList[$decodedKey] = $decodedValue;
17 | }
18 | return $gpcList;
19 | }
20 |
21 | $_GET = transcribe( $_GET );
22 | $_POST = transcribe( $_POST );
23 | $_REQUEST = transcribe( $_REQUEST );
24 |
25 |
26 | function v( $str )
27 | {
28 | return isset( $_REQUEST[$str] ) ? $_REQUEST[$str] : false;
29 | }
30 |
31 | function z( $str )
32 | {
33 | return strip_tags( $str );
34 | }
35 |
36 | function c( $str )
37 | {
38 | return isset( $GLOBALS['config'][$str] ) ? $GLOBALS['config'][$str] : false;
39 | }
40 |
41 | function g( $str )
42 | {
43 | return isset( $GLOBALS[$str] ) ? $GLOBALS[$str] : false;
44 | }
45 |
46 | function t( $str )
47 | {
48 | return trim($str);
49 | }
50 |
51 | function u( $str )
52 | {
53 | return urlencode( $str );
54 | }
55 |
56 | // render functiones
57 | function render( $data = NULL , $layout = NULL , $sharp = 'default' )
58 | {
59 | if( $layout == null )
60 | {
61 | if( is_ajax_request() )
62 | {
63 | $layout = 'ajax';
64 | }
65 | elseif( is_mobile_request() )
66 | {
67 | $layout = 'mobile';
68 | }
69 | else
70 | {
71 | $layout = 'web';
72 | }
73 | }
74 |
75 | $GLOBALS['layout'] = $layout;
76 | $GLOBALS['sharp'] = $sharp;
77 |
78 | $layout_file = AROOT . 'view/layout/' . $layout . '/' . $sharp . '.tpl.html';
79 | if( file_exists( $layout_file ) )
80 | {
81 | @extract( $data );
82 | require( $layout_file );
83 | }
84 | else
85 | {
86 | $layout_file = CROOT . 'view/layout/' . $layout . '/' . $sharp . '.tpl.html';
87 | if( file_exists( $layout_file ) )
88 | {
89 | @extract( $data );
90 | require( $layout_file );
91 | }
92 | }
93 | }
94 |
95 | function ajax_echo( $info )
96 | {
97 | if( !headers_sent() )
98 | {
99 | header("Content-Type:text/html;charset=utf-8");
100 | header("Expires: Thu, 01 Jan 1970 00:00:01 GMT");
101 | header("Cache-Control: no-cache, must-revalidate");
102 | header("Pragma: no-cache");
103 | }
104 |
105 | echo $info;
106 | }
107 |
108 |
109 | function info_page( $info , $title = '系统消息' )
110 | {
111 | if( is_ajax_request() )
112 | $layout = 'ajax';
113 | else
114 | $layout = 'web';
115 |
116 | $data['top_title'] = $data['title'] = $title;
117 | $data['info'] = $info;
118 |
119 | render( $data , $layout , 'info' );
120 |
121 | }
122 |
123 | function is_ajax_request()
124 | {
125 | $headers = apache_request_headers();
126 | return (isset( $headers['X-Requested-With'] ) && ( $headers['X-Requested-With'] == 'XMLHttpRequest' )) || (isset( $headers['x-requested-with'] ) && ($headers['x-requested-with'] == 'XMLHttpRequest' ));
127 | }
128 |
129 | if (!function_exists('apache_request_headers'))
130 | {
131 | function apache_request_headers()
132 | {
133 | foreach($_SERVER as $key=>$value)
134 | {
135 | if (substr($key,0,5)=="HTTP_")
136 | {
137 | $key=str_replace(" ","-",ucwords(strtolower(str_replace("_"," ",substr($key,5)))));
138 | $out[$key]=$value;
139 | }
140 | else
141 | {
142 | $out[$key]=$value;
143 | }
144 | }
145 |
146 | return $out;
147 | }
148 | }
149 |
150 | function is_mobile_request()
151 | {
152 | $_SERVER['ALL_HTTP'] = isset($_SERVER['ALL_HTTP']) ? $_SERVER['ALL_HTTP'] : '';
153 |
154 | $mobile_browser = '0';
155 |
156 | if(preg_match('/(up.browser|up.link|mmp|symbian|smartphone|midp|wap|phone|iphone|ipad|ipod|android|xoom)/i', strtolower($_SERVER['HTTP_USER_AGENT'])))
157 | $mobile_browser++;
158 |
159 | if((isset($_SERVER['HTTP_ACCEPT'])) and (strpos(strtolower($_SERVER['HTTP_ACCEPT']),'application/vnd.wap.xhtml+xml') !== false))
160 | $mobile_browser++;
161 |
162 | if(isset($_SERVER['HTTP_X_WAP_PROFILE']))
163 | $mobile_browser++;
164 |
165 | if(isset($_SERVER['HTTP_PROFILE']))
166 | $mobile_browser++;
167 |
168 | $mobile_ua = strtolower(substr($_SERVER['HTTP_USER_AGENT'],0,4));
169 | $mobile_agents = array(
170 | 'w3c ','acs-','alav','alca','amoi','audi','avan','benq','bird','blac',
171 | 'blaz','brew','cell','cldc','cmd-','dang','doco','eric','hipt','inno',
172 | 'ipaq','java','jigs','kddi','keji','leno','lg-c','lg-d','lg-g','lge-',
173 | 'maui','maxo','midp','mits','mmef','mobi','mot-','moto','mwbp','nec-',
174 | 'newt','noki','oper','palm','pana','pant','phil','play','port','prox',
175 | 'qwap','sage','sams','sany','sch-','sec-','send','seri','sgh-','shar',
176 | 'sie-','siem','smal','smar','sony','sph-','symb','t-mo','teli','tim-',
177 | 'tosh','tsm-','upg1','upsi','vk-v','voda','wap-','wapa','wapi','wapp',
178 | 'wapr','webc','winw','winw','xda','xda-'
179 | );
180 |
181 | if(in_array($mobile_ua, $mobile_agents))
182 | $mobile_browser++;
183 |
184 | if(strpos(strtolower($_SERVER['ALL_HTTP']), 'operamini') !== false)
185 | $mobile_browser++;
186 |
187 | // Pre-final check to reset everything if the user is on Windows
188 | if(strpos(strtolower($_SERVER['HTTP_USER_AGENT']), 'windows') !== false)
189 | $mobile_browser=0;
190 |
191 | // But WP7 is also Windows, with a slightly different characteristic
192 | if(strpos(strtolower($_SERVER['HTTP_USER_AGENT']), 'windows phone') !== false)
193 | $mobile_browser++;
194 |
195 | if($mobile_browser>0)
196 | return true;
197 | else
198 | return false;
199 | }
200 |
201 | function uses( $m )
202 | {
203 | load( 'lib/' . basename($m) );
204 | }
205 |
206 | function load( $file_path )
207 | {
208 | $file = AROOT . $file_path;
209 | if( file_exists( $file ) )
210 | {
211 | //echo $file;
212 | require( $file );
213 |
214 | }
215 | else
216 | {
217 | //echo CROOT . $file_path;
218 | require( CROOT . $file_path );
219 | }
220 |
221 | }
222 |
223 | // ===========================================
224 | // load db functions
225 | // ===========================================
226 | if( defined('SAE_APPNAME') )
227 | include_once( CROOT . 'lib/db.sae.function.php' );
228 | else
229 | include_once( CROOT . 'lib/db.function.php' );
230 |
231 | if (!function_exists('_'))
232 | {
233 | function _( $string , $data = null )
234 | {
235 | if( !isset($GLOBALS['i18n']) )
236 | {
237 | $c = c('default_language');
238 | if( strlen($c) < 1 ) $c = 'zh_cn';
239 |
240 | $lang_file = AROOT . 'local' . DS . basename($c) . '.lang.php';
241 | if( file_exists( $lang_file ) )
242 | {
243 | include_once( $lang_file );
244 | $GLOBALS['i18n'] = $c;
245 | }
246 | else
247 | $GLOBALS['i18n'] = 'zh_cn';
248 |
249 |
250 | }
251 |
252 | //print_r( $GLOBALS['language'][$GLOBALS['i18n']] );
253 |
254 |
255 |
256 | if( isset( $GLOBALS['language'][$GLOBALS['i18n']][$string] ) )
257 | $to = $GLOBALS['language'][$GLOBALS['i18n']][$string];
258 | else
259 | $to = $string;
260 |
261 | if( $data == null )
262 | return $to;
263 | else
264 | {
265 | if( !is_array( $data ) ) $data = array( $data );
266 | return vsprintf( $to , $data );
267 | }
268 |
269 | }
270 | }
271 |
272 |
273 |
274 |
--------------------------------------------------------------------------------
/_lp/core/lib/db.function.php:
--------------------------------------------------------------------------------
1 | $v )
57 | $array[$k] = s($v );
58 |
59 | $reg = '/\?([is])/i';
60 | $sql = preg_replace_callback( $reg , 'prepair_string' , $sql );
61 | $count = count( $array );
62 | for( $i = 0 ; $i < $count; $i++ )
63 | {
64 | $str[] = '$array[' .$i . ']';
65 | }
66 |
67 | $statement = '$sql = sprintf( $sql , ' . join( ',' , $str ) . ' );';
68 | eval( $statement );
69 | return $sql;
70 |
71 | }
72 |
73 | function prepair_string( $matches )
74 | {
75 | if( $matches[1] == 's' ) return "'%s'";
76 | if( $matches[1] == 'i' ) return "'%d'";
77 | }
78 |
79 |
80 | function get_data( $sql , $db = NULL )
81 | {
82 | if( $db == NULL ) $db = db();
83 |
84 | $GLOBALS['LP_LAST_SQL'] = $sql;
85 | $data = Array();
86 | $i = 0;
87 | $result = mysql_query( $sql ,$db );
88 |
89 | if( mysql_errno() != 0 )
90 | echo mysql_error() .' ' . $sql;
91 |
92 | while( $Array = mysql_fetch_array($result, MYSQL_ASSOC ) )
93 | {
94 | $data[$i++] = $Array;
95 | }
96 |
97 | if( mysql_errno() != 0 )
98 | echo mysql_error() .' ' . $sql;
99 |
100 | mysql_free_result($result);
101 |
102 | if( count( $data ) > 0 )
103 | return $data;
104 | else
105 | return false;
106 | }
107 |
108 | function get_line( $sql , $db = NULL )
109 | {
110 | $data = get_data( $sql , $db );
111 | return @reset($data);
112 | }
113 |
114 | function get_var( $sql , $db = NULL )
115 | {
116 | $data = get_line( $sql , $db );
117 | return $data[ @reset(@array_keys( $data )) ];
118 | }
119 |
120 | function last_id( $db = NULL )
121 | {
122 | if( $db == NULL ) $db = db();
123 | return get_var( "SELECT LAST_INSERT_ID() " , $db );
124 | }
125 |
126 | function run_sql( $sql , $db = NULL )
127 | {
128 | if( $db == NULL ) $db = db();
129 | $GLOBALS['LP_LAST_SQL'] = $sql;
130 | return mysql_query( $sql , $db );
131 | }
132 |
133 | function db_errno( $db = NULL )
134 | {
135 | if( $db == NULL ) $db = db();
136 | return mysql_errno( $db );
137 | }
138 |
139 |
140 | function db_error( $db = NULL )
141 | {
142 | if( $db == NULL ) $db = db();
143 | return mysql_error( $db );
144 | }
145 |
146 | function last_error()
147 | {
148 | if( isset( $GLOBALS['LP_DB_LAST_ERROR'] ) )
149 | return $GLOBALS['LP_DB_LAST_ERROR'];
150 | }
151 |
152 | function close_db( $db = NULL )
153 | {
154 | if( $db == NULL )
155 | $db = $GLOBALS['LP_DB'];
156 |
157 | unset( $GLOBALS['LP_DB'] );
158 | mysql_close( $db );
159 | }
160 |
--------------------------------------------------------------------------------
/_lp/core/lib/db.sae.function.php:
--------------------------------------------------------------------------------
1 | $v )
99 | $array[$k] = s($v );
100 |
101 | $reg = '/\?([is])/i';
102 | $sql = preg_replace_callback( $reg , 'prepair_string' , $sql );
103 | $count = count( $array );
104 | for( $i = 0 ; $i < $count; $i++ )
105 | {
106 | $str[] = '$array[' .$i . ']';
107 | }
108 |
109 | $statement = '$sql = sprintf( $sql , ' . join( ',' , $str ) . ' );';
110 | eval( $statement );
111 | return $sql;
112 |
113 | }
114 |
115 | function prepair_string( $matches )
116 | {
117 | if( $matches[1] == 's' ) return "'%s'";
118 | if( $matches[1] == 'i' ) return "'%d'";
119 | }
120 |
121 |
122 | function get_data( $sql , $db = NULL )
123 | {
124 | if( $db == NULL ) $db = db_read();
125 |
126 | $GLOBALS['LP_LAST_SQL'] = $sql;
127 | $data = Array();
128 | $i = 0;
129 | $result = mysql_query( $sql ,$db );
130 |
131 | if( mysql_errno() != 0 )
132 | echo mysql_error() .' ' . $sql;
133 |
134 | while( $Array = mysql_fetch_array($result, MYSQL_ASSOC ) )
135 | {
136 | $data[$i++] = $Array;
137 | }
138 |
139 | if( mysql_errno() != 0 )
140 | echo mysql_error() .' ' . $sql;
141 |
142 | mysql_free_result($result);
143 |
144 | if( count( $data ) > 0 )
145 | return $data;
146 | else
147 | return false;
148 | }
149 |
150 | function get_line( $sql , $db = NULL )
151 | {
152 | $data = get_data( $sql , $db );
153 | return @reset($data);
154 | }
155 |
156 | function get_var( $sql , $db = NULL )
157 | {
158 | $data = get_line( $sql , $db );
159 | return $data[ @reset(@array_keys( $data )) ];
160 | }
161 |
162 | function last_id( $db = NULL )
163 | {
164 | if( $db == NULL ) $db = db();
165 | return get_var( "SELECT LAST_INSERT_ID() " , $db );
166 | }
167 |
168 | function run_sql( $sql , $db = NULL )
169 | {
170 | if( $db == NULL ) $db = db();
171 | $GLOBALS['LP_LAST_SQL'] = $sql;
172 | return mysql_query( $sql , $db );
173 | }
174 |
175 | function db_errno( $db = NULL )
176 | {
177 | if( $db == NULL ) $db = db();
178 | return mysql_errno( $db );
179 | }
180 |
181 |
182 | function db_error( $db = NULL )
183 | {
184 | if( $db == NULL ) $db = db();
185 | return mysql_error( $db );
186 | }
187 |
188 | function last_error()
189 | {
190 | if( isset( $GLOBALS['LP_DB_LAST_ERROR'] ) )
191 | return $GLOBALS['LP_DB_LAST_ERROR'];
192 | }
193 |
194 | function close_db( $db = NULL )
195 | {
196 | if( $db == NULL )
197 | $db = $GLOBALS['LP_DB'];
198 |
199 | unset( $GLOBALS['LP_DB'] );
200 | mysql_close( $db );
201 | }
202 |
--------------------------------------------------------------------------------
/_lp/core/model/README:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/windiest/LazyPHP/99f2837615a0801bb27520827b4ec73fb8559b20/_lp/core/model/README
--------------------------------------------------------------------------------
/_lp/core/view/layout/web/main/default/index.tpl.html:
--------------------------------------------------------------------------------
1 |
2 | main area
3 |
--------------------------------------------------------------------------------
/_lp/core/view/layout/web/side/default/index.tpl.html:
--------------------------------------------------------------------------------
1 |
2 | sidebar
3 |
--------------------------------------------------------------------------------
/_lp/lp.init.php:
--------------------------------------------------------------------------------
1 | 0) {
31 | list($key, $value) = $this->parseArgument($arguments);
32 | $this->assign($key, $value);
33 | }
34 | }
35 |
36 | /**
37 | * Sets the value in the argments object. If multiple
38 | * values are added under the same key, the key will
39 | * give an array value in the order they were added.
40 | * @param string $key The variable to assign to.
41 | * @param string value The value that would norally
42 | * be colected on the command line.
43 | */
44 | function assign($key, $value) {
45 | if ($this->$key === false) {
46 | $this->all[$key] = $value;
47 | } elseif (! is_array($this->$key)) {
48 | $this->all[$key] = array($this->$key, $value);
49 | } else {
50 | $this->all[$key][] = $value;
51 | }
52 | }
53 |
54 | /**
55 | * Extracts the next key and value from the argument list.
56 | * @param array $arguments The remaining arguments to be parsed.
57 | * The argument list will be reduced.
58 | * @return array Two item array of key and value.
59 | * If no value can be found it will
60 | * have the value true assigned instead.
61 | */
62 | private function parseArgument(&$arguments) {
63 | $argument = array_shift($arguments);
64 | if (preg_match('/^-(\w)=(.+)$/', $argument, $matches)) {
65 | return array($matches[1], $matches[2]);
66 | } elseif (preg_match('/^-(\w)$/', $argument, $matches)) {
67 | return array($matches[1], $this->nextNonFlagElseTrue($arguments));
68 | } elseif (preg_match('/^--(\w+)=(.+)$/', $argument, $matches)) {
69 | return array($matches[1], $matches[2]);
70 | } elseif (preg_match('/^--(\w+)$/', $argument, $matches)) {
71 | return array($matches[1], $this->nextNonFlagElseTrue($arguments));
72 | }
73 | }
74 |
75 | /**
76 | * Attempts to use the next argument as a value. It
77 | * won't use what it thinks is a flag.
78 | * @param array $arguments Remaining arguments to be parsed.
79 | * This variable is modified if there
80 | * is a value to be extracted.
81 | * @return string/boolean The next value unless it's a flag.
82 | */
83 | private function nextNonFlagElseTrue(&$arguments) {
84 | return $this->valueIsNext($arguments) ? array_shift($arguments) : true;
85 | }
86 |
87 | /**
88 | * Test to see if the next available argument is a valid value.
89 | * If it starts with "-" or "--" it's a flag and doesn't count.
90 | * @param array $arguments Remaining arguments to be parsed.
91 | * Not affected by this call.
92 | * boolean True if valid value.
93 | */
94 | function valueIsNext($arguments) {
95 | return isset($arguments[0]) && ! $this->isFlag($arguments[0]);
96 | }
97 |
98 | /**
99 | * It's a flag if it starts with "-" or "--".
100 | * @param string $argument Value to be tested.
101 | * @return boolean True if it's a flag.
102 | */
103 | function isFlag($argument) {
104 | return strncmp($argument, '-', 1) == 0;
105 | }
106 |
107 | /**
108 | * The arguments are available as individual member
109 | * variables on the object.
110 | * @param string $key Argument name.
111 | * @return string/array/boolean Either false for no value,
112 | * the value as a string or
113 | * a list of multiple values if
114 | * the flag had been specified more
115 | * than once.
116 | */
117 | function __get($key) {
118 | if (isset($this->all[$key])) {
119 | return $this->all[$key];
120 | }
121 | return false;
122 | }
123 |
124 | /**
125 | * The entire argument set as a hash.
126 | * @return hash Each argument and it's value(s).
127 | */
128 | function all() {
129 | return $this->all;
130 | }
131 | }
132 |
133 | /**
134 | * Renders the help for the command line arguments.
135 | * @package SimpleTest
136 | * @subpackage UnitTester
137 | */
138 | class SimpleHelp {
139 | private $overview;
140 | private $flag_sets = array();
141 | private $explanations = array();
142 |
143 | /**
144 | * Sets up the top level explanation for the program.
145 | * @param string $overview Summary of program.
146 | */
147 | function __construct($overview = '') {
148 | $this->overview = $overview;
149 | }
150 |
151 | /**
152 | * Adds the explanation for a group of flags that all
153 | * have the same function.
154 | * @param string/array $flags Flag and alternates. Don't
155 | * worry about leading dashes
156 | * as these are inserted automatically.
157 | * @param string $explanation What that flag group does.
158 | */
159 | function explainFlag($flags, $explanation) {
160 | $flags = is_array($flags) ? $flags : array($flags);
161 | $this->flag_sets[] = $flags;
162 | $this->explanations[] = $explanation;
163 | }
164 |
165 | /**
166 | * Generates the help text.
167 | * @returns string The complete formatted text.
168 | */
169 | function render() {
170 | $tab_stop = $this->longestFlag($this->flag_sets) + 4;
171 | $text = $this->overview . "\n";
172 | for ($i = 0; $i < count($this->flag_sets); $i++) {
173 | $text .= $this->renderFlagSet($this->flag_sets[$i], $this->explanations[$i], $tab_stop);
174 | }
175 | return $this->noDuplicateNewLines($text);
176 | }
177 |
178 | /**
179 | * Works out the longest flag for formatting purposes.
180 | * @param array $flag_sets The internal flag set list.
181 | */
182 | private function longestFlag($flag_sets) {
183 | $longest = 0;
184 | foreach ($flag_sets as $flags) {
185 | foreach ($flags as $flag) {
186 | $longest = max($longest, strlen($this->renderFlag($flag)));
187 | }
188 | }
189 | return $longest;
190 | }
191 |
192 | /**
193 | * Generates the text for a single flag and it's alternate flags.
194 | * @returns string Help text for that flag group.
195 | */
196 | private function renderFlagSet($flags, $explanation, $tab_stop) {
197 | $flag = array_shift($flags);
198 | $text = str_pad($this->renderFlag($flag), $tab_stop, ' ') . $explanation . "\n";
199 | foreach ($flags as $flag) {
200 | $text .= ' ' . $this->renderFlag($flag) . "\n";
201 | }
202 | return $text;
203 | }
204 |
205 | /**
206 | * Generates the flag name including leading dashes.
207 | * @param string $flag Just the name.
208 | * @returns Fag with apropriate dashes.
209 | */
210 | private function renderFlag($flag) {
211 | return (strlen($flag) == 1 ? '-' : '--') . $flag;
212 | }
213 |
214 | /**
215 | * Converts multiple new lines into a single new line.
216 | * Just there to trap accidental duplicate new lines.
217 | * @param string $text Text to clean up.
218 | * @returns string Text with no blank lines.
219 | */
220 | private function noDuplicateNewLines($text) {
221 | return preg_replace('/(\n+)/', "\n", $text);
222 | }
223 | }
224 | ?>
--------------------------------------------------------------------------------
/_lp/simpletest/authentication.php:
--------------------------------------------------------------------------------
1 | type = $type;
34 | $this->root = $url->getBasePath();
35 | $this->username = false;
36 | $this->password = false;
37 | }
38 |
39 | /**
40 | * Adds another location to the realm.
41 | * @param SimpleUrl $url Somewhere in realm.
42 | * @access public
43 | */
44 | function stretch($url) {
45 | $this->root = $this->getCommonPath($this->root, $url->getPath());
46 | }
47 |
48 | /**
49 | * Finds the common starting path.
50 | * @param string $first Path to compare.
51 | * @param string $second Path to compare.
52 | * @return string Common directories.
53 | * @access private
54 | */
55 | protected function getCommonPath($first, $second) {
56 | $first = explode('/', $first);
57 | $second = explode('/', $second);
58 | for ($i = 0; $i < min(count($first), count($second)); $i++) {
59 | if ($first[$i] != $second[$i]) {
60 | return implode('/', array_slice($first, 0, $i)) . '/';
61 | }
62 | }
63 | return implode('/', $first) . '/';
64 | }
65 |
66 | /**
67 | * Sets the identity to try within this realm.
68 | * @param string $username Username in authentication dialog.
69 | * @param string $username Password in authentication dialog.
70 | * @access public
71 | */
72 | function setIdentity($username, $password) {
73 | $this->username = $username;
74 | $this->password = $password;
75 | }
76 |
77 | /**
78 | * Accessor for current identity.
79 | * @return string Last succesful username.
80 | * @access public
81 | */
82 | function getUsername() {
83 | return $this->username;
84 | }
85 |
86 | /**
87 | * Accessor for current identity.
88 | * @return string Last succesful password.
89 | * @access public
90 | */
91 | function getPassword() {
92 | return $this->password;
93 | }
94 |
95 | /**
96 | * Test to see if the URL is within the directory
97 | * tree of the realm.
98 | * @param SimpleUrl $url URL to test.
99 | * @return boolean True if subpath.
100 | * @access public
101 | */
102 | function isWithin($url) {
103 | if ($this->isIn($this->root, $url->getBasePath())) {
104 | return true;
105 | }
106 | if ($this->isIn($this->root, $url->getBasePath() . $url->getPage() . '/')) {
107 | return true;
108 | }
109 | return false;
110 | }
111 |
112 | /**
113 | * Tests to see if one string is a substring of
114 | * another.
115 | * @param string $part Small bit.
116 | * @param string $whole Big bit.
117 | * @return boolean True if the small bit is
118 | * in the big bit.
119 | * @access private
120 | */
121 | protected function isIn($part, $whole) {
122 | return strpos($whole, $part) === 0;
123 | }
124 | }
125 |
126 | /**
127 | * Manages security realms.
128 | * @package SimpleTest
129 | * @subpackage WebTester
130 | */
131 | class SimpleAuthenticator {
132 | private $realms;
133 |
134 | /**
135 | * Clears the realms.
136 | * @access public
137 | */
138 | function SimpleAuthenticator() {
139 | $this->restartSession();
140 | }
141 |
142 | /**
143 | * Starts with no realms set up.
144 | * @access public
145 | */
146 | function restartSession() {
147 | $this->realms = array();
148 | }
149 |
150 | /**
151 | * Adds a new realm centered the current URL.
152 | * Browsers privatey wildly on their behaviour in this
153 | * regard. Mozilla ignores the realm and presents
154 | * only when challenged, wasting bandwidth. IE
155 | * just carries on presenting until a new challenge
156 | * occours. SimpleTest tries to follow the spirit of
157 | * the original standards committee and treats the
158 | * base URL as the root of a file tree shaped realm.
159 | * @param SimpleUrl $url Base of realm.
160 | * @param string $type Authentication type for this
161 | * realm. Only Basic authentication
162 | * is currently supported.
163 | * @param string $realm Name of realm.
164 | * @access public
165 | */
166 | function addRealm($url, $type, $realm) {
167 | $this->realms[$url->getHost()][$realm] = new SimpleRealm($type, $url);
168 | }
169 |
170 | /**
171 | * Sets the current identity to be presented
172 | * against that realm.
173 | * @param string $host Server hosting realm.
174 | * @param string $realm Name of realm.
175 | * @param string $username Username for realm.
176 | * @param string $password Password for realm.
177 | * @access public
178 | */
179 | function setIdentityForRealm($host, $realm, $username, $password) {
180 | if (isset($this->realms[$host][$realm])) {
181 | $this->realms[$host][$realm]->setIdentity($username, $password);
182 | }
183 | }
184 |
185 | /**
186 | * Finds the name of the realm by comparing URLs.
187 | * @param SimpleUrl $url URL to test.
188 | * @return SimpleRealm Name of realm.
189 | * @access private
190 | */
191 | protected function findRealmFromUrl($url) {
192 | if (! isset($this->realms[$url->getHost()])) {
193 | return false;
194 | }
195 | foreach ($this->realms[$url->getHost()] as $name => $realm) {
196 | if ($realm->isWithin($url)) {
197 | return $realm;
198 | }
199 | }
200 | return false;
201 | }
202 |
203 | /**
204 | * Presents the appropriate headers for this location.
205 | * @param SimpleHttpRequest $request Request to modify.
206 | * @param SimpleUrl $url Base of realm.
207 | * @access public
208 | */
209 | function addHeaders(&$request, $url) {
210 | if ($url->getUsername() && $url->getPassword()) {
211 | $username = $url->getUsername();
212 | $password = $url->getPassword();
213 | } elseif ($realm = $this->findRealmFromUrl($url)) {
214 | $username = $realm->getUsername();
215 | $password = $realm->getPassword();
216 | } else {
217 | return;
218 | }
219 | $this->addBasicHeaders($request, $username, $password);
220 | }
221 |
222 | /**
223 | * Presents the appropriate headers for this
224 | * location for basic authentication.
225 | * @param SimpleHttpRequest $request Request to modify.
226 | * @param string $username Username for realm.
227 | * @param string $password Password for realm.
228 | * @access public
229 | */
230 | static function addBasicHeaders(&$request, $username, $password) {
231 | if ($username && $password) {
232 | $request->addHeaderLine(
233 | 'Authorization: Basic ' . base64_encode("$username:$password"));
234 | }
235 | }
236 | }
237 | ?>
--------------------------------------------------------------------------------
/_lp/simpletest/autorun.php:
--------------------------------------------------------------------------------
1 | createSuiteFromClasses(
52 | basename(initial_file()),
53 | $loader->selectRunnableTests($candidates));
54 | return $suite->run(new DefaultReporter());
55 | } catch (Exception $stack_frame_fix) {
56 | print $stack_frame_fix->getMessage();
57 | return false;
58 | }
59 | }
60 |
61 | /**
62 | * Checks the current test context to see if a test has
63 | * ever been run.
64 | * @return boolean True if tests have run.
65 | */
66 | function tests_have_run() {
67 | if ($context = SimpleTest::getContext()) {
68 | return (boolean)$context->getTest();
69 | }
70 | return false;
71 | }
72 |
73 | /**
74 | * The first autorun file.
75 | * @return string Filename of first autorun script.
76 | */
77 | function initial_file() {
78 | static $file = false;
79 | if (! $file) {
80 | if (isset($_SERVER, $_SERVER['SCRIPT_FILENAME'])) {
81 | $file = $_SERVER['SCRIPT_FILENAME'];
82 | } else {
83 | $included_files = get_included_files();
84 | $file = reset($included_files);
85 | }
86 | }
87 | return $file;
88 | }
89 |
90 | /**
91 | * Every class since the first autorun include. This
92 | * is safe enough if require_once() is always used.
93 | * @return array Class names.
94 | */
95 | function capture_new_classes() {
96 | global $SIMPLETEST_AUTORUNNER_INITIAL_CLASSES;
97 | return array_map('strtolower', array_diff(get_declared_classes(),
98 | $SIMPLETEST_AUTORUNNER_INITIAL_CLASSES ?
99 | $SIMPLETEST_AUTORUNNER_INITIAL_CLASSES : array()));
100 | }
101 | ?>
--------------------------------------------------------------------------------
/_lp/simpletest/collector.php:
--------------------------------------------------------------------------------
1 |
7 | * @package SimpleTest
8 | * @subpackage UnitTester
9 | * @version $Id: collector.php 2011 2011-04-29 08:22:48Z pp11 $
10 | */
11 |
12 | /**
13 | * The basic collector for {@link GroupTest}
14 | *
15 | * @see collect(), GroupTest::collect()
16 | * @package SimpleTest
17 | * @subpackage UnitTester
18 | */
19 | class SimpleCollector {
20 |
21 | /**
22 | * Strips off any kind of slash at the end so as to normalise the path.
23 | * @param string $path Path to normalise.
24 | * @return string Path without trailing slash.
25 | */
26 | protected function removeTrailingSlash($path) {
27 | if (substr($path, -1) == DIRECTORY_SEPARATOR) {
28 | return substr($path, 0, -1);
29 | } elseif (substr($path, -1) == '/') {
30 | return substr($path, 0, -1);
31 | } else {
32 | return $path;
33 | }
34 | }
35 |
36 | /**
37 | * Scans the directory and adds what it can.
38 | * @param object $test Group test with {@link GroupTest::addTestFile()} method.
39 | * @param string $path Directory to scan.
40 | * @see _attemptToAdd()
41 | */
42 | function collect(&$test, $path) {
43 | $path = $this->removeTrailingSlash($path);
44 | if ($handle = opendir($path)) {
45 | while (($entry = readdir($handle)) !== false) {
46 | if ($this->isHidden($entry)) {
47 | continue;
48 | }
49 | $this->handle($test, $path . DIRECTORY_SEPARATOR . $entry);
50 | }
51 | closedir($handle);
52 | }
53 | }
54 |
55 | /**
56 | * This method determines what should be done with a given file and adds
57 | * it via {@link GroupTest::addTestFile()} if necessary.
58 | *
59 | * This method should be overriden to provide custom matching criteria,
60 | * such as pattern matching, recursive matching, etc. For an example, see
61 | * {@link SimplePatternCollector::_handle()}.
62 | *
63 | * @param object $test Group test with {@link GroupTest::addTestFile()} method.
64 | * @param string $filename A filename as generated by {@link collect()}
65 | * @see collect()
66 | * @access protected
67 | */
68 | protected function handle(&$test, $file) {
69 | if (is_dir($file)) {
70 | return;
71 | }
72 | $test->addFile($file);
73 | }
74 |
75 | /**
76 | * Tests for hidden files so as to skip them. Currently
77 | * only tests for Unix hidden files.
78 | * @param string $filename Plain filename.
79 | * @return boolean True if hidden file.
80 | * @access private
81 | */
82 | protected function isHidden($filename) {
83 | return strncmp($filename, '.', 1) == 0;
84 | }
85 | }
86 |
87 | /**
88 | * An extension to {@link SimpleCollector} that only adds files matching a
89 | * given pattern.
90 | *
91 | * @package SimpleTest
92 | * @subpackage UnitTester
93 | * @see SimpleCollector
94 | */
95 | class SimplePatternCollector extends SimpleCollector {
96 | private $pattern;
97 |
98 | /**
99 | *
100 | * @param string $pattern Perl compatible regex to test name against
101 | * See {@link http://us4.php.net/manual/en/reference.pcre.pattern.syntax.php PHP's PCRE}
102 | * for full documentation of valid pattern.s
103 | */
104 | function __construct($pattern = '/php$/i') {
105 | $this->pattern = $pattern;
106 | }
107 |
108 | /**
109 | * Attempts to add files that match a given pattern.
110 | *
111 | * @see SimpleCollector::_handle()
112 | * @param object $test Group test with {@link GroupTest::addTestFile()} method.
113 | * @param string $path Directory to scan.
114 | * @access protected
115 | */
116 | protected function handle(&$test, $filename) {
117 | if (preg_match($this->pattern, $filename)) {
118 | parent::handle($test, $filename);
119 | }
120 | }
121 | }
122 | ?>
--------------------------------------------------------------------------------
/_lp/simpletest/compatibility.php:
--------------------------------------------------------------------------------
1 | = 0) {
23 | eval('$copy = clone $object;');
24 | return $copy;
25 | }
26 | return $object;
27 | }
28 |
29 | /**
30 | * Identity test. Drops back to equality + types for PHP5
31 | * objects as the === operator counts as the
32 | * stronger reference constraint.
33 | * @param mixed $first Test subject.
34 | * @param mixed $second Comparison object.
35 | * @return boolean True if identical.
36 | * @access public
37 | */
38 | static function isIdentical($first, $second) {
39 | if (version_compare(phpversion(), '5') >= 0) {
40 | return SimpleTestCompatibility::isIdenticalType($first, $second);
41 | }
42 | if ($first != $second) {
43 | return false;
44 | }
45 | return ($first === $second);
46 | }
47 |
48 | /**
49 | * Recursive type test.
50 | * @param mixed $first Test subject.
51 | * @param mixed $second Comparison object.
52 | * @return boolean True if same type.
53 | * @access private
54 | */
55 | protected static function isIdenticalType($first, $second) {
56 | if (gettype($first) != gettype($second)) {
57 | return false;
58 | }
59 | if (is_object($first) && is_object($second)) {
60 | if (get_class($first) != get_class($second)) {
61 | return false;
62 | }
63 | return SimpleTestCompatibility::isArrayOfIdenticalTypes(
64 | (array) $first,
65 | (array) $second);
66 | }
67 | if (is_array($first) && is_array($second)) {
68 | return SimpleTestCompatibility::isArrayOfIdenticalTypes($first, $second);
69 | }
70 | if ($first !== $second) {
71 | return false;
72 | }
73 | return true;
74 | }
75 |
76 | /**
77 | * Recursive type test for each element of an array.
78 | * @param mixed $first Test subject.
79 | * @param mixed $second Comparison object.
80 | * @return boolean True if identical.
81 | * @access private
82 | */
83 | protected static function isArrayOfIdenticalTypes($first, $second) {
84 | if (array_keys($first) != array_keys($second)) {
85 | return false;
86 | }
87 | foreach (array_keys($first) as $key) {
88 | $is_identical = SimpleTestCompatibility::isIdenticalType(
89 | $first[$key],
90 | $second[$key]);
91 | if (! $is_identical) {
92 | return false;
93 | }
94 | }
95 | return true;
96 | }
97 |
98 | /**
99 | * Test for two variables being aliases.
100 | * @param mixed $first Test subject.
101 | * @param mixed $second Comparison object.
102 | * @return boolean True if same.
103 | * @access public
104 | */
105 | static function isReference(&$first, &$second) {
106 | if (version_compare(phpversion(), '5', '>=') && is_object($first)) {
107 | return ($first === $second);
108 | }
109 | if (is_object($first) && is_object($second)) {
110 | $id = uniqid("test");
111 | $first->$id = true;
112 | $is_ref = isset($second->$id);
113 | unset($first->$id);
114 | return $is_ref;
115 | }
116 | $temp = $first;
117 | $first = uniqid("test");
118 | $is_ref = ($first === $second);
119 | $first = $temp;
120 | return $is_ref;
121 | }
122 |
123 | /**
124 | * Test to see if an object is a member of a
125 | * class hiearchy.
126 | * @param object $object Object to test.
127 | * @param string $class Root name of hiearchy.
128 | * @return boolean True if class in hiearchy.
129 | * @access public
130 | */
131 | static function isA($object, $class) {
132 | if (version_compare(phpversion(), '5') >= 0) {
133 | if (! class_exists($class, false)) {
134 | if (function_exists('interface_exists')) {
135 | if (! interface_exists($class, false)) {
136 | return false;
137 | }
138 | }
139 | }
140 | eval("\$is_a = \$object instanceof $class;");
141 | return $is_a;
142 | }
143 | if (function_exists('is_a')) {
144 | return is_a($object, $class);
145 | }
146 | return ((strtolower($class) == get_class($object))
147 | or (is_subclass_of($object, $class)));
148 | }
149 |
150 | /**
151 | * Sets a socket timeout for each chunk.
152 | * @param resource $handle Socket handle.
153 | * @param integer $timeout Limit in seconds.
154 | * @access public
155 | */
156 | static function setTimeout($handle, $timeout) {
157 | if (function_exists('stream_set_timeout')) {
158 | stream_set_timeout($handle, $timeout, 0);
159 | } elseif (function_exists('socket_set_timeout')) {
160 | socket_set_timeout($handle, $timeout, 0);
161 | } elseif (function_exists('set_socket_timeout')) {
162 | set_socket_timeout($handle, $timeout, 0);
163 | }
164 | }
165 | }
166 | ?>
--------------------------------------------------------------------------------
/_lp/simpletest/cookies.php:
--------------------------------------------------------------------------------
1 | host = false;
41 | $this->name = $name;
42 | $this->value = $value;
43 | $this->path = ($path ? $this->fixPath($path) : "/");
44 | $this->expiry = false;
45 | if (is_string($expiry)) {
46 | $this->expiry = strtotime($expiry);
47 | } elseif (is_integer($expiry)) {
48 | $this->expiry = $expiry;
49 | }
50 | $this->is_secure = $is_secure;
51 | }
52 |
53 | /**
54 | * Sets the host. The cookie rules determine
55 | * that the first two parts are taken for
56 | * certain TLDs and three for others. If the
57 | * new host does not match these rules then the
58 | * call will fail.
59 | * @param string $host New hostname.
60 | * @return boolean True if hostname is valid.
61 | * @access public
62 | */
63 | function setHost($host) {
64 | if ($host = $this->truncateHost($host)) {
65 | $this->host = $host;
66 | return true;
67 | }
68 | return false;
69 | }
70 |
71 | /**
72 | * Accessor for the truncated host to which this
73 | * cookie applies.
74 | * @return string Truncated hostname.
75 | * @access public
76 | */
77 | function getHost() {
78 | return $this->host;
79 | }
80 |
81 | /**
82 | * Test for a cookie being valid for a host name.
83 | * @param string $host Host to test against.
84 | * @return boolean True if the cookie would be valid
85 | * here.
86 | */
87 | function isValidHost($host) {
88 | return ($this->truncateHost($host) === $this->getHost());
89 | }
90 |
91 | /**
92 | * Extracts just the domain part that determines a
93 | * cookie's host validity.
94 | * @param string $host Host name to truncate.
95 | * @return string Domain or false on a bad host.
96 | * @access private
97 | */
98 | protected function truncateHost($host) {
99 | $tlds = SimpleUrl::getAllTopLevelDomains();
100 | if (preg_match('/[a-z\-]+\.(' . $tlds . ')$/i', $host, $matches)) {
101 | return $matches[0];
102 | } elseif (preg_match('/[a-z\-]+\.[a-z\-]+\.[a-z\-]+$/i', $host, $matches)) {
103 | return $matches[0];
104 | }
105 | return false;
106 | }
107 |
108 | /**
109 | * Accessor for name.
110 | * @return string Cookie key.
111 | * @access public
112 | */
113 | function getName() {
114 | return $this->name;
115 | }
116 |
117 | /**
118 | * Accessor for value. A deleted cookie will
119 | * have an empty string for this.
120 | * @return string Cookie value.
121 | * @access public
122 | */
123 | function getValue() {
124 | return $this->value;
125 | }
126 |
127 | /**
128 | * Accessor for path.
129 | * @return string Valid cookie path.
130 | * @access public
131 | */
132 | function getPath() {
133 | return $this->path;
134 | }
135 |
136 | /**
137 | * Tests a path to see if the cookie applies
138 | * there. The test path must be longer or
139 | * equal to the cookie path.
140 | * @param string $path Path to test against.
141 | * @return boolean True if cookie valid here.
142 | * @access public
143 | */
144 | function isValidPath($path) {
145 | return (strncmp(
146 | $this->fixPath($path),
147 | $this->getPath(),
148 | strlen($this->getPath())) == 0);
149 | }
150 |
151 | /**
152 | * Accessor for expiry.
153 | * @return string Expiry string.
154 | * @access public
155 | */
156 | function getExpiry() {
157 | if (! $this->expiry) {
158 | return false;
159 | }
160 | return gmdate("D, d M Y H:i:s", $this->expiry) . " GMT";
161 | }
162 |
163 | /**
164 | * Test to see if cookie is expired against
165 | * the cookie format time or timestamp.
166 | * Will give true for a session cookie.
167 | * @param integer/string $now Time to test against. Result
168 | * will be false if this time
169 | * is later than the cookie expiry.
170 | * Can be either a timestamp integer
171 | * or a cookie format date.
172 | * @access public
173 | */
174 | function isExpired($now) {
175 | if (! $this->expiry) {
176 | return true;
177 | }
178 | if (is_string($now)) {
179 | $now = strtotime($now);
180 | }
181 | return ($this->expiry < $now);
182 | }
183 |
184 | /**
185 | * Ages the cookie by the specified number of
186 | * seconds.
187 | * @param integer $interval In seconds.
188 | * @public
189 | */
190 | function agePrematurely($interval) {
191 | if ($this->expiry) {
192 | $this->expiry -= $interval;
193 | }
194 | }
195 |
196 | /**
197 | * Accessor for the secure flag.
198 | * @return boolean True if cookie needs SSL.
199 | * @access public
200 | */
201 | function isSecure() {
202 | return $this->is_secure;
203 | }
204 |
205 | /**
206 | * Adds a trailing and leading slash to the path
207 | * if missing.
208 | * @param string $path Path to fix.
209 | * @access private
210 | */
211 | protected function fixPath($path) {
212 | if (substr($path, 0, 1) != '/') {
213 | $path = '/' . $path;
214 | }
215 | if (substr($path, -1, 1) != '/') {
216 | $path .= '/';
217 | }
218 | return $path;
219 | }
220 | }
221 |
222 | /**
223 | * Repository for cookies. This stuff is a
224 | * tiny bit browser dependent.
225 | * @package SimpleTest
226 | * @subpackage WebTester
227 | */
228 | class SimpleCookieJar {
229 | private $cookies;
230 |
231 | /**
232 | * Constructor. Jar starts empty.
233 | * @access public
234 | */
235 | function __construct() {
236 | $this->cookies = array();
237 | }
238 |
239 | /**
240 | * Removes expired and temporary cookies as if
241 | * the browser was closed and re-opened.
242 | * @param string/integer $now Time to test expiry against.
243 | * @access public
244 | */
245 | function restartSession($date = false) {
246 | $surviving_cookies = array();
247 | for ($i = 0; $i < count($this->cookies); $i++) {
248 | if (! $this->cookies[$i]->getValue()) {
249 | continue;
250 | }
251 | if (! $this->cookies[$i]->getExpiry()) {
252 | continue;
253 | }
254 | if ($date && $this->cookies[$i]->isExpired($date)) {
255 | continue;
256 | }
257 | $surviving_cookies[] = $this->cookies[$i];
258 | }
259 | $this->cookies = $surviving_cookies;
260 | }
261 |
262 | /**
263 | * Ages all cookies in the cookie jar.
264 | * @param integer $interval The old session is moved
265 | * into the past by this number
266 | * of seconds. Cookies now over
267 | * age will be removed.
268 | * @access public
269 | */
270 | function agePrematurely($interval) {
271 | for ($i = 0; $i < count($this->cookies); $i++) {
272 | $this->cookies[$i]->agePrematurely($interval);
273 | }
274 | }
275 |
276 | /**
277 | * Sets an additional cookie. If a cookie has
278 | * the same name and path it is replaced.
279 | * @param string $name Cookie key.
280 | * @param string $value Value of cookie.
281 | * @param string $host Host upon which the cookie is valid.
282 | * @param string $path Cookie path if not host wide.
283 | * @param string $expiry Expiry date.
284 | * @access public
285 | */
286 | function setCookie($name, $value, $host = false, $path = '/', $expiry = false) {
287 | $cookie = new SimpleCookie($name, $value, $path, $expiry);
288 | if ($host) {
289 | $cookie->setHost($host);
290 | }
291 | $this->cookies[$this->findFirstMatch($cookie)] = $cookie;
292 | }
293 |
294 | /**
295 | * Finds a matching cookie to write over or the
296 | * first empty slot if none.
297 | * @param SimpleCookie $cookie Cookie to write into jar.
298 | * @return integer Available slot.
299 | * @access private
300 | */
301 | protected function findFirstMatch($cookie) {
302 | for ($i = 0; $i < count($this->cookies); $i++) {
303 | $is_match = $this->isMatch(
304 | $cookie,
305 | $this->cookies[$i]->getHost(),
306 | $this->cookies[$i]->getPath(),
307 | $this->cookies[$i]->getName());
308 | if ($is_match) {
309 | return $i;
310 | }
311 | }
312 | return count($this->cookies);
313 | }
314 |
315 | /**
316 | * Reads the most specific cookie value from the
317 | * browser cookies. Looks for the longest path that
318 | * matches.
319 | * @param string $host Host to search.
320 | * @param string $path Applicable path.
321 | * @param string $name Name of cookie to read.
322 | * @return string False if not present, else the
323 | * value as a string.
324 | * @access public
325 | */
326 | function getCookieValue($host, $path, $name) {
327 | $longest_path = '';
328 | foreach ($this->cookies as $cookie) {
329 | if ($this->isMatch($cookie, $host, $path, $name)) {
330 | if (strlen($cookie->getPath()) > strlen($longest_path)) {
331 | $value = $cookie->getValue();
332 | $longest_path = $cookie->getPath();
333 | }
334 | }
335 | }
336 | return (isset($value) ? $value : false);
337 | }
338 |
339 | /**
340 | * Tests cookie for matching against search
341 | * criteria.
342 | * @param SimpleTest $cookie Cookie to test.
343 | * @param string $host Host must match.
344 | * @param string $path Cookie path must be shorter than
345 | * this path.
346 | * @param string $name Name must match.
347 | * @return boolean True if matched.
348 | * @access private
349 | */
350 | protected function isMatch($cookie, $host, $path, $name) {
351 | if ($cookie->getName() != $name) {
352 | return false;
353 | }
354 | if ($host && $cookie->getHost() && ! $cookie->isValidHost($host)) {
355 | return false;
356 | }
357 | if (! $cookie->isValidPath($path)) {
358 | return false;
359 | }
360 | return true;
361 | }
362 |
363 | /**
364 | * Uses a URL to sift relevant cookies by host and
365 | * path. Results are list of strings of form "name=value".
366 | * @param SimpleUrl $url Url to select by.
367 | * @return array Valid name and value pairs.
368 | * @access public
369 | */
370 | function selectAsPairs($url) {
371 | $pairs = array();
372 | foreach ($this->cookies as $cookie) {
373 | if ($this->isMatch($cookie, $url->getHost(), $url->getPath(), $cookie->getName())) {
374 | $pairs[] = $cookie->getName() . '=' . $cookie->getValue();
375 | }
376 | }
377 | return $pairs;
378 | }
379 | }
380 | ?>
--------------------------------------------------------------------------------
/_lp/simpletest/default_reporter.php:
--------------------------------------------------------------------------------
1 | 'case', 'c' => 'case',
28 | 'test' => 'test', 't' => 'test',
29 | );
30 | private $case = '';
31 | private $test = '';
32 | private $xml = false;
33 | private $help = false;
34 | private $no_skips = false;
35 |
36 | /**
37 | * Parses raw command line arguments into object properties.
38 | * @param string $arguments Raw commend line arguments.
39 | */
40 | function __construct($arguments) {
41 | if (! is_array($arguments)) {
42 | return;
43 | }
44 | foreach ($arguments as $i => $argument) {
45 | if (preg_match('/^--?(test|case|t|c)=(.+)$/', $argument, $matches)) {
46 | $property = $this->to_property[$matches[1]];
47 | $this->$property = $matches[2];
48 | } elseif (preg_match('/^--?(test|case|t|c)$/', $argument, $matches)) {
49 | $property = $this->to_property[$matches[1]];
50 | if (isset($arguments[$i + 1])) {
51 | $this->$property = $arguments[$i + 1];
52 | }
53 | } elseif (preg_match('/^--?(xml|x)$/', $argument)) {
54 | $this->xml = true;
55 | } elseif (preg_match('/^--?(no-skip|no-skips|s)$/', $argument)) {
56 | $this->no_skips = true;
57 | } elseif (preg_match('/^--?(help|h)$/', $argument)) {
58 | $this->help = true;
59 | }
60 | }
61 | }
62 |
63 | /**
64 | * Run only this test.
65 | * @return string Test name to run.
66 | */
67 | function getTest() {
68 | return $this->test;
69 | }
70 |
71 | /**
72 | * Run only this test suite.
73 | * @return string Test class name to run.
74 | */
75 | function getTestCase() {
76 | return $this->case;
77 | }
78 |
79 | /**
80 | * Output should be XML or not.
81 | * @return boolean True if XML desired.
82 | */
83 | function isXml() {
84 | return $this->xml;
85 | }
86 |
87 | /**
88 | * Output should suppress skip messages.
89 | * @return boolean True for no skips.
90 | */
91 | function noSkips() {
92 | return $this->no_skips;
93 | }
94 |
95 | /**
96 | * Output should be a help message. Disabled during XML mode.
97 | * @return boolean True if help message desired.
98 | */
99 | function help() {
100 | return $this->help && ! $this->xml;
101 | }
102 |
103 | /**
104 | * Returns plain-text help message for command line runner.
105 | * @return string String help message
106 | */
107 | function getHelpText() {
108 | return << [args...]
111 |
112 | -c Run only the test-case
113 | -t Run only the test method
114 | -s Suppress skip messages
115 | -x Return test results in XML
116 | -h Display this help message
117 |
118 | HELP;
119 | }
120 |
121 | }
122 |
123 | /**
124 | * The default reporter used by SimpleTest's autorun
125 | * feature. The actual reporters used are dependency
126 | * injected and can be overridden.
127 | * @package SimpleTest
128 | * @subpackage UnitTester
129 | */
130 | class DefaultReporter extends SimpleReporterDecorator {
131 |
132 | /**
133 | * Assembles the appropriate reporter for the environment.
134 | */
135 | function __construct() {
136 | if (SimpleReporter::inCli()) {
137 | $parser = new SimpleCommandLineParser($_SERVER['argv']);
138 | $interfaces = $parser->isXml() ? array('XmlReporter') : array('TextReporter');
139 | if ($parser->help()) {
140 | // I'm not sure if we should do the echo'ing here -- ezyang
141 | echo $parser->getHelpText();
142 | exit(1);
143 | }
144 | $reporter = new SelectiveReporter(
145 | SimpleTest::preferred($interfaces),
146 | $parser->getTestCase(),
147 | $parser->getTest());
148 | if ($parser->noSkips()) {
149 | $reporter = new NoSkipsReporter($reporter);
150 | }
151 | } else {
152 | $reporter = new SelectiveReporter(
153 | SimpleTest::preferred('HtmlReporter'),
154 | @$_GET['c'],
155 | @$_GET['t']);
156 | if (@$_GET['skips'] == 'no' || @$_GET['show-skips'] == 'no') {
157 | $reporter = new NoSkipsReporter($reporter);
158 | }
159 | }
160 | parent::__construct($reporter);
161 | }
162 | }
163 | ?>
--------------------------------------------------------------------------------
/_lp/simpletest/detached.php:
--------------------------------------------------------------------------------
1 | command = $command;
34 | $this->dry_command = $dry_command ? $dry_command : $command;
35 | $this->size = false;
36 | }
37 |
38 | /**
39 | * Accessor for the test name for subclasses.
40 | * @return string Name of the test.
41 | * @access public
42 | */
43 | function getLabel() {
44 | return $this->command;
45 | }
46 |
47 | /**
48 | * Runs the top level test for this class. Currently
49 | * reads the data as a single chunk. I'll fix this
50 | * once I have added iteration to the browser.
51 | * @param SimpleReporter $reporter Target of test results.
52 | * @returns boolean True if no failures.
53 | * @access public
54 | */
55 | function run(&$reporter) {
56 | $shell = &new SimpleShell();
57 | $shell->execute($this->command);
58 | $parser = &$this->createParser($reporter);
59 | if (! $parser->parse($shell->getOutput())) {
60 | trigger_error('Cannot parse incoming XML from [' . $this->command . ']');
61 | return false;
62 | }
63 | return true;
64 | }
65 |
66 | /**
67 | * Accessor for the number of subtests.
68 | * @return integer Number of test cases.
69 | * @access public
70 | */
71 | function getSize() {
72 | if ($this->size === false) {
73 | $shell = &new SimpleShell();
74 | $shell->execute($this->dry_command);
75 | $reporter = &new SimpleReporter();
76 | $parser = &$this->createParser($reporter);
77 | if (! $parser->parse($shell->getOutput())) {
78 | trigger_error('Cannot parse incoming XML from [' . $this->dry_command . ']');
79 | return false;
80 | }
81 | $this->size = $reporter->getTestCaseCount();
82 | }
83 | return $this->size;
84 | }
85 |
86 | /**
87 | * Creates the XML parser.
88 | * @param SimpleReporter $reporter Target of test results.
89 | * @return SimpleTestXmlListener XML reader.
90 | * @access protected
91 | */
92 | protected function &createParser(&$reporter) {
93 | return new SimpleTestXmlParser($reporter);
94 | }
95 | }
96 | ?>
--------------------------------------------------------------------------------
/_lp/simpletest/eclipse.php:
--------------------------------------------------------------------------------
1 | listener = &$listener;
32 | $this->SimpleScorer();
33 | $this->case = "";
34 | $this->group = "";
35 | $this->method = "";
36 | $this->cc = $cc;
37 | $this->error = false;
38 | $this->fail = false;
39 | }
40 |
41 | /**
42 | * Means to display human readable object comparisons.
43 | * @return SimpleDumper Visual comparer.
44 | */
45 | function getDumper() {
46 | return new SimpleDumper();
47 | }
48 |
49 | /**
50 | * Localhost connection from Eclipse.
51 | * @param integer $port Port to connect to Eclipse.
52 | * @param string $host Normally localhost.
53 | * @return SimpleSocket Connection to Eclipse.
54 | */
55 | function &createListener($port, $host="127.0.0.1"){
56 | $tmplistener = &new SimpleSocket($host, $port, 5);
57 | return $tmplistener;
58 | }
59 |
60 | /**
61 | * Wraps the test in an output buffer.
62 | * @param SimpleInvoker $invoker Current test runner.
63 | * @return EclipseInvoker Decorator with output buffering.
64 | * @access public
65 | */
66 | function &createInvoker(&$invoker){
67 | $eclinvoker = &new EclipseInvoker($invoker, $this->listener);
68 | return $eclinvoker;
69 | }
70 |
71 | /**
72 | * C style escaping.
73 | * @param string $raw String with backslashes, quotes and whitespace.
74 | * @return string Replaced with C backslashed tokens.
75 | */
76 | function escapeVal($raw){
77 | $needle = array("\\","\"","/","\b","\f","\n","\r","\t");
78 | $replace = array('\\\\','\"','\/','\b','\f','\n','\r','\t');
79 | return str_replace($needle, $replace, $raw);
80 | }
81 |
82 | /**
83 | * Stash the first passing item. Clicking the test
84 | * item goes to first pass.
85 | * @param string $message Test message, but we only wnat the first.
86 | * @access public
87 | */
88 | function paintPass($message){
89 | if (! $this->pass){
90 | $this->message = $this->escapeVal($message);
91 | }
92 | $this->pass = true;
93 | }
94 |
95 | /**
96 | * Stash the first failing item. Clicking the test
97 | * item goes to first fail.
98 | * @param string $message Test message, but we only wnat the first.
99 | * @access public
100 | */
101 | function paintFail($message){
102 | //only get the first failure or error
103 | if (! $this->fail && ! $this->error){
104 | $this->fail = true;
105 | $this->message = $this->escapeVal($message);
106 | $this->listener->write('{status:"fail",message:"'.$this->message.'",group:"'.$this->group.'",case:"'.$this->case.'",method:"'.$this->method.'"}');
107 | }
108 | }
109 |
110 | /**
111 | * Stash the first error. Clicking the test
112 | * item goes to first error.
113 | * @param string $message Test message, but we only wnat the first.
114 | * @access public
115 | */
116 | function paintError($message){
117 | if (! $this->fail && ! $this->error){
118 | $this->error = true;
119 | $this->message = $this->escapeVal($message);
120 | $this->listener->write('{status:"error",message:"'.$this->message.'",group:"'.$this->group.'",case:"'.$this->case.'",method:"'.$this->method.'"}');
121 | }
122 | }
123 |
124 |
125 | /**
126 | * Stash the first exception. Clicking the test
127 | * item goes to first message.
128 | * @param string $message Test message, but we only wnat the first.
129 | * @access public
130 | */
131 | function paintException($exception){
132 | if (! $this->fail && ! $this->error){
133 | $this->error = true;
134 | $message = 'Unexpected exception of type[' . get_class($exception) .
135 | '] with message [' . $exception->getMessage() . '] in [' .
136 | $exception->getFile() .' line '. $exception->getLine() . ']';
137 | $this->message = $this->escapeVal($message);
138 | $this->listener->write(
139 | '{status:"error",message:"' . $this->message . '",group:"' .
140 | $this->group . '",case:"' . $this->case . '",method:"' . $this->method
141 | . '"}');
142 | }
143 | }
144 |
145 |
146 | /**
147 | * We don't display any special header.
148 | * @param string $test_name First test top level
149 | * to start.
150 | * @access public
151 | */
152 | function paintHeader($test_name) {
153 | }
154 |
155 | /**
156 | * We don't display any special footer.
157 | * @param string $test_name The top level test.
158 | * @access public
159 | */
160 | function paintFooter($test_name) {
161 | }
162 |
163 | /**
164 | * Paints nothing at the start of a test method, but stash
165 | * the method name for later.
166 | * @param string $test_name Name of test that is starting.
167 | * @access public
168 | */
169 | function paintMethodStart($method) {
170 | $this->pass = false;
171 | $this->fail = false;
172 | $this->error = false;
173 | $this->method = $this->escapeVal($method);
174 | }
175 |
176 | /**
177 | * Only send one message if the test passes, after that
178 | * suppress the message.
179 | * @param string $test_name Name of test that is ending.
180 | * @access public
181 | */
182 | function paintMethodEnd($method){
183 | if ($this->fail || $this->error || ! $this->pass){
184 | } else {
185 | $this->listener->write(
186 | '{status:"pass",message:"' . $this->message . '",group:"' .
187 | $this->group . '",case:"' . $this->case . '",method:"' .
188 | $this->method . '"}');
189 | }
190 | }
191 |
192 | /**
193 | * Stashes the test case name for the later failure message.
194 | * @param string $test_name Name of test or other label.
195 | * @access public
196 | */
197 | function paintCaseStart($case){
198 | $this->case = $this->escapeVal($case);
199 | }
200 |
201 | /**
202 | * Drops the name.
203 | * @param string $test_name Name of test or other label.
204 | * @access public
205 | */
206 | function paintCaseEnd($case){
207 | $this->case = "";
208 | }
209 |
210 | /**
211 | * Stashes the name of the test suite. Starts test coverage
212 | * if enabled.
213 | * @param string $group Name of test or other label.
214 | * @param integer $size Number of test cases starting.
215 | * @access public
216 | */
217 | function paintGroupStart($group, $size){
218 | $this->group = $this->escapeVal($group);
219 | if ($this->cc){
220 | if (extension_loaded('xdebug')){
221 | xdebug_start_code_coverage(XDEBUG_CC_UNUSED | XDEBUG_CC_DEAD_CODE);
222 | }
223 | }
224 | }
225 |
226 | /**
227 | * Paints coverage report if enabled.
228 | * @param string $group Name of test or other label.
229 | * @access public
230 | */
231 | function paintGroupEnd($group){
232 | $this->group = "";
233 | $cc = "";
234 | if ($this->cc){
235 | if (extension_loaded('xdebug')){
236 | $arrfiles = xdebug_get_code_coverage();
237 | xdebug_stop_code_coverage();
238 | $thisdir = dirname(__FILE__);
239 | $thisdirlen = strlen($thisdir);
240 | foreach ($arrfiles as $index=>$file){
241 | if (substr($index, 0, $thisdirlen)===$thisdir){
242 | continue;
243 | }
244 | $lcnt = 0;
245 | $ccnt = 0;
246 | foreach ($file as $line){
247 | if ($line == -2){
248 | continue;
249 | }
250 | $lcnt++;
251 | if ($line==1){
252 | $ccnt++;
253 | }
254 | }
255 | if ($lcnt > 0){
256 | $cc .= round(($ccnt/$lcnt) * 100, 2) . '%';
257 | }else{
258 | $cc .= "0.00%";
259 | }
260 | $cc.= "\t". $index . "\n";
261 | }
262 | }
263 | }
264 | $this->listener->write('{status:"coverage",message:"' .
265 | EclipseReporter::escapeVal($cc) . '"}');
266 | }
267 | }
268 |
269 | /**
270 | * Invoker decorator for Eclipse. Captures output until
271 | * the end of the test.
272 | * @package SimpleTest
273 | * @subpackage Eclipse
274 | */
275 | class EclipseInvoker extends SimpleInvokerDecorator{
276 | function __construct(&$invoker, &$listener) {
277 | $this->listener = &$listener;
278 | $this->SimpleInvokerDecorator($invoker);
279 | }
280 |
281 | /**
282 | * Starts output buffering.
283 | * @param string $method Test method to call.
284 | * @access public
285 | */
286 | function before($method){
287 | ob_start();
288 | $this->invoker->before($method);
289 | }
290 |
291 | /**
292 | * Stops output buffering and send the captured output
293 | * to the listener.
294 | * @param string $method Test method to call.
295 | * @access public
296 | */
297 | function after($method) {
298 | $this->invoker->after($method);
299 | $output = ob_get_contents();
300 | ob_end_clean();
301 | if ($output !== ""){
302 | $result = $this->listener->write('{status:"info",message:"' .
303 | EclipseReporter::escapeVal($output) . '"}');
304 | }
305 | }
306 | }
307 | ?>
--------------------------------------------------------------------------------
/_lp/simpletest/errors.php:
--------------------------------------------------------------------------------
1 | createErrorQueue();
41 | set_error_handler('SimpleTestErrorHandler');
42 | parent::invoke($method);
43 | restore_error_handler();
44 | $queue->tally();
45 | }
46 |
47 | /**
48 | * Wires up the error queue for a single test.
49 | * @return SimpleErrorQueue Queue connected to the test.
50 | * @access private
51 | */
52 | protected function createErrorQueue() {
53 | $context = SimpleTest::getContext();
54 | $test = $this->getTestCase();
55 | $queue = $context->get('SimpleErrorQueue');
56 | $queue->setTestCase($test);
57 | return $queue;
58 | }
59 | }
60 |
61 | /**
62 | * Error queue used to record trapped
63 | * errors.
64 | * @package SimpleTest
65 | * @subpackage UnitTester
66 | */
67 | class SimpleErrorQueue {
68 | private $queue;
69 | private $expectation_queue;
70 | private $test;
71 | private $using_expect_style = false;
72 |
73 | /**
74 | * Starts with an empty queue.
75 | */
76 | function __construct() {
77 | $this->clear();
78 | }
79 |
80 | /**
81 | * Discards the contents of the error queue.
82 | * @access public
83 | */
84 | function clear() {
85 | $this->queue = array();
86 | $this->expectation_queue = array();
87 | }
88 |
89 | /**
90 | * Sets the currently running test case.
91 | * @param SimpleTestCase $test Test case to send messages to.
92 | * @access public
93 | */
94 | function setTestCase($test) {
95 | $this->test = $test;
96 | }
97 |
98 | /**
99 | * Sets up an expectation of an error. If this is
100 | * not fulfilled at the end of the test, a failure
101 | * will occour. If the error does happen, then this
102 | * will cancel it out and send a pass message.
103 | * @param SimpleExpectation $expected Expected error match.
104 | * @param string $message Message to display.
105 | * @access public
106 | */
107 | function expectError($expected, $message) {
108 | array_push($this->expectation_queue, array($expected, $message));
109 | }
110 |
111 | /**
112 | * Adds an error to the front of the queue.
113 | * @param integer $severity PHP error code.
114 | * @param string $content Text of error.
115 | * @param string $filename File error occoured in.
116 | * @param integer $line Line number of error.
117 | * @access public
118 | */
119 | function add($severity, $content, $filename, $line) {
120 | $content = str_replace('%', '%%', $content);
121 | $this->testLatestError($severity, $content, $filename, $line);
122 | }
123 |
124 | /**
125 | * Any errors still in the queue are sent to the test
126 | * case. Any unfulfilled expectations trigger failures.
127 | * @access public
128 | */
129 | function tally() {
130 | while (list($severity, $message, $file, $line) = $this->extract()) {
131 | $severity = $this->getSeverityAsString($severity);
132 | $this->test->error($severity, $message, $file, $line);
133 | }
134 | while (list($expected, $message) = $this->extractExpectation()) {
135 | $this->test->assert($expected, false, "%s -> Expected error not caught");
136 | }
137 | }
138 |
139 | /**
140 | * Tests the error against the most recent expected
141 | * error.
142 | * @param integer $severity PHP error code.
143 | * @param string $content Text of error.
144 | * @param string $filename File error occoured in.
145 | * @param integer $line Line number of error.
146 | * @access private
147 | */
148 | protected function testLatestError($severity, $content, $filename, $line) {
149 | if ($expectation = $this->extractExpectation()) {
150 | list($expected, $message) = $expectation;
151 | $this->test->assert($expected, $content, sprintf(
152 | $message,
153 | "%s -> PHP error [$content] severity [" .
154 | $this->getSeverityAsString($severity) .
155 | "] in [$filename] line [$line]"));
156 | } else {
157 | $this->test->error($severity, $content, $filename, $line);
158 | }
159 | }
160 |
161 | /**
162 | * Pulls the earliest error from the queue.
163 | * @return mixed False if none, or a list of error
164 | * information. Elements are: severity
165 | * as the PHP error code, the error message,
166 | * the file with the error, the line number
167 | * and a list of PHP super global arrays.
168 | * @access public
169 | */
170 | function extract() {
171 | if (count($this->queue)) {
172 | return array_shift($this->queue);
173 | }
174 | return false;
175 | }
176 |
177 | /**
178 | * Pulls the earliest expectation from the queue.
179 | * @return SimpleExpectation False if none.
180 | * @access private
181 | */
182 | protected function extractExpectation() {
183 | if (count($this->expectation_queue)) {
184 | return array_shift($this->expectation_queue);
185 | }
186 | return false;
187 | }
188 |
189 | /**
190 | * Converts an error code into it's string
191 | * representation.
192 | * @param $severity PHP integer error code.
193 | * @return String version of error code.
194 | * @access public
195 | */
196 | static function getSeverityAsString($severity) {
197 | static $map = array(
198 | E_STRICT => 'E_STRICT',
199 | E_ERROR => 'E_ERROR',
200 | E_WARNING => 'E_WARNING',
201 | E_PARSE => 'E_PARSE',
202 | E_NOTICE => 'E_NOTICE',
203 | E_CORE_ERROR => 'E_CORE_ERROR',
204 | E_CORE_WARNING => 'E_CORE_WARNING',
205 | E_COMPILE_ERROR => 'E_COMPILE_ERROR',
206 | E_COMPILE_WARNING => 'E_COMPILE_WARNING',
207 | E_USER_ERROR => 'E_USER_ERROR',
208 | E_USER_WARNING => 'E_USER_WARNING',
209 | E_USER_NOTICE => 'E_USER_NOTICE');
210 | if (defined('E_RECOVERABLE_ERROR')) {
211 | $map[E_RECOVERABLE_ERROR] = 'E_RECOVERABLE_ERROR';
212 | }
213 | if (defined('E_DEPRECATED')) {
214 | $map[E_DEPRECATED] = 'E_DEPRECATED';
215 | }
216 | return $map[$severity];
217 | }
218 | }
219 |
220 | /**
221 | * Error handler that simply stashes any errors into the global
222 | * error queue. Simulates the existing behaviour with respect to
223 | * logging errors, but this feature may be removed in future.
224 | * @param $severity PHP error code.
225 | * @param $message Text of error.
226 | * @param $filename File error occoured in.
227 | * @param $line Line number of error.
228 | * @param $super_globals Hash of PHP super global arrays.
229 | * @access public
230 | */
231 | function SimpleTestErrorHandler($severity, $message, $filename = null, $line = null, $super_globals = null, $mask = null) {
232 | $severity = $severity & error_reporting();
233 | if ($severity) {
234 | restore_error_handler();
235 | if (IsNotCausedBySimpleTest($message) && IsNotTimeZoneNag($message)) {
236 | if (ini_get('log_errors')) {
237 | $label = SimpleErrorQueue::getSeverityAsString($severity);
238 | error_log("$label: $message in $filename on line $line");
239 | }
240 | $queue = SimpleTest::getContext()->get('SimpleErrorQueue');
241 | $queue->add($severity, $message, $filename, $line);
242 | }
243 | set_error_handler('SimpleTestErrorHandler');
244 | }
245 | return true;
246 | }
247 |
248 | /**
249 | * Certain messages can be caused by the unit tester itself.
250 | * These have to be filtered.
251 | * @param string $message Message to filter.
252 | * @return boolean True if genuine failure.
253 | */
254 | function IsNotCausedBySimpleTest($message) {
255 | return ! preg_match('/returned by reference/', $message);
256 | }
257 |
258 | /**
259 | * Certain messages caused by PHP are just noise.
260 | * These have to be filtered.
261 | * @param string $message Message to filter.
262 | * @return boolean True if genuine failure.
263 | */
264 | function IsNotTimeZoneNag($message) {
265 | return ! preg_match('/not safe to rely .* timezone settings/', $message);
266 | }
267 | ?>
--------------------------------------------------------------------------------
/_lp/simpletest/exceptions.php:
--------------------------------------------------------------------------------
1 | get('SimpleExceptionTrap');
40 | $trap->clear();
41 | try {
42 | $has_thrown = false;
43 | parent::invoke($method);
44 | } catch (Exception $exception) {
45 | $has_thrown = true;
46 | if (! $trap->isExpected($this->getTestCase(), $exception)) {
47 | $this->getTestCase()->exception($exception);
48 | }
49 | $trap->clear();
50 | }
51 | if ($message = $trap->getOutstanding()) {
52 | $this->getTestCase()->fail($message);
53 | }
54 | if ($has_thrown) {
55 | try {
56 | parent::getTestCase()->tearDown();
57 | } catch (Exception $e) { }
58 | }
59 | }
60 | }
61 |
62 | /**
63 | * Tests exceptions either by type or the exact
64 | * exception. This could be improved to accept
65 | * a pattern expectation to test the error
66 | * message, but that will have to come later.
67 | * @package SimpleTest
68 | * @subpackage UnitTester
69 | */
70 | class ExceptionExpectation extends SimpleExpectation {
71 | private $expected;
72 |
73 | /**
74 | * Sets up the conditions to test against.
75 | * If the expected value is a string, then
76 | * it will act as a test of the class name.
77 | * An exception as the comparison will
78 | * trigger an identical match. Writing this
79 | * down now makes it look doubly dumb. I hope
80 | * come up with a better scheme later.
81 | * @param mixed $expected A class name or an actual
82 | * exception to compare with.
83 | * @param string $message Message to display.
84 | */
85 | function __construct($expected, $message = '%s') {
86 | $this->expected = $expected;
87 | parent::__construct($message);
88 | }
89 |
90 | /**
91 | * Carry out the test.
92 | * @param Exception $compare Value to check.
93 | * @return boolean True if matched.
94 | */
95 | function test($compare) {
96 | if (is_string($this->expected)) {
97 | return ($compare instanceof $this->expected);
98 | }
99 | if (get_class($compare) != get_class($this->expected)) {
100 | return false;
101 | }
102 | return $compare->getMessage() == $this->expected->getMessage();
103 | }
104 |
105 | /**
106 | * Create the message to display describing the test.
107 | * @param Exception $compare Exception to match.
108 | * @return string Final message.
109 | */
110 | function testMessage($compare) {
111 | if (is_string($this->expected)) {
112 | return "Exception [" . $this->describeException($compare) .
113 | "] should be type [" . $this->expected . "]";
114 | }
115 | return "Exception [" . $this->describeException($compare) .
116 | "] should match [" .
117 | $this->describeException($this->expected) . "]";
118 | }
119 |
120 | /**
121 | * Summary of an Exception object.
122 | * @param Exception $compare Exception to describe.
123 | * @return string Text description.
124 | */
125 | protected function describeException($exception) {
126 | return get_class($exception) . ": " . $exception->getMessage();
127 | }
128 | }
129 |
130 | /**
131 | * Stores expected exceptions for when they
132 | * get thrown. Saves the irritating try...catch
133 | * block.
134 | * @package SimpleTest
135 | * @subpackage UnitTester
136 | */
137 | class SimpleExceptionTrap {
138 | private $expected;
139 | private $ignored;
140 | private $message;
141 |
142 | /**
143 | * Clears down the queue ready for action.
144 | */
145 | function __construct() {
146 | $this->clear();
147 | }
148 |
149 | /**
150 | * Sets up an expectation of an exception.
151 | * This has the effect of intercepting an
152 | * exception that matches.
153 | * @param SimpleExpectation $expected Expected exception to match.
154 | * @param string $message Message to display.
155 | * @access public
156 | */
157 | function expectException($expected = false, $message = '%s') {
158 | $this->expected = $this->coerceToExpectation($expected);
159 | $this->message = $message;
160 | }
161 |
162 | /**
163 | * Adds an exception to the ignore list. This is the list
164 | * of exceptions that when thrown do not affect the test.
165 | * @param SimpleExpectation $ignored Exception to skip.
166 | * @access public
167 | */
168 | function ignoreException($ignored) {
169 | $this->ignored[] = $this->coerceToExpectation($ignored);
170 | }
171 |
172 | /**
173 | * Compares the expected exception with any
174 | * in the queue. Issues a pass or fail and
175 | * returns the state of the test.
176 | * @param SimpleTestCase $test Test case to send messages to.
177 | * @param Exception $exception Exception to compare.
178 | * @return boolean False on no match.
179 | */
180 | function isExpected($test, $exception) {
181 | if ($this->expected) {
182 | return $test->assert($this->expected, $exception, $this->message);
183 | }
184 | foreach ($this->ignored as $ignored) {
185 | if ($ignored->test($exception)) {
186 | return true;
187 | }
188 | }
189 | return false;
190 | }
191 |
192 | /**
193 | * Turns an expected exception into a SimpleExpectation object.
194 | * @param mixed $exception Exception, expectation or
195 | * class name of exception.
196 | * @return SimpleExpectation Expectation that will match the
197 | * exception.
198 | */
199 | private function coerceToExpectation($exception) {
200 | if ($exception === false) {
201 | return new AnythingExpectation();
202 | }
203 | if (! SimpleExpectation::isExpectation($exception)) {
204 | return new ExceptionExpectation($exception);
205 | }
206 | return $exception;
207 | }
208 |
209 | /**
210 | * Tests for any left over exception.
211 | * @return string/false The failure message or false if none.
212 | */
213 | function getOutstanding() {
214 | return sprintf($this->message, 'Failed to trap exception');
215 | }
216 |
217 | /**
218 | * Discards the contents of the error queue.
219 | */
220 | function clear() {
221 | $this->expected = false;
222 | $this->message = false;
223 | $this->ignored = array();
224 | }
225 | }
226 | ?>
--------------------------------------------------------------------------------
/_lp/simpletest/extensions/pear_test_case.php:
--------------------------------------------------------------------------------
1 | _loosely_typed = false;
35 | }
36 |
37 | /**
38 | * Will test straight equality if set to loose
39 | * typing, or identity if not.
40 | * @param $first First value.
41 | * @param $second Comparison value.
42 | * @param $message Message to display.
43 | * @public
44 | */
45 | function assertEquals($first, $second, $message = "%s", $delta = 0) {
46 | if ($this->_loosely_typed) {
47 | $expectation = new EqualExpectation($first);
48 | } else {
49 | $expectation = new IdenticalExpectation($first);
50 | }
51 | $this->assert($expectation, $second, $message);
52 | }
53 |
54 | /**
55 | * Passes if the value tested is not null.
56 | * @param $value Value to test against.
57 | * @param $message Message to display.
58 | * @public
59 | */
60 | function assertNotNull($value, $message = "%s") {
61 | parent::assert(new TrueExpectation(), isset($value), $message);
62 | }
63 |
64 | /**
65 | * Passes if the value tested is null.
66 | * @param $value Value to test against.
67 | * @param $message Message to display.
68 | * @public
69 | */
70 | function assertNull($value, $message = "%s") {
71 | parent::assert(new TrueExpectation(), !isset($value), $message);
72 | }
73 |
74 | /**
75 | * Identity test tests for the same object.
76 | * @param $first First object handle.
77 | * @param $second Hopefully the same handle.
78 | * @param $message Message to display.
79 | * @public
80 | */
81 | function assertSame($first, $second, $message = "%s") {
82 | $dumper = new SimpleDumper();
83 | $message = sprintf(
84 | $message,
85 | "[" . $dumper->describeValue($first) .
86 | "] and [" . $dumper->describeValue($second) .
87 | "] should reference the same object");
88 | return $this->assert(
89 | new TrueExpectation(),
90 | SimpleTestCompatibility::isReference($first, $second),
91 | $message);
92 | }
93 |
94 | /**
95 | * Inverted identity test.
96 | * @param $first First object handle.
97 | * @param $second Hopefully a different handle.
98 | * @param $message Message to display.
99 | * @public
100 | */
101 | function assertNotSame($first, $second, $message = "%s") {
102 | $dumper = new SimpleDumper();
103 | $message = sprintf(
104 | $message,
105 | "[" . $dumper->describeValue($first) .
106 | "] and [" . $dumper->describeValue($second) .
107 | "] should not be the same object");
108 | return $this->assert(
109 | new falseExpectation(),
110 | SimpleTestCompatibility::isReference($first, $second),
111 | $message);
112 | }
113 |
114 | /**
115 | * Sends pass if the test condition resolves true,
116 | * a fail otherwise.
117 | * @param $condition Condition to test true.
118 | * @param $message Message to display.
119 | * @public
120 | */
121 | function assertTrue($condition, $message = "%s") {
122 | parent::assert(new TrueExpectation(), $condition, $message);
123 | }
124 |
125 | /**
126 | * Sends pass if the test condition resolves false,
127 | * a fail otherwise.
128 | * @param $condition Condition to test false.
129 | * @param $message Message to display.
130 | * @public
131 | */
132 | function assertFalse($condition, $message = "%s") {
133 | parent::assert(new FalseExpectation(), $condition, $message);
134 | }
135 |
136 | /**
137 | * Tests a regex match. Needs refactoring.
138 | * @param $pattern Regex to match.
139 | * @param $subject String to search in.
140 | * @param $message Message to display.
141 | * @public
142 | */
143 | function assertRegExp($pattern, $subject, $message = "%s") {
144 | $this->assert(new PatternExpectation($pattern), $subject, $message);
145 | }
146 |
147 | /**
148 | * Tests the type of a value.
149 | * @param $value Value to take type of.
150 | * @param $type Hoped for type.
151 | * @param $message Message to display.
152 | * @public
153 | */
154 | function assertType($value, $type, $message = "%s") {
155 | parent::assert(new TrueExpectation(), gettype($value) == strtolower($type), $message);
156 | }
157 |
158 | /**
159 | * Sets equality operation to act as a simple equal
160 | * comparison only, allowing a broader range of
161 | * matches.
162 | * @param $loosely_typed True for broader comparison.
163 | * @public
164 | */
165 | function setLooselyTyped($loosely_typed) {
166 | $this->_loosely_typed = $loosely_typed;
167 | }
168 |
169 | /**
170 | * For progress indication during
171 | * a test amongst other things.
172 | * @return Usually one.
173 | * @public
174 | */
175 | function countTestCases() {
176 | return $this->getSize();
177 | }
178 |
179 | /**
180 | * Accessor for name, normally just the class
181 | * name.
182 | * @public
183 | */
184 | function getName() {
185 | return $this->getLabel();
186 | }
187 |
188 | /**
189 | * Does nothing. For compatibility only.
190 | * @param $name Dummy
191 | * @public
192 | */
193 | function setName($name) {
194 | }
195 | }
196 | ?>
--------------------------------------------------------------------------------
/_lp/simpletest/extensions/testdox.php:
--------------------------------------------------------------------------------
1 | _test_case_pattern = empty($test_case_pattern) ? '/^(.*)$/' : $test_case_pattern;
21 | }
22 |
23 | function paintCaseStart($test_name) {
24 | preg_match($this->_test_case_pattern, $test_name, $matches);
25 | if (!empty($matches[1])) {
26 | echo $matches[1] . "\n";
27 | } else {
28 | echo $test_name . "\n";
29 | }
30 | }
31 |
32 | function paintCaseEnd($test_name) {
33 | echo "\n";
34 | }
35 |
36 | function paintMethodStart($test_name) {
37 | if (!preg_match('/^test(.*)$/i', $test_name, $matches)) {
38 | return;
39 | }
40 | $test_name = $matches[1];
41 | $test_name = preg_replace('/([A-Z])([A-Z])/', '$1 $2', $test_name);
42 | echo '- ' . strtolower(preg_replace('/([a-zA-Z])([A-Z0-9])/', '$1 $2', $test_name));
43 | }
44 |
45 | function paintMethodEnd($test_name) {
46 | echo "\n";
47 | }
48 |
49 | function paintFail($message) {
50 | echo " [FAILED]";
51 | }
52 | }
53 | ?>
54 |
--------------------------------------------------------------------------------
/_lp/simpletest/extensions/testdox/test.php:
--------------------------------------------------------------------------------
1 | assertIsA($dox, 'SimpleScorer');
14 | $this->assertIsA($dox, 'SimpleReporter');
15 | }
16 |
17 | function testOutputsNameOfTestCase() {
18 | $dox = new TestDoxReporter();
19 | ob_start();
20 | $dox->paintCaseStart('TestOfTestDoxReporter');
21 | $buffer = ob_get_clean();
22 | $this->assertPattern('/^TestDoxReporter/', $buffer);
23 | }
24 |
25 | function testOutputOfTestCaseNameFilteredByConstructParameter() {
26 | $dox = new TestDoxReporter('/^(.*)Test$/');
27 | ob_start();
28 | $dox->paintCaseStart('SomeGreatWidgetTest');
29 | $buffer = ob_get_clean();
30 | $this->assertPattern('/^SomeGreatWidget/', $buffer);
31 | }
32 |
33 | function testIfTest_case_patternIsEmptyAssumeEverythingMatches() {
34 | $dox = new TestDoxReporter('');
35 | ob_start();
36 | $dox->paintCaseStart('TestOfTestDoxReporter');
37 | $buffer = ob_get_clean();
38 | $this->assertPattern('/^TestOfTestDoxReporter/', $buffer);
39 | }
40 |
41 | function testEmptyLineInsertedWhenCaseEnds() {
42 | $dox = new TestDoxReporter();
43 | ob_start();
44 | $dox->paintCaseEnd('TestOfTestDoxReporter');
45 | $buffer = ob_get_clean();
46 | $this->assertEqual("\n", $buffer);
47 | }
48 |
49 | function testPaintsTestMethodInTestDoxFormat() {
50 | $dox = new TestDoxReporter();
51 | ob_start();
52 | $dox->paintMethodStart('testSomeGreatTestCase');
53 | $buffer = ob_get_clean();
54 | $this->assertEqual("- some great test case", $buffer);
55 | unset($buffer);
56 |
57 | $random = rand(100, 200);
58 | ob_start();
59 | $dox->paintMethodStart("testRandomNumberIs{$random}");
60 | $buffer = ob_get_clean();
61 | $this->assertEqual("- random number is {$random}", $buffer);
62 | }
63 |
64 | function testDoesNotOutputAnythingOnNoneTestMethods() {
65 | $dox = new TestDoxReporter();
66 | ob_start();
67 | $dox->paintMethodStart('nonMatchingMethod');
68 | $buffer = ob_get_clean();
69 | $this->assertEqual('', $buffer);
70 | }
71 |
72 | function testPaintMethodAddLineBreak() {
73 | $dox = new TestDoxReporter();
74 | ob_start();
75 | $dox->paintMethodEnd('someMethod');
76 | $buffer = ob_get_clean();
77 | $this->assertEqual("\n", $buffer);
78 | }
79 |
80 | function testProperlySpacesSingleLettersInMethodName() {
81 | $dox = new TestDoxReporter();
82 | ob_start();
83 | $dox->paintMethodStart('testAVerySimpleAgainAVerySimpleMethod');
84 | $buffer = ob_get_clean();
85 | $this->assertEqual('- a very simple again a very simple method', $buffer);
86 | }
87 |
88 | function testOnFailureThisPrintsFailureNotice() {
89 | $dox = new TestDoxReporter();
90 | ob_start();
91 | $dox->paintFail('');
92 | $buffer = ob_get_clean();
93 | $this->assertEqual(' [FAILED]', $buffer);
94 | }
95 |
96 | function testWhenMatchingMethodNamesTestPrefixIsCaseInsensitive() {
97 | $dox = new TestDoxReporter();
98 | ob_start();
99 | $dox->paintMethodStart('TESTSupportsAllUppercaseTestPrefixEvenThoughIDoNotKnowWhyYouWouldDoThat');
100 | $buffer = ob_get_clean();
101 | $this->assertEqual(
102 | '- supports all uppercase test prefix even though i do not know why you would do that',
103 | $buffer
104 | );
105 | }
106 | }
107 | ?>
--------------------------------------------------------------------------------
/_lp/simpletest/invoker.php:
--------------------------------------------------------------------------------
1 | test_case = $test_case;
39 | }
40 |
41 | /**
42 | * Accessor for test case being run.
43 | * @return SimpleTestCase Test case.
44 | * @access public
45 | */
46 | function getTestCase() {
47 | return $this->test_case;
48 | }
49 |
50 | /**
51 | * Runs test level set up. Used for changing
52 | * the mechanics of base test cases.
53 | * @param string $method Test method to call.
54 | * @access public
55 | */
56 | function before($method) {
57 | $this->test_case->before($method);
58 | }
59 |
60 | /**
61 | * Invokes a test method and buffered with setUp()
62 | * and tearDown() calls.
63 | * @param string $method Test method to call.
64 | * @access public
65 | */
66 | function invoke($method) {
67 | $this->test_case->setUp();
68 | $this->test_case->$method();
69 | $this->test_case->tearDown();
70 | }
71 |
72 | /**
73 | * Runs test level clean up. Used for changing
74 | * the mechanics of base test cases.
75 | * @param string $method Test method to call.
76 | * @access public
77 | */
78 | function after($method) {
79 | $this->test_case->after($method);
80 | }
81 | }
82 |
83 | /**
84 | * Do nothing decorator. Just passes the invocation
85 | * straight through.
86 | * @package SimpleTest
87 | * @subpackage UnitTester
88 | */
89 | class SimpleInvokerDecorator {
90 | private $invoker;
91 |
92 | /**
93 | * Stores the invoker to wrap.
94 | * @param SimpleInvoker $invoker Test method runner.
95 | */
96 | function __construct($invoker) {
97 | $this->invoker = $invoker;
98 | }
99 |
100 | /**
101 | * Accessor for test case being run.
102 | * @return SimpleTestCase Test case.
103 | * @access public
104 | */
105 | function getTestCase() {
106 | return $this->invoker->getTestCase();
107 | }
108 |
109 | /**
110 | * Runs test level set up. Used for changing
111 | * the mechanics of base test cases.
112 | * @param string $method Test method to call.
113 | * @access public
114 | */
115 | function before($method) {
116 | $this->invoker->before($method);
117 | }
118 |
119 | /**
120 | * Invokes a test method and buffered with setUp()
121 | * and tearDown() calls.
122 | * @param string $method Test method to call.
123 | * @access public
124 | */
125 | function invoke($method) {
126 | $this->invoker->invoke($method);
127 | }
128 |
129 | /**
130 | * Runs test level clean up. Used for changing
131 | * the mechanics of base test cases.
132 | * @param string $method Test method to call.
133 | * @access public
134 | */
135 | function after($method) {
136 | $this->invoker->after($method);
137 | }
138 | }
139 | ?>
--------------------------------------------------------------------------------
/_lp/simpletest/recorder.php:
--------------------------------------------------------------------------------
1 | time, $this->breadcrumb, $this->message) =
34 | array(time(), $breadcrumb, $message);
35 | }
36 | }
37 |
38 | /**
39 | * A single pass captured for later.
40 | * @package SimpleTest
41 | * @subpackage Extensions
42 | */
43 | class SimpleResultOfPass extends SimpleResult { }
44 |
45 | /**
46 | * A single failure captured for later.
47 | * @package SimpleTest
48 | * @subpackage Extensions
49 | */
50 | class SimpleResultOfFail extends SimpleResult { }
51 |
52 | /**
53 | * A single exception captured for later.
54 | * @package SimpleTest
55 | * @subpackage Extensions
56 | */
57 | class SimpleResultOfException extends SimpleResult { }
58 |
59 | /**
60 | * Array-based test recorder. Returns an array
61 | * with timestamp, status, test name and message for each pass and failure.
62 | * @package SimpleTest
63 | * @subpackage Extensions
64 | */
65 | class Recorder extends SimpleReporterDecorator {
66 | public $results = array();
67 |
68 | /**
69 | * Stashes the pass as a SimpleResultOfPass
70 | * for later retrieval.
71 | * @param string $message Pass message to be displayed
72 | * eventually.
73 | */
74 | function paintPass($message) {
75 | parent::paintPass($message);
76 | $this->results[] = new SimpleResultOfPass(parent::getTestList(), $message);
77 | }
78 |
79 | /**
80 | * Stashes the fail as a SimpleResultOfFail
81 | * for later retrieval.
82 | * @param string $message Failure message to be displayed
83 | * eventually.
84 | */
85 | function paintFail($message) {
86 | parent::paintFail($message);
87 | $this->results[] = new SimpleResultOfFail(parent::getTestList(), $message);
88 | }
89 |
90 | /**
91 | * Stashes the exception as a SimpleResultOfException
92 | * for later retrieval.
93 | * @param string $message Exception message to be displayed
94 | * eventually.
95 | */
96 | function paintException($message) {
97 | parent::paintException($message);
98 | $this->results[] = new SimpleResultOfException(parent::getTestList(), $message);
99 | }
100 | }
101 | ?>
--------------------------------------------------------------------------------
/_lp/simpletest/reflection_php4.php:
--------------------------------------------------------------------------------
1 | _interface = $interface;
25 | }
26 |
27 | /**
28 | * Checks that a class has been declared.
29 | * @return boolean True if defined.
30 | * @access public
31 | */
32 | function classExists() {
33 | return class_exists($this->_interface);
34 | }
35 |
36 | /**
37 | * Needed to kill the autoload feature in PHP5
38 | * for classes created dynamically.
39 | * @return boolean True if defined.
40 | * @access public
41 | */
42 | function classExistsSansAutoload() {
43 | return class_exists($this->_interface);
44 | }
45 |
46 | /**
47 | * Checks that a class or interface has been
48 | * declared.
49 | * @return boolean True if defined.
50 | * @access public
51 | */
52 | function classOrInterfaceExists() {
53 | return class_exists($this->_interface);
54 | }
55 |
56 | /**
57 | * Needed to kill the autoload feature in PHP5
58 | * for classes created dynamically.
59 | * @return boolean True if defined.
60 | * @access public
61 | */
62 | function classOrInterfaceExistsSansAutoload() {
63 | return class_exists($this->_interface);
64 | }
65 |
66 | /**
67 | * Gets the list of methods on a class or
68 | * interface.
69 | * @returns array List of method names.
70 | * @access public
71 | */
72 | function getMethods() {
73 | return get_class_methods($this->_interface);
74 | }
75 |
76 | /**
77 | * Gets the list of interfaces from a class. If the
78 | * class name is actually an interface then just that
79 | * interface is returned.
80 | * @returns array List of interfaces.
81 | * @access public
82 | */
83 | function getInterfaces() {
84 | return array();
85 | }
86 |
87 | /**
88 | * Finds the parent class name.
89 | * @returns string Parent class name.
90 | * @access public
91 | */
92 | function getParent() {
93 | return strtolower(get_parent_class($this->_interface));
94 | }
95 |
96 | /**
97 | * Determines if the class is abstract, which for PHP 4
98 | * will never be the case.
99 | * @returns boolean True if abstract.
100 | * @access public
101 | */
102 | function isAbstract() {
103 | return false;
104 | }
105 |
106 | /**
107 | * Determines if the the entity is an interface, which for PHP 4
108 | * will never be the case.
109 | * @returns boolean True if interface.
110 | * @access public
111 | */
112 | function isInterface() {
113 | return false;
114 | }
115 |
116 | /**
117 | * Scans for final methods, but as it's PHP 4 there
118 | * aren't any.
119 | * @returns boolean True if the class has a final method.
120 | * @access public
121 | */
122 | function hasFinal() {
123 | return false;
124 | }
125 |
126 | /**
127 | * Gets the source code matching the declaration
128 | * of a method.
129 | * @param string $method Method name.
130 | * @access public
131 | */
132 | function getSignature($method) {
133 | return "function &$method()";
134 | }
135 | }
136 | ?>
--------------------------------------------------------------------------------
/_lp/simpletest/remote.php:
--------------------------------------------------------------------------------
1 | url = $url;
35 | $this->dry_url = $dry_url ? $dry_url : $url;
36 | $this->size = false;
37 | }
38 |
39 | /**
40 | * Accessor for the test name for subclasses.
41 | * @return string Name of the test.
42 | * @access public
43 | */
44 | function getLabel() {
45 | return $this->url;
46 | }
47 |
48 | /**
49 | * Runs the top level test for this class. Currently
50 | * reads the data as a single chunk. I'll fix this
51 | * once I have added iteration to the browser.
52 | * @param SimpleReporter $reporter Target of test results.
53 | * @returns boolean True if no failures.
54 | * @access public
55 | */
56 | function run($reporter) {
57 | $browser = $this->createBrowser();
58 | $xml = $browser->get($this->url);
59 | if (! $xml) {
60 | trigger_error('Cannot read remote test URL [' . $this->url . ']');
61 | return false;
62 | }
63 | $parser = $this->createParser($reporter);
64 | if (! $parser->parse($xml)) {
65 | trigger_error('Cannot parse incoming XML from [' . $this->url . ']');
66 | return false;
67 | }
68 | return true;
69 | }
70 |
71 | /**
72 | * Creates a new web browser object for fetching
73 | * the XML report.
74 | * @return SimpleBrowser New browser.
75 | * @access protected
76 | */
77 | protected function createBrowser() {
78 | return new SimpleBrowser();
79 | }
80 |
81 | /**
82 | * Creates the XML parser.
83 | * @param SimpleReporter $reporter Target of test results.
84 | * @return SimpleTestXmlListener XML reader.
85 | * @access protected
86 | */
87 | protected function createParser($reporter) {
88 | return new SimpleTestXmlParser($reporter);
89 | }
90 |
91 | /**
92 | * Accessor for the number of subtests.
93 | * @return integer Number of test cases.
94 | * @access public
95 | */
96 | function getSize() {
97 | if ($this->size === false) {
98 | $browser = $this->createBrowser();
99 | $xml = $browser->get($this->dry_url);
100 | if (! $xml) {
101 | trigger_error('Cannot read remote test URL [' . $this->dry_url . ']');
102 | return false;
103 | }
104 | $reporter = new SimpleReporter();
105 | $parser = $this->createParser($reporter);
106 | if (! $parser->parse($xml)) {
107 | trigger_error('Cannot parse incoming XML from [' . $this->dry_url . ']');
108 | return false;
109 | }
110 | $this->size = $reporter->getTestCaseCount();
111 | }
112 | return $this->size;
113 | }
114 | }
115 | ?>
--------------------------------------------------------------------------------
/_lp/simpletest/selector.php:
--------------------------------------------------------------------------------
1 | name = $name;
31 | }
32 |
33 | /**
34 | * Accessor for name.
35 | * @returns string $name Name to match.
36 | */
37 | function getName() {
38 | return $this->name;
39 | }
40 |
41 | /**
42 | * Compares with name attribute of widget.
43 | * @param SimpleWidget $widget Control to compare.
44 | * @access public
45 | */
46 | function isMatch($widget) {
47 | return ($widget->getName() == $this->name);
48 | }
49 | }
50 |
51 | /**
52 | * Used to extract form elements for testing against.
53 | * Searches by visible label or alt text.
54 | * @package SimpleTest
55 | * @subpackage WebTester
56 | */
57 | class SimpleByLabel {
58 | private $label;
59 |
60 | /**
61 | * Stashes the name for later comparison.
62 | * @param string $label Visible text to match.
63 | */
64 | function __construct($label) {
65 | $this->label = $label;
66 | }
67 |
68 | /**
69 | * Comparison. Compares visible text of widget or
70 | * related label.
71 | * @param SimpleWidget $widget Control to compare.
72 | * @access public
73 | */
74 | function isMatch($widget) {
75 | if (! method_exists($widget, 'isLabel')) {
76 | return false;
77 | }
78 | return $widget->isLabel($this->label);
79 | }
80 | }
81 |
82 | /**
83 | * Used to extract form elements for testing against.
84 | * Searches dy id attribute.
85 | * @package SimpleTest
86 | * @subpackage WebTester
87 | */
88 | class SimpleById {
89 | private $id;
90 |
91 | /**
92 | * Stashes the name for later comparison.
93 | * @param string $id ID atribute to match.
94 | */
95 | function __construct($id) {
96 | $this->id = $id;
97 | }
98 |
99 | /**
100 | * Comparison. Compares id attribute of widget.
101 | * @param SimpleWidget $widget Control to compare.
102 | * @access public
103 | */
104 | function isMatch($widget) {
105 | return $widget->isId($this->id);
106 | }
107 | }
108 |
109 | /**
110 | * Used to extract form elements for testing against.
111 | * Searches by visible label, name or alt text.
112 | * @package SimpleTest
113 | * @subpackage WebTester
114 | */
115 | class SimpleByLabelOrName {
116 | private $label;
117 |
118 | /**
119 | * Stashes the name/label for later comparison.
120 | * @param string $label Visible text to match.
121 | */
122 | function __construct($label) {
123 | $this->label = $label;
124 | }
125 |
126 | /**
127 | * Comparison. Compares visible text of widget or
128 | * related label or name.
129 | * @param SimpleWidget $widget Control to compare.
130 | * @access public
131 | */
132 | function isMatch($widget) {
133 | if (method_exists($widget, 'isLabel')) {
134 | if ($widget->isLabel($this->label)) {
135 | return true;
136 | }
137 | }
138 | return ($widget->getName() == $this->label);
139 | }
140 | }
141 | ?>
--------------------------------------------------------------------------------
/_lp/simpletest/shell_tester.php:
--------------------------------------------------------------------------------
1 | output = false;
29 | }
30 |
31 | /**
32 | * Actually runs the command. Does not trap the
33 | * error stream output as this need PHP 4.3+.
34 | * @param string $command The actual command line
35 | * to run.
36 | * @return integer Exit code.
37 | * @access public
38 | */
39 | function execute($command) {
40 | $this->output = false;
41 | exec($command, $this->output, $ret);
42 | return $ret;
43 | }
44 |
45 | /**
46 | * Accessor for the last output.
47 | * @return string Output as text.
48 | * @access public
49 | */
50 | function getOutput() {
51 | return implode("\n", $this->output);
52 | }
53 |
54 | /**
55 | * Accessor for the last output.
56 | * @return array Output as array of lines.
57 | * @access public
58 | */
59 | function getOutputAsList() {
60 | return $this->output;
61 | }
62 | }
63 |
64 | /**
65 | * Test case for testing of command line scripts and
66 | * utilities. Usually scripts that are external to the
67 | * PHP code, but support it in some way.
68 | * @package SimpleTest
69 | * @subpackage UnitTester
70 | */
71 | class ShellTestCase extends SimpleTestCase {
72 | private $current_shell;
73 | private $last_status;
74 | private $last_command;
75 |
76 | /**
77 | * Creates an empty test case. Should be subclassed
78 | * with test methods for a functional test case.
79 | * @param string $label Name of test case. Will use
80 | * the class name if none specified.
81 | * @access public
82 | */
83 | function __construct($label = false) {
84 | parent::__construct($label);
85 | $this->current_shell = $this->createShell();
86 | $this->last_status = false;
87 | $this->last_command = '';
88 | }
89 |
90 | /**
91 | * Executes a command and buffers the results.
92 | * @param string $command Command to run.
93 | * @return boolean True if zero exit code.
94 | * @access public
95 | */
96 | function execute($command) {
97 | $shell = $this->getShell();
98 | $this->last_status = $shell->execute($command);
99 | $this->last_command = $command;
100 | return ($this->last_status === 0);
101 | }
102 |
103 | /**
104 | * Dumps the output of the last command.
105 | * @access public
106 | */
107 | function dumpOutput() {
108 | $this->dump($this->getOutput());
109 | }
110 |
111 | /**
112 | * Accessor for the last output.
113 | * @return string Output as text.
114 | * @access public
115 | */
116 | function getOutput() {
117 | $shell = $this->getShell();
118 | return $shell->getOutput();
119 | }
120 |
121 | /**
122 | * Accessor for the last output.
123 | * @return array Output as array of lines.
124 | * @access public
125 | */
126 | function getOutputAsList() {
127 | $shell = $this->getShell();
128 | return $shell->getOutputAsList();
129 | }
130 |
131 | /**
132 | * Called from within the test methods to register
133 | * passes and failures.
134 | * @param boolean $result Pass on true.
135 | * @param string $message Message to display describing
136 | * the test state.
137 | * @return boolean True on pass
138 | * @access public
139 | */
140 | function assertTrue($result, $message = false) {
141 | return $this->assert(new TrueExpectation(), $result, $message);
142 | }
143 |
144 | /**
145 | * Will be true on false and vice versa. False
146 | * is the PHP definition of false, so that null,
147 | * empty strings, zero and an empty array all count
148 | * as false.
149 | * @param boolean $result Pass on false.
150 | * @param string $message Message to display.
151 | * @return boolean True on pass
152 | * @access public
153 | */
154 | function assertFalse($result, $message = '%s') {
155 | return $this->assert(new FalseExpectation(), $result, $message);
156 | }
157 |
158 | /**
159 | * Will trigger a pass if the two parameters have
160 | * the same value only. Otherwise a fail. This
161 | * is for testing hand extracted text, etc.
162 | * @param mixed $first Value to compare.
163 | * @param mixed $second Value to compare.
164 | * @param string $message Message to display.
165 | * @return boolean True on pass
166 | * @access public
167 | */
168 | function assertEqual($first, $second, $message = "%s") {
169 | return $this->assert(
170 | new EqualExpectation($first),
171 | $second,
172 | $message);
173 | }
174 |
175 | /**
176 | * Will trigger a pass if the two parameters have
177 | * a different value. Otherwise a fail. This
178 | * is for testing hand extracted text, etc.
179 | * @param mixed $first Value to compare.
180 | * @param mixed $second Value to compare.
181 | * @param string $message Message to display.
182 | * @return boolean True on pass
183 | * @access public
184 | */
185 | function assertNotEqual($first, $second, $message = "%s") {
186 | return $this->assert(
187 | new NotEqualExpectation($first),
188 | $second,
189 | $message);
190 | }
191 |
192 | /**
193 | * Tests the last status code from the shell.
194 | * @param integer $status Expected status of last
195 | * command.
196 | * @param string $message Message to display.
197 | * @return boolean True if pass.
198 | * @access public
199 | */
200 | function assertExitCode($status, $message = "%s") {
201 | $message = sprintf($message, "Expected status code of [$status] from [" .
202 | $this->last_command . "], but got [" .
203 | $this->last_status . "]");
204 | return $this->assertTrue($status === $this->last_status, $message);
205 | }
206 |
207 | /**
208 | * Attempt to exactly match the combined STDERR and
209 | * STDOUT output.
210 | * @param string $expected Expected output.
211 | * @param string $message Message to display.
212 | * @return boolean True if pass.
213 | * @access public
214 | */
215 | function assertOutput($expected, $message = "%s") {
216 | $shell = $this->getShell();
217 | return $this->assert(
218 | new EqualExpectation($expected),
219 | $shell->getOutput(),
220 | $message);
221 | }
222 |
223 | /**
224 | * Scans the output for a Perl regex. If found
225 | * anywhere it passes, else it fails.
226 | * @param string $pattern Regex to search for.
227 | * @param string $message Message to display.
228 | * @return boolean True if pass.
229 | * @access public
230 | */
231 | function assertOutputPattern($pattern, $message = "%s") {
232 | $shell = $this->getShell();
233 | return $this->assert(
234 | new PatternExpectation($pattern),
235 | $shell->getOutput(),
236 | $message);
237 | }
238 |
239 | /**
240 | * If a Perl regex is found anywhere in the current
241 | * output then a failure is generated, else a pass.
242 | * @param string $pattern Regex to search for.
243 | * @param $message Message to display.
244 | * @return boolean True if pass.
245 | * @access public
246 | */
247 | function assertNoOutputPattern($pattern, $message = "%s") {
248 | $shell = $this->getShell();
249 | return $this->assert(
250 | new NoPatternExpectation($pattern),
251 | $shell->getOutput(),
252 | $message);
253 | }
254 |
255 | /**
256 | * File existence check.
257 | * @param string $path Full filename and path.
258 | * @param string $message Message to display.
259 | * @return boolean True if pass.
260 | * @access public
261 | */
262 | function assertFileExists($path, $message = "%s") {
263 | $message = sprintf($message, "File [$path] should exist");
264 | return $this->assertTrue(file_exists($path), $message);
265 | }
266 |
267 | /**
268 | * File non-existence check.
269 | * @param string $path Full filename and path.
270 | * @param string $message Message to display.
271 | * @return boolean True if pass.
272 | * @access public
273 | */
274 | function assertFileNotExists($path, $message = "%s") {
275 | $message = sprintf($message, "File [$path] should not exist");
276 | return $this->assertFalse(file_exists($path), $message);
277 | }
278 |
279 | /**
280 | * Scans a file for a Perl regex. If found
281 | * anywhere it passes, else it fails.
282 | * @param string $pattern Regex to search for.
283 | * @param string $path Full filename and path.
284 | * @param string $message Message to display.
285 | * @return boolean True if pass.
286 | * @access public
287 | */
288 | function assertFilePattern($pattern, $path, $message = "%s") {
289 | return $this->assert(
290 | new PatternExpectation($pattern),
291 | implode('', file($path)),
292 | $message);
293 | }
294 |
295 | /**
296 | * If a Perl regex is found anywhere in the named
297 | * file then a failure is generated, else a pass.
298 | * @param string $pattern Regex to search for.
299 | * @param string $path Full filename and path.
300 | * @param string $message Message to display.
301 | * @return boolean True if pass.
302 | * @access public
303 | */
304 | function assertNoFilePattern($pattern, $path, $message = "%s") {
305 | return $this->assert(
306 | new NoPatternExpectation($pattern),
307 | implode('', file($path)),
308 | $message);
309 | }
310 |
311 | /**
312 | * Accessor for current shell. Used for testing the
313 | * the tester itself.
314 | * @return Shell Current shell.
315 | * @access protected
316 | */
317 | protected function getShell() {
318 | return $this->current_shell;
319 | }
320 |
321 | /**
322 | * Factory for the shell to run the command on.
323 | * @return Shell New shell object.
324 | * @access protected
325 | */
326 | protected function createShell() {
327 | return new SimpleShell();
328 | }
329 | }
330 | ?>
--------------------------------------------------------------------------------
/_lp/simpletest/socket.php:
--------------------------------------------------------------------------------
1 | clearError();
30 | }
31 |
32 | /**
33 | * Test for an outstanding error.
34 | * @return boolean True if there is an error.
35 | * @access public
36 | */
37 | function isError() {
38 | return ($this->error != '');
39 | }
40 |
41 | /**
42 | * Accessor for an outstanding error.
43 | * @return string Empty string if no error otherwise
44 | * the error message.
45 | * @access public
46 | */
47 | function getError() {
48 | return $this->error;
49 | }
50 |
51 | /**
52 | * Sets the internal error.
53 | * @param string Error message to stash.
54 | * @access protected
55 | */
56 | function setError($error) {
57 | $this->error = $error;
58 | }
59 |
60 | /**
61 | * Resets the error state to no error.
62 | * @access protected
63 | */
64 | function clearError() {
65 | $this->setError('');
66 | }
67 | }
68 |
69 | /**
70 | * @package SimpleTest
71 | * @subpackage WebTester
72 | */
73 | class SimpleFileSocket extends SimpleStickyError {
74 | private $handle;
75 | private $is_open = false;
76 | private $sent = '';
77 | private $block_size;
78 |
79 | /**
80 | * Opens a socket for reading and writing.
81 | * @param SimpleUrl $file Target URI to fetch.
82 | * @param integer $block_size Size of chunk to read.
83 | * @access public
84 | */
85 | function __construct($file, $block_size = 1024) {
86 | parent::__construct();
87 | if (! ($this->handle = $this->openFile($file, $error))) {
88 | $file_string = $file->asString();
89 | $this->setError("Cannot open [$file_string] with [$error]");
90 | return;
91 | }
92 | $this->is_open = true;
93 | $this->block_size = $block_size;
94 | }
95 |
96 | /**
97 | * Writes some data to the socket and saves alocal copy.
98 | * @param string $message String to send to socket.
99 | * @return boolean True if successful.
100 | * @access public
101 | */
102 | function write($message) {
103 | return true;
104 | }
105 |
106 | /**
107 | * Reads data from the socket. The error suppresion
108 | * is a workaround for PHP4 always throwing a warning
109 | * with a secure socket.
110 | * @return integer/boolean Incoming bytes. False
111 | * on error.
112 | * @access public
113 | */
114 | function read() {
115 | $raw = @fread($this->handle, $this->block_size);
116 | if ($raw === false) {
117 | $this->setError('Cannot read from socket');
118 | $this->close();
119 | }
120 | return $raw;
121 | }
122 |
123 | /**
124 | * Accessor for socket open state.
125 | * @return boolean True if open.
126 | * @access public
127 | */
128 | function isOpen() {
129 | return $this->is_open;
130 | }
131 |
132 | /**
133 | * Closes the socket preventing further reads.
134 | * Cannot be reopened once closed.
135 | * @return boolean True if successful.
136 | * @access public
137 | */
138 | function close() {
139 | if (!$this->is_open) return false;
140 | $this->is_open = false;
141 | return fclose($this->handle);
142 | }
143 |
144 | /**
145 | * Accessor for content so far.
146 | * @return string Bytes sent only.
147 | * @access public
148 | */
149 | function getSent() {
150 | return $this->sent;
151 | }
152 |
153 | /**
154 | * Actually opens the low level socket.
155 | * @param SimpleUrl $file SimpleUrl file target.
156 | * @param string $error Recipient of error message.
157 | * @param integer $timeout Maximum time to wait for connection.
158 | * @access protected
159 | */
160 | protected function openFile($file, &$error) {
161 | return @fopen($file->asString(), 'r');
162 | }
163 | }
164 |
165 | /**
166 | * Wrapper for TCP/IP socket.
167 | * @package SimpleTest
168 | * @subpackage WebTester
169 | */
170 | class SimpleSocket extends SimpleStickyError {
171 | private $handle;
172 | private $is_open = false;
173 | private $sent = '';
174 | private $lock_size;
175 |
176 | /**
177 | * Opens a socket for reading and writing.
178 | * @param string $host Hostname to send request to.
179 | * @param integer $port Port on remote machine to open.
180 | * @param integer $timeout Connection timeout in seconds.
181 | * @param integer $block_size Size of chunk to read.
182 | * @access public
183 | */
184 | function __construct($host, $port, $timeout, $block_size = 255) {
185 | parent::__construct();
186 | if (! ($this->handle = $this->openSocket($host, $port, $error_number, $error, $timeout))) {
187 | $this->setError("Cannot open [$host:$port] with [$error] within [$timeout] seconds");
188 | return;
189 | }
190 | $this->is_open = true;
191 | $this->block_size = $block_size;
192 | SimpleTestCompatibility::setTimeout($this->handle, $timeout);
193 | }
194 |
195 | /**
196 | * Writes some data to the socket and saves alocal copy.
197 | * @param string $message String to send to socket.
198 | * @return boolean True if successful.
199 | * @access public
200 | */
201 | function write($message) {
202 | if ($this->isError() || ! $this->isOpen()) {
203 | return false;
204 | }
205 | $count = fwrite($this->handle, $message);
206 | if (! $count) {
207 | if ($count === false) {
208 | $this->setError('Cannot write to socket');
209 | $this->close();
210 | }
211 | return false;
212 | }
213 | fflush($this->handle);
214 | $this->sent .= $message;
215 | return true;
216 | }
217 |
218 | /**
219 | * Reads data from the socket. The error suppresion
220 | * is a workaround for PHP4 always throwing a warning
221 | * with a secure socket.
222 | * @return integer/boolean Incoming bytes. False
223 | * on error.
224 | * @access public
225 | */
226 | function read() {
227 | if ($this->isError() || ! $this->isOpen()) {
228 | return false;
229 | }
230 | $raw = @fread($this->handle, $this->block_size);
231 | if ($raw === false) {
232 | $this->setError('Cannot read from socket');
233 | $this->close();
234 | }
235 | return $raw;
236 | }
237 |
238 | /**
239 | * Accessor for socket open state.
240 | * @return boolean True if open.
241 | * @access public
242 | */
243 | function isOpen() {
244 | return $this->is_open;
245 | }
246 |
247 | /**
248 | * Closes the socket preventing further reads.
249 | * Cannot be reopened once closed.
250 | * @return boolean True if successful.
251 | * @access public
252 | */
253 | function close() {
254 | $this->is_open = false;
255 | return fclose($this->handle);
256 | }
257 |
258 | /**
259 | * Accessor for content so far.
260 | * @return string Bytes sent only.
261 | * @access public
262 | */
263 | function getSent() {
264 | return $this->sent;
265 | }
266 |
267 | /**
268 | * Actually opens the low level socket.
269 | * @param string $host Host to connect to.
270 | * @param integer $port Port on host.
271 | * @param integer $error_number Recipient of error code.
272 | * @param string $error Recipoent of error message.
273 | * @param integer $timeout Maximum time to wait for connection.
274 | * @access protected
275 | */
276 | protected function openSocket($host, $port, &$error_number, &$error, $timeout) {
277 | return @fsockopen($host, $port, $error_number, $error, $timeout);
278 | }
279 | }
280 |
281 | /**
282 | * Wrapper for TCP/IP socket over TLS.
283 | * @package SimpleTest
284 | * @subpackage WebTester
285 | */
286 | class SimpleSecureSocket extends SimpleSocket {
287 |
288 | /**
289 | * Opens a secure socket for reading and writing.
290 | * @param string $host Hostname to send request to.
291 | * @param integer $port Port on remote machine to open.
292 | * @param integer $timeout Connection timeout in seconds.
293 | * @access public
294 | */
295 | function __construct($host, $port, $timeout) {
296 | parent::__construct($host, $port, $timeout);
297 | }
298 |
299 | /**
300 | * Actually opens the low level socket.
301 | * @param string $host Host to connect to.
302 | * @param integer $port Port on host.
303 | * @param integer $error_number Recipient of error code.
304 | * @param string $error Recipient of error message.
305 | * @param integer $timeout Maximum time to wait for connection.
306 | * @access protected
307 | */
308 | function openSocket($host, $port, &$error_number, &$error, $timeout) {
309 | return parent::openSocket("tls://$host", $port, $error_number, $error, $timeout);
310 | }
311 | }
312 | ?>
--------------------------------------------------------------------------------
/_lp/simpletest/user_agent.php:
--------------------------------------------------------------------------------
1 | cookie_jar = new SimpleCookieJar();
48 | $this->authenticator = new SimpleAuthenticator();
49 | }
50 |
51 | /**
52 | * Removes expired and temporary cookies as if
53 | * the browser was closed and re-opened. Authorisation
54 | * has to be obtained again as well.
55 | * @param string/integer $date Time when session restarted.
56 | * If omitted then all persistent
57 | * cookies are kept.
58 | * @access public
59 | */
60 | function restart($date = false) {
61 | $this->cookie_jar->restartSession($date);
62 | $this->authenticator->restartSession();
63 | }
64 |
65 | /**
66 | * Adds a header to every fetch.
67 | * @param string $header Header line to add to every
68 | * request until cleared.
69 | * @access public
70 | */
71 | function addHeader($header) {
72 | $this->additional_headers[] = $header;
73 | }
74 |
75 | /**
76 | * Ages the cookies by the specified time.
77 | * @param integer $interval Amount in seconds.
78 | * @access public
79 | */
80 | function ageCookies($interval) {
81 | $this->cookie_jar->agePrematurely($interval);
82 | }
83 |
84 | /**
85 | * Sets an additional cookie. If a cookie has
86 | * the same name and path it is replaced.
87 | * @param string $name Cookie key.
88 | * @param string $value Value of cookie.
89 | * @param string $host Host upon which the cookie is valid.
90 | * @param string $path Cookie path if not host wide.
91 | * @param string $expiry Expiry date.
92 | * @access public
93 | */
94 | function setCookie($name, $value, $host = false, $path = '/', $expiry = false) {
95 | $this->cookie_jar->setCookie($name, $value, $host, $path, $expiry);
96 | }
97 |
98 | /**
99 | * Reads the most specific cookie value from the
100 | * browser cookies.
101 | * @param string $host Host to search.
102 | * @param string $path Applicable path.
103 | * @param string $name Name of cookie to read.
104 | * @return string False if not present, else the
105 | * value as a string.
106 | * @access public
107 | */
108 | function getCookieValue($host, $path, $name) {
109 | return $this->cookie_jar->getCookieValue($host, $path, $name);
110 | }
111 |
112 | /**
113 | * Reads the current cookies within the base URL.
114 | * @param string $name Key of cookie to find.
115 | * @param SimpleUrl $base Base URL to search from.
116 | * @return string/boolean Null if there is no base URL, false
117 | * if the cookie is not set.
118 | * @access public
119 | */
120 | function getBaseCookieValue($name, $base) {
121 | if (! $base) {
122 | return null;
123 | }
124 | return $this->getCookieValue($base->getHost(), $base->getPath(), $name);
125 | }
126 |
127 | /**
128 | * Switches off cookie sending and recieving.
129 | * @access public
130 | */
131 | function ignoreCookies() {
132 | $this->cookies_enabled = false;
133 | }
134 |
135 | /**
136 | * Switches back on the cookie sending and recieving.
137 | * @access public
138 | */
139 | function useCookies() {
140 | $this->cookies_enabled = true;
141 | }
142 |
143 | /**
144 | * Sets the socket timeout for opening a connection.
145 | * @param integer $timeout Maximum time in seconds.
146 | * @access public
147 | */
148 | function setConnectionTimeout($timeout) {
149 | $this->connection_timeout = $timeout;
150 | }
151 |
152 | /**
153 | * Sets the maximum number of redirects before
154 | * a page will be loaded anyway.
155 | * @param integer $max Most hops allowed.
156 | * @access public
157 | */
158 | function setMaximumRedirects($max) {
159 | $this->max_redirects = $max;
160 | }
161 |
162 | /**
163 | * Sets proxy to use on all requests for when
164 | * testing from behind a firewall. Set URL
165 | * to false to disable.
166 | * @param string $proxy Proxy URL.
167 | * @param string $username Proxy username for authentication.
168 | * @param string $password Proxy password for authentication.
169 | * @access public
170 | */
171 | function useProxy($proxy, $username, $password) {
172 | if (! $proxy) {
173 | $this->proxy = false;
174 | return;
175 | }
176 | if ((strncmp($proxy, 'http://', 7) != 0) && (strncmp($proxy, 'https://', 8) != 0)) {
177 | $proxy = 'http://'. $proxy;
178 | }
179 | $this->proxy = new SimpleUrl($proxy);
180 | $this->proxy_username = $username;
181 | $this->proxy_password = $password;
182 | }
183 |
184 | /**
185 | * Test to see if the redirect limit is passed.
186 | * @param integer $redirects Count so far.
187 | * @return boolean True if over.
188 | * @access private
189 | */
190 | protected function isTooManyRedirects($redirects) {
191 | return ($redirects > $this->max_redirects);
192 | }
193 |
194 | /**
195 | * Sets the identity for the current realm.
196 | * @param string $host Host to which realm applies.
197 | * @param string $realm Full name of realm.
198 | * @param string $username Username for realm.
199 | * @param string $password Password for realm.
200 | * @access public
201 | */
202 | function setIdentity($host, $realm, $username, $password) {
203 | $this->authenticator->setIdentityForRealm($host, $realm, $username, $password);
204 | }
205 |
206 | /**
207 | * Fetches a URL as a response object. Will keep trying if redirected.
208 | * It will also collect authentication realm information.
209 | * @param string/SimpleUrl $url Target to fetch.
210 | * @param SimpleEncoding $encoding Additional parameters for request.
211 | * @return SimpleHttpResponse Hopefully the target page.
212 | * @access public
213 | */
214 | function fetchResponse($url, $encoding) {
215 | if ($encoding->getMethod() != 'POST') {
216 | $url->addRequestParameters($encoding);
217 | $encoding->clear();
218 | }
219 | $response = $this->fetchWhileRedirected($url, $encoding);
220 | if ($headers = $response->getHeaders()) {
221 | if ($headers->isChallenge()) {
222 | $this->authenticator->addRealm(
223 | $url,
224 | $headers->getAuthentication(),
225 | $headers->getRealm());
226 | }
227 | }
228 | return $response;
229 | }
230 |
231 | /**
232 | * Fetches the page until no longer redirected or
233 | * until the redirect limit runs out.
234 | * @param SimpleUrl $url Target to fetch.
235 | * @param SimpelFormEncoding $encoding Additional parameters for request.
236 | * @return SimpleHttpResponse Hopefully the target page.
237 | * @access private
238 | */
239 | protected function fetchWhileRedirected($url, $encoding) {
240 | $redirects = 0;
241 | do {
242 | $response = $this->fetch($url, $encoding);
243 | if ($response->isError()) {
244 | return $response;
245 | }
246 | $headers = $response->getHeaders();
247 | if ($this->cookies_enabled) {
248 | $headers->writeCookiesToJar($this->cookie_jar, $url);
249 | }
250 | if (! $headers->isRedirect()) {
251 | break;
252 | }
253 | $location = new SimpleUrl($headers->getLocation());
254 | $url = $location->makeAbsolute($url);
255 | $encoding = new SimpleGetEncoding();
256 | } while (! $this->isTooManyRedirects(++$redirects));
257 | return $response;
258 | }
259 |
260 | /**
261 | * Actually make the web request.
262 | * @param SimpleUrl $url Target to fetch.
263 | * @param SimpleFormEncoding $encoding Additional parameters for request.
264 | * @return SimpleHttpResponse Headers and hopefully content.
265 | * @access protected
266 | */
267 | protected function fetch($url, $encoding) {
268 | $request = $this->createRequest($url, $encoding);
269 | return $request->fetch($this->connection_timeout);
270 | }
271 |
272 | /**
273 | * Creates a full page request.
274 | * @param SimpleUrl $url Target to fetch as url object.
275 | * @param SimpleFormEncoding $encoding POST/GET parameters.
276 | * @return SimpleHttpRequest New request.
277 | * @access private
278 | */
279 | protected function createRequest($url, $encoding) {
280 | $request = $this->createHttpRequest($url, $encoding);
281 | $this->addAdditionalHeaders($request);
282 | if ($this->cookies_enabled) {
283 | $request->readCookiesFromJar($this->cookie_jar, $url);
284 | }
285 | $this->authenticator->addHeaders($request, $url);
286 | return $request;
287 | }
288 |
289 | /**
290 | * Builds the appropriate HTTP request object.
291 | * @param SimpleUrl $url Target to fetch as url object.
292 | * @param SimpleFormEncoding $parameters POST/GET parameters.
293 | * @return SimpleHttpRequest New request object.
294 | * @access protected
295 | */
296 | protected function createHttpRequest($url, $encoding) {
297 | return new SimpleHttpRequest($this->createRoute($url), $encoding);
298 | }
299 |
300 | /**
301 | * Sets up either a direct route or via a proxy.
302 | * @param SimpleUrl $url Target to fetch as url object.
303 | * @return SimpleRoute Route to take to fetch URL.
304 | * @access protected
305 | */
306 | protected function createRoute($url) {
307 | if ($this->proxy) {
308 | return new SimpleProxyRoute(
309 | $url,
310 | $this->proxy,
311 | $this->proxy_username,
312 | $this->proxy_password);
313 | }
314 | return new SimpleRoute($url);
315 | }
316 |
317 | /**
318 | * Adds additional manual headers.
319 | * @param SimpleHttpRequest $request Outgoing request.
320 | * @access private
321 | */
322 | protected function addAdditionalHeaders(&$request) {
323 | foreach ($this->additional_headers as $header) {
324 | $request->addHeaderLine($header);
325 | }
326 | }
327 | }
328 | ?>
--------------------------------------------------------------------------------
/_lp/st.init.php:
--------------------------------------------------------------------------------
1 | addFile( $f );
33 |
34 |
35 | //$test->run(new HtmlReporter('UTF-8'));
36 | unset( $test );
37 |
38 |
39 |
40 |
--------------------------------------------------------------------------------
/config/app.config.php:
--------------------------------------------------------------------------------
1 | @Easy | Twitter - @Easychen" , "Follow Me" );
59 | }
60 |
61 | function test()
62 | {
63 | $data['title'] = $data['top_title'] = '自动测试页';
64 | $data['info'] = '根据访问来源自动切换Layout';
65 |
66 | return render( $data );
67 | }
68 |
69 | function sql()
70 | {
71 | db();
72 | echo $sql = prepare( "SELECT * FROM `user` WHERE `name` = ?s AND `uid` = ?i AND `level` = ?s LIMIT 1" , array( "Easy'" , '-1', '9.56' ) );
73 | }
74 |
75 |
76 | }
77 |
--------------------------------------------------------------------------------
/index.php:
--------------------------------------------------------------------------------
1 | '登入',
5 | 'logout' => '退出',
6 | 'hello%s' => '你好%s'
7 | );
8 |
--------------------------------------------------------------------------------
/model/README:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/windiest/LazyPHP/99f2837615a0801bb27520827b4ec73fb8559b20/model/README
--------------------------------------------------------------------------------
/static/css/ie6.min.css:
--------------------------------------------------------------------------------
1 | body{background:#fff;background-image:none;padding:0;}.row{margin:0 0 0 -20px;}.span1,.span2,.span3,.span4,.span5,.span6,.span7,.span8,.span9,.span10,.span11,.span12{float:left;display:inline;}.last-child{margin-right:0;}.margin-left-20{float:left;margin-left:20px;}.nav li a{display:block;}.navbar .nav .active a,.navbar .nav .active a:hover{color:#fff;text-decoration:none;background-color:rgba(0,0,0,0.5);}.navbar .nav li{display:block;float:left;}.navbar .nav li a{float:none;line-height:19px;padding:10px 10px 11px;}.navbar .nav li a:hover{background-color:transparent;color:#fff;text-decoration:none;}.navbar .nav .open .dropdown-toggle,.navbar .nav .active .dropdown-toggle,.navbar .nav .open.active .dropdown-toggle{background-color:transparent;}.navbar .nav .active .dropdown-toggle:hover{color:#fff;}.dropdown .dropdown-toggle{margin-bottom:1px;position:relative;top:2px;left:0;}.dropdown-menu li a:hover,.dropdown-menu .active a,.dropdown-menu .active a:hover{background-color:#08C;color:#FFF;text-decoration:none;}.nav-tabs li{float:left;display:inline;margin-bottom:-2px;}.nav-tabs li a{line-height:14px;margin-right:2px;padding:9px 12px;}.nav-tabs li.active{background:none;border:1px solid #ddd;border-color:#eee #eee #ddd;}.tab-content .tab-pane.active{display:block;background-color:transparent;}.button-reset{height:auto;width:auto;margin-bottom:0;}.input-text{display:inline-block;line-height:18px;height:18px;border:1px solid #ccc;font-family:'Helvetica Neue',Helvetica,Arial,sans-serif;margin:0 0 9px;padding:4px;}.help-inline{display:block;line-height:18px;height:18px;padding:4px 0 4px 5px;}.form-inline label.checkbox{display:inline-block;line-height:18px;height:18px;width:auto;padding-left:0;margin:0;}.form-inline .input-checkbox{width:auto;float:left;display:inline-block;height:auto;border:non;margin:0;padding:0;}.form-horizontal .help-block{display:inline-block;margin-left:3px;}.form-horizontal .control-label{float:left;display:inline-block;width:140px;text-align:right;padding-top:5px;}.form-horizontal label.checkbox{display:inline-block;line-height:18px;height:18px;width:auto;padding-left:0;margin:0 9px 9px 0;}.form-horizontal .input-checkbox{margin-left:-3px;}.form-horizontal .input-multiple{height:auto;}.form-horizontal .input-file{display:inline-block;line-height:24px;height:24px;width:220px;padding:4px;}.btn-primary{margin-right:4px;}.disabled{cursor:not-allowed;}.control-group.warning label,.control-group.warning .help-block,.control-group.warning .help-inline{color:#C09853;}.control-group.error label,.control-group.error .help-block,.control-group.error .help-inline{color:#B94A48;}.control-group.success label,.control-group.success .help-block,.control-group.success .help-inline{color:#468847;}input.span1,input.span2,input.span3,input.span4,input.span5,input.span6,input.span7,input.span8,input.span9,input.span10,input.span11,input.span12,select.span1,select.span2,select.span3,select.span4,select.span5,select.span6,select.span7,select.span8,select.span9,select.span10,select.span11,select.span12{float:left;display:inline-block;margin:0;}input.btn,a.btn,button.btn{height:auto,width:auto;}.input-prepend input{margin-top:1px;}.icon-sprite{background-image:url(http://twitter.github.com/bootstrap/assets/img/glyphicons-halflings.png);background-repeat:no-repeat;display:inline-block;height:14px;line-height:14px;vertical-align:text-top;width:14px;padding-left:3px;}.dropdown .caret{font-size:1px;height:2px;background:none;background-color:#292929;color:#292929;}.pagination-first-child{border-left-width:1px!important;}ul.thumbnails{background-color:red;margin-left:-20px;float:none;display:inline-block;zoom:1;clear:both;}.thumbnails li{float:left;background-color:#FF0;margin:0 0 18px 20px;}.tooltip.top{margin-top:5px;}.tooltip.bottom{margin-top:-5px;}.popover{opacity:1;filter:alpha(opacity=100);}.popover.top{margin-top:-7px;}.popover.bottom{margin-top:7px;}.btn{margin-left:0;padding:2px 8px;}.btn:hover{opacity:.4;filter:alpha(opacity=40);background-color:transparent;background-position:0 0;color:#000;}.modal{position:relative;filter:alpha(opacity=99);top:55%;}.modal-header a.close{cursor:pointer;}.nav-collapse,legend{width:auto;}.dropdown-menu li,.dropdown-menu li a{width:100%;}.tab-content .tab-pane,.tooltip.top .tooltip-arrow,.tooltip.right .tooltip-arrow,.tooltip.bottom .tooltip-arrow,.tooltip.left .tooltip-arrow,.popover.top .arrow,.popover.right .arrow,.popover.bottom .arrow,.popover.left .arrow{display:none;}label.checkbox,label.radio{display:block;line-height:18px;height:18px;width:100%;padding-left:0;margin:0 0 9px -2px;}.input-checkbox,.input-radio{width:auto;float:left;display:inline-block;height:auto;border:none;margin:0;padding:0;}
--------------------------------------------------------------------------------
/static/css/style.css:
--------------------------------------------------------------------------------
1 | #ft
2 | {
3 | color:#999;
4 | text-align:center;
5 | margin-top:20px;
6 | }
7 |
8 | #main,#side
9 | {
10 | min-height:400px;
11 | _height:400px;
12 | background:#eee;
13 |
14 | -moz-border-radius: 5px;
15 | -webkit-border-radius: 5px;
16 | border-radius: 5px;
17 | }
18 |
19 | #side
20 | {
21 | width:160px;
22 | margin-right:10px;
23 | }
24 |
25 | .content_box,.cbox
26 | {
27 | padding:10px;
28 | }
29 |
30 | .form_notice
31 | {
32 | padding:5px;
33 | margin:5px;
34 | margin-left:0px;
35 | margin-top:0px;
36 | }
37 |
38 | .front-page h1
39 | {
40 | margin-bottom: 10px;
41 | }
42 |
43 | #lp_pop_box
44 | {
45 | position:absolute;
46 | position:fixed;
47 | width:400px;
48 | background:rgba( 0 , 0 , 0 , 0.2 );
49 | margin:auto;
50 | top:200px;
51 |
52 | -moz-border-radius: 5px;
53 | -webkit-border-radius: 5px;
54 | border-radius: 5px;
55 | }
56 |
57 | #lp_pop_container
58 | {
59 | margin:10px;
60 | min-height:200px;
61 | height:100%;
62 |
63 | background: white; /* fallback for older/unsupporting browsers */
64 | background: -moz-linear-gradient(top, #eee, white 8%);
65 | background: -webkit-gradient(linear, 0 0, 0 8%, from(#eee), to(white));
66 |
67 | }
68 |
69 | .close
70 | {
71 | float:right;
72 | cursor:pointer;
73 | }
74 |
75 | .round5
76 | {
77 | -moz-border-radius: 5px;
78 | -webkit-border-radius: 5px;
79 | border-radius: 5px;
80 | }
81 |
82 | .x2
83 | {
84 | line-height:200%;
85 | }
86 |
87 | .x1-5
88 | {
89 | line-height:150%;
90 | }
91 |
92 | a
93 | {
94 | color:#0066cc;
95 | text-decoration:none;
96 | }
97 |
98 | a:hover
99 | {
100 | text-decoration:underline;
101 | }
102 |
103 |
104 |
--------------------------------------------------------------------------------
/static/image/cross.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/windiest/LazyPHP/99f2837615a0801bb27520827b4ec73fb8559b20/static/image/cross.png
--------------------------------------------------------------------------------
/static/image/glyphicons-halflings-white.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/windiest/LazyPHP/99f2837615a0801bb27520827b4ec73fb8559b20/static/image/glyphicons-halflings-white.png
--------------------------------------------------------------------------------
/static/image/glyphicons-halflings.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/windiest/LazyPHP/99f2837615a0801bb27520827b4ec73fb8559b20/static/image/glyphicons-halflings.png
--------------------------------------------------------------------------------
/static/script/app.js:
--------------------------------------------------------------------------------
1 | /*
2 | send form data via ajax and return the data to callback function
3 | */
4 | function send_form( name , func )
5 | {
6 | var url = $('#'+name).attr('action');
7 |
8 | var params = {};
9 | $.each( $('#'+name).serializeArray(), function(index,value)
10 | {
11 | params[value.name] = value.value;
12 | });
13 |
14 |
15 | $.post( url , params , func );
16 | }
17 |
18 | /*
19 | send form data via ajax and show the return content to pop div
20 | */
21 |
22 | function send_form_pop( name )
23 | {
24 | return send_form( name , function( data ){ show_pop_box( data ); } );
25 | }
26 |
27 | /*
28 | send form data via ajax and show the return content in front of the form
29 | */
30 | function send_form_in( name )
31 | {
32 | return send_form( name , function( data ){ set_form_notice( name , data ) } );
33 | }
34 |
35 |
36 | function set_form_notice( name , data )
37 | {
38 | data = '' + data + '';
39 |
40 | if( $('#form_'+name+'_notice').length != 0 )
41 | {
42 | $('#form_'+name+'_notice').html(data);
43 | }
44 | else
45 | {
46 | var odiv = $( "" );
47 | odiv.attr( 'id' , 'form_'+name+'_notice' );
48 | odiv.html(data);
49 | $('#'+name).prepend( odiv );
50 | }
51 |
52 | }
53 |
54 |
55 | function show_pop_box( data , popid )
56 | {
57 | if( popid == undefined ) popid = 'lp_pop_box'
58 | //console.log($('#' + popid) );
59 | if( $('#' + popid).length == 0 )
60 | {
61 | var did = $('');
62 | did.attr( 'id' , popid );
63 | did.css( 'display','none' );
64 | $('body').prepend(did);
65 | }
66 |
67 | if( data != '' )
68 | $('#lp_pop_container').html(data);
69 |
70 | var left = ($(window).width() - $('#' + popid ).width())/2;
71 |
72 | $('#' + popid ).css('left',left);
73 | $('#' + popid ).css('display','block');
74 | }
75 |
76 | function hide_pop_box( popid )
77 | {
78 | if( popid == undefined ) popid = 'lp_pop_box'
79 | $('#' + popid ).css('display','none');
80 | }
81 |
82 |
83 |
84 | /* post demo
85 | $.post( 'url&get var' , { 'post':'value'} , function( data )
86 | {
87 | var data_obj = jQuery.parseJSON( data );
88 | console.log( data_obj );
89 |
90 | if( data_obj.err_code == 0 )
91 | {
92 |
93 | }
94 | else
95 | {
96 |
97 | }
98 | } );
99 |
100 | */
--------------------------------------------------------------------------------
/static/script/html5.js:
--------------------------------------------------------------------------------
1 | /*! HTML5 Shiv pre3.5 | @afarkas @jdalton @jon_neal @rem | MIT/GPL2 Licensed
2 | Uncompressed source: https://github.com/aFarkas/html5shiv */
3 | (function(a,b){function h(a,b){var c=a.createElement("p"),d=a.getElementsByTagName("head")[0]||a.documentElement;return c.innerHTML="x",d.insertBefore(c.lastChild,d.firstChild)}function i(){var a=l.elements;return typeof a=="string"?a.split(" "):a}function j(a){var b={},c=a.createElement,f=a.createDocumentFragment,g=f();a.createElement=function(a){l.shivMethods||c(a);var f;return b[a]?f=b[a].cloneNode():e.test(a)?f=(b[a]=c(a)).cloneNode():f=c(a),f.canHaveChildren&&!d.test(a)?g.appendChild(f):f},a.createDocumentFragment=Function("h,f","return function(){var n=f.cloneNode(),c=n.createElement;h.shivMethods&&("+i().join().replace(/\w+/g,function(a){return b[a]=c(a),g.createElement(a),'c("'+a+'")'})+");return n}")(l,g)}function k(a){var b;return a.documentShived?a:(l.shivCSS&&!f&&(b=!!h(a,"article,aside,details,figcaption,figure,footer,header,hgroup,nav,section{display:block}audio{display:none}canvas,video{display:inline-block;*display:inline;*zoom:1}[hidden]{display:none}audio[controls]{display:inline-block;*display:inline;*zoom:1}mark{background:#FF0;color:#000}")),g||(b=!j(a)),b&&(a.documentShived=b),a)}function p(a){var b,c=a.getElementsByTagName("*"),d=c.length,e=RegExp("^(?:"+i().join("|")+")$","i"),f=[];while(d--)b=c[d],e.test(b.nodeName)&&f.push(b.applyElement(q(b)));return f}function q(a){var b,c=a.attributes,d=c.length,e=a.ownerDocument.createElement(n+":"+a.nodeName);while(d--)b=c[d],b.specified&&e.setAttribute(b.nodeName,b.nodeValue);return e.style.cssText=a.style.cssText,e}function r(a){var b,c=a.split("{"),d=c.length,e=RegExp("(^|[\\s,>+~])("+i().join("|")+")(?=[[\\s,>+~#.:]|$)","gi"),f="$1"+n+"\\:$2";while(d--)b=c[d]=c[d].split("}"),b[b.length-1]=b[b.length-1].replace(e,f),c[d]=b.join("}");return c.join("{")}function s(a){var b=a.length;while(b--)a[b].removeNode()}function t(a){var b,c,d=a.namespaces,e=a.parentWindow;return!o||a.printShived?a:(typeof d[n]=="undefined"&&d.add(n),e.attachEvent("onbeforeprint",function(){var d,e,f,g=a.styleSheets,i=[],j=g.length,k=Array(j);while(j--)k[j]=g[j];while(f=k.pop())if(!f.disabled&&m.test(f.media)){for(d=f.imports,j=0,e=d.length;j",f="hidden"in c,f&&typeof injectElementWithStyles=="function"&&injectElementWithStyles("#modernizr{}",function(b){b.hidden=!0,f=(a.getComputedStyle?getComputedStyle(b,null):b.currentStyle).display=="none"}),g=c.childNodes.length==1||function(){try{b.createElement("a")}catch(a){return!0}var c=b.createDocumentFragment();return typeof c.cloneNode=="undefined"||typeof c.createDocumentFragment=="undefined"||typeof c.createElement=="undefined"}()})();var l={elements:c.elements||"abbr article aside audio bdi canvas data datalist details figcaption figure footer header hgroup mark meter nav output progress section summary time video",shivCSS:c.shivCSS!==!1,shivMethods:c.shivMethods!==!1,type:"default",shivDocument:k};a.html5=l,k(b);var m=/^$|\b(?:all|print)\b/,n="html5shiv",o=!g&&function(){var c=b.documentElement;return typeof b.namespaces!="undefined"&&typeof b.parentWindow!="undefined"&&typeof c.applyElement!="undefined"&&typeof c.removeNode!="undefined"&&typeof a.attachEvent!="undefined"}();l.type+=" print",l.shivPrint=t,t(b)})(this,document)
--------------------------------------------------------------------------------
/static/script/ie6.min.js:
--------------------------------------------------------------------------------
1 | $(function(){if($.browser.msie&&parseInt($.browser.version,10)===6){$('.row div[class^="span"]:last-child').addClass("last-child");$('[class*="span"]').addClass("margin-left-20");$(':button[class="btn"], :reset[class="btn"], :submit[class="btn"], input[type="button"]').addClass("button-reset");$(":checkbox").addClass("input-checkbox");$('[class^="icon-"], [class*=" icon-"]').addClass("icon-sprite");$(".pagination li:first-child a").addClass("pagination-first-child")}})
--------------------------------------------------------------------------------
/test/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | LazyPHP QUnit Test Center
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
--------------------------------------------------------------------------------
/test/index.php:
--------------------------------------------------------------------------------
1 | assertEqual( $out1 , 'test' );
15 | }
16 |
17 |
18 | function test_info_page()
19 | {
20 | ob_start();
21 | info_page('hello kitty');
22 | $out1 = ob_get_contents();
23 | ob_end_clean();
24 |
25 | $this->assertTrue( strpos( $out1 , '系统消息' ) );
26 | $this->assertTrue( strpos( $out1 , 'hello kitty' ) );
27 | }
28 |
29 | function test_safe_check()
30 | {
31 | if( file_exists( AROOT . 'controller' . DS . 'default.class.php' ) )
32 | $this->assertEqual( 'bad request' , $this->get( SITE_URL . 'controller/default.class.php' ) );
33 |
34 |
35 | if( file_exists( AROOT . 'controller' . DS . 'app.class.php' ) )
36 | $this->assertEqual( 'bad request' , $this->get( SITE_URL . 'controller/app.class.php' ) );
37 |
38 | }
39 |
40 |
41 |
42 | // render
43 |
44 |
45 |
46 |
47 | }
48 |
--------------------------------------------------------------------------------
/test/phptest/fast.test.php:
--------------------------------------------------------------------------------
1 |
2 | class TestOfFastfunction extends UnitTestCase
3 | {
4 |
5 |
6 | public function test_v()
7 | {
8 | // hit
9 | $_REQUEST['name'] = 'oldtimes';
10 | $this->assertEqual( v('name') , 'oldtimes' );
11 |
12 | // not hit
13 | unset($_REQUEST['name']) ;
14 | $this->assertEqual( v('name') , false );
15 |
16 | }
17 |
18 | public function test_z()
19 | {
20 | $tmp = 'news';
21 | $this->assertEqual( z($tmp) , 'news' );
22 | }
23 |
24 | public function test_c()
25 | {
26 | $GLOBALS['config']['unittest'] = 'ing';
27 | $this->assertEqual( c('unittest') , 'ing' );
28 |
29 | unset( $GLOBALS['config']['unittest'] );
30 | $this->assertFalse( c('unittest') );
31 | }
32 |
33 | public function test_g()
34 | {
35 | unset( $GLOBALS['test'] );
36 | $this->assertFalse( g('test') );
37 |
38 | $GLOBALS['test'] = 'im';
39 | $this->assertEqual( g('test') , 'im' );
40 | }
41 |
42 | public function test_u()
43 | {
44 | $this->assertEqual( u('?c=user&a=login') , '%3Fc%3Duser%26a%3Dlogin' );
45 | }
46 |
47 | public function test_text()
48 | {
49 | $this->assertEqual( _('login') , '登入' );
50 | $this->assertEqual( _('hello%s' , 'Aoi') , '你好Aoi' );
51 | $this->assertEqual( _('Not exists' ) , 'Not exists' );
52 | $this->assertEqual( _('Not exists %s' , 'Money' ) , 'Not exists Money' );
53 |
54 | }
55 |
56 | // render
57 | // ajax_echo
58 | // info_page
59 |
60 |
61 | }
62 |
--------------------------------------------------------------------------------
/test/phptest/sae.test.php:
--------------------------------------------------------------------------------
1 |
2 |
3 | if( defined('SAE_APPNAME') )
4 | {
5 | class TestOfSAEfunction extends UnitTestCase
6 | {
7 |
8 | // replication
9 | function test_sae_db()
10 | {
11 | $db = db();
12 | $data= reset(get_data( "show global variables like 'read_only';" , $db ));
13 | $this->assertEqual( $data['Value'] , 'OFF' );
14 |
15 | $dbr = db_read();
16 | $data2= reset(get_data( "show global variables like 'read_only';" , $dbr ));
17 | $this->assertEqual( $data2['Value'] , 'ON' );
18 |
19 | // auto
20 | $data3= reset(get_data( "show global variables like 'read_only';" ));
21 | $this->assertEqual( $data2['Value'] , 'ON' );
22 |
23 | }
24 |
25 |
26 |
27 |
28 | }
29 | }
30 |
31 |
32 |
33 |
--------------------------------------------------------------------------------
/view/layout/ajax/default.tpl.html:
--------------------------------------------------------------------------------
1 |
2 |

3 |
8 |
--------------------------------------------------------------------------------
/view/layout/ajax/default/test.tpl.html:
--------------------------------------------------------------------------------
1 | =$info?>
--------------------------------------------------------------------------------
/view/layout/ajax/info.tpl.html:
--------------------------------------------------------------------------------
1 |
2 |

3 | =$info;?>
4 |
--------------------------------------------------------------------------------
/view/layout/mobile/default.tpl.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | =$top_title?>
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
19 |
20 |
21 |
--------------------------------------------------------------------------------
/view/layout/mobile/default/index.tpl.html:
--------------------------------------------------------------------------------
1 | mobile version of LP3. Modify AROOT/view/layout/mobile/default/index.tpl.html to change this.
--------------------------------------------------------------------------------
/view/layout/mobile/default/mobile.tpl.html:
--------------------------------------------------------------------------------
1 | 这是一个for Mobile设备的页面,加载了JQ.Mobi
--------------------------------------------------------------------------------
/view/layout/rest/default.tpl.html:
--------------------------------------------------------------------------------
1 |
17 |
--------------------------------------------------------------------------------
/view/layout/web/default.tpl.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | =$top_title . ' | ' . c('site_name') ?>
6 |
7 |
8 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
30 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
45 |
46 |
47 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
--------------------------------------------------------------------------------
/view/layout/web/footer.tpl.html:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/view/layout/web/header.tpl.html:
--------------------------------------------------------------------------------
1 |
20 |
--------------------------------------------------------------------------------
/view/layout/web/info.tpl.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | =$top_title . ' | ' . c('site_name') ?>
6 |
7 |
8 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
29 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
=$title?>
39 |
=$info?>
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
--------------------------------------------------------------------------------
/view/layout/web/main/default/index.tpl.html:
--------------------------------------------------------------------------------
1 |
2 |
TRY LazyPHP3 !
3 |
4 |
LazyPHP是一个轻框架.
5 |
6 | 之所以开发这么一个框架,是因为其他框架给的太多。在高压力的情况下,ORM和盘根错节的对象树反而将简单的页面请求处理复杂化,在调试和性能上带来反面效果。
7 |
8 |
9 | LP采用函数式接口封装对象,对内通过面向对象实现代码重用,对外则提供简明扼要的操作函数。开发者甚至不用理解面向对象就能很好的使用,这让一些初级程序员很容易就开发出强壮的应用。
10 |
11 |
帮助文档 »
12 |
13 |
41 |
42 |
43 |
--------------------------------------------------------------------------------
/view/layout/web/main/default/test.tpl.html:
--------------------------------------------------------------------------------
1 | 测试页面
--------------------------------------------------------------------------------
/view/layout/web/side/default/index.tpl.html:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------