PageRenderTime 54ms CodeModel.GetById 23ms RepoModel.GetById 0ms app.codeStats 1ms

/lib/sm.php

https://github.com/xurenlu/supermini
PHP | 1055 lines | 962 code | 3 blank | 90 comment | 41 complexity | 43e9ca2f0bdda405c829a6b09628d98d MD5 | raw file
  1. <?php
  2. /**
  3. *@file sm.php 主框架内容;
  4. * vim: set fdm=marker:
  5. *@author xurenlu <helloasp@hotmail.com>
  6. *@version 1.2.0
  7. *\b License: \b MIT <http://en.wikipedia.org/wiki/MIT_License>
  8. <pre>
  9. *@last_modified 2012-03-27 01:44:37
  10. \b Homepage: http://www.162cm.com/
  11. \b Slide: http://codeany.com/slides.10.play.miniphpkuangjiasuperminijianjie.shtml
  12. </pre>
  13. \b 使用之前要理解并同意的几个关键点
  14. 1.Mysql已经相当好用了,所以,这个框架只支持用mysql做数据库。没有设计一大堆的DBDriver;
  15. 2.做cache,Memcache足够好用了,因此,内置的一些cache支持是基于memcache的;
  16. 3.只用最好的,最必需的,精简精简再精简~
  17. </pre>
  18. */
  19. /** smPhpEvent 一些跟事件触发相关的全局函数. */
  20. global $SM_PE_EVENTS,$SM_PE_FILTERS,$sm_config,$sm_temp,$sm_data;
  21. $SM_PE_FILTERS=array();
  22. $SM_PE_EVENTS=array();
  23. /**
  24. * 执行某一事件.
  25. * @param $event String 事件的名称
  26. * @param $args MISC 要传递给事件的参数;
  27. */
  28. function smDoEvent($event,$args=null){
  29. global $SM_PE_EVENTS;
  30. if(is_array($SM_PE_EVENTS[$event]))
  31. foreach($SM_PE_EVENTS[$event] as $handle)
  32. {
  33. if(function_exists($handle))
  34. $handle($args);
  35. }
  36. }
  37. /**
  38. * 加入一个事件处理器
  39. *@name smAddEvent
  40. *@param $event string "event name"
  41. *@param $handle string "event handle" must be an exists function name
  42. *@return nothing
  43. */
  44. function smAddEvent($event,$handle){
  45. global $SM_PE_EVENTS;
  46. $SM_PE_EVENTS[$event][]=$handle;
  47. }
  48. /**
  49. * 给数据加一个过滤器.
  50. *@name smAddFilter
  51. *@param $dataName string 数据名
  52. *@param $filterName string 过滤器名
  53. *@return nothing
  54. */
  55. function smAddFilter($dataName,$filterName){
  56. global $SM_PE_FILTERS;
  57. $SM_PE_FILTERS[$dataName][]=$filterName;
  58. }
  59. /**
  60. * 给数据应用过滤器.
  61. *@name smApplyEvent
  62. *@param $data string 数据
  63. *@param $dataName string 数据名
  64. *@return nothing
  65. */
  66. function smApplyEvent(&$data,$dataName) {
  67. global $SM_PE_FILTERS;
  68. if(is_array($SM_PE_FILTERS[$dataName]))
  69. foreach($SM_PE_FILTERS[$dataName] as $filter)
  70. {
  71. if(function_exists($filter))
  72. $filter( $data);
  73. }
  74. }
  75. /** generate URL by $_GET arguments */
  76. function sm_url($args,$string=""){
  77. global $sm_temp;
  78. if(!$sm_temp["use_shorturl"]){
  79. if(!$args["controller"])
  80. $args["controller"]=$sm_temp["controller"];
  81. if(!$args["action"])
  82. $args["action"]=$sm_temp["action"];
  83. $arr=array();
  84. foreach($args as $key=>$val){
  85. if(!sm_test_urlencode($val)){
  86. $val=urlencode($val);
  87. }
  88. $arr[]=$key."=".$val;
  89. }
  90. $pagestr="?".join("&",$arr);
  91. return $pagestr;
  92. }
  93. if(!isset($args["controller"]))
  94. $args["controller"]=$sm_temp["controller"];
  95. if(!isset($args["action"]))
  96. $args["action"]=$sm_temp["action"];
  97. $keys=array_keys($args);
  98. sort($keys);
  99. foreach($sm_temp["compiled_url_routes"] as $k=>$v){
  100. sort($v["fields"]);
  101. if($keys==$v["fields"]){
  102. $pattern=$v["pat"];
  103. break;
  104. }
  105. }
  106. if(!isset($pattern)){
  107. $controller = $args["controller"];
  108. $action = $args["action"];
  109. unset($args["controller"]);
  110. unset($args["action"]);
  111. foreach($args as $key=>$val){
  112. if(!sm_test_urlencode($val)){
  113. $val=urlencode($val);
  114. }
  115. $arr[]=$key."=".$val;
  116. }
  117. $string =sm_url(array("controller"=>$controller,"action"=>$action))."?".join("&",$arr);
  118. return $string;
  119. }
  120. else{
  121. $string = $pattern;
  122. foreach($args as $k=>$v){
  123. $string=str_replace("{".$k."}",$v,$string);
  124. }
  125. $string=sm_urlmap($string,2);
  126. $left2=substr($string,0,2);
  127. if($left2=="//")
  128. $string = substr($string ,1);
  129. return $string;
  130. }
  131. }
  132. /** sm_test_urlencode * 探测一个变量是否已经被urlencode过了。 */
  133. function sm_test_urlencode($var){
  134. return (urldecode($var)==$var)?false:true;
  135. }
  136. /** sm_pagenav_default 分页函数 ,
  137. *
  138. * @param int $total 总记录个数
  139. * @param int $pagesize 每页记录数
  140. * @param string $pagestr 其他分页的链接模板
  141. * @param array $get 一般情况下就是GET数组
  142. * @param string $page_var_name 一般是page
  143. * @param int $l 当前页链接的左边保留多少个链接
  144. * @param int $r 当前页链接的右边保留多少个链接
  145. *
  146. * @code
  147. * echo sm_pagenav_default(18332,20);
  148. * echo sm_pagenav_default(18244,25,"index.php?page={page}",array("key"=>1),"page",3,3);
  149. * echo sm_pagenav_default(18244,25,null,array("key"=>1),"page",3,3);
  150. * @endcode
  151. */
  152. function sm_pagenav_default($total,$pagesize=null,$pagestr=null,$get_args=null,$page_var_name="page",$l=4,$r=4){
  153. global $sm_temp;
  154. $url_pattern=$sm_temp["url_pattern"];
  155. if(is_null($pagestr)){
  156. $arr=array();
  157. if(is_null($get_args))
  158. $get_args=$_GET;
  159. while(list($key,$val)=each($get_args)){
  160. if(!sm_test_urlencode($val))
  161. $val=urlencode($val);
  162. if(strtolower($key)!=$page_var_name)
  163. $arr[]=$key."=".$val;
  164. }
  165. $arr[]=$page_var_name."={page}";
  166. $pagestr="?".join("&",$arr);
  167. }
  168. $get_args[$page_var_name]="{page}";
  169. unset($get_args["use_layout"]);
  170. if(is_null($pagesize)){
  171. global $sm_config;
  172. $pagesize=$sm_config["pagesize"]>0?$sm_config["pagesize"]:20;
  173. }
  174. $pagecount=$total/$pagesize;
  175. if(floor($pagecount)<$pagecount)
  176. $pagecount= floor($pagecount)+1;
  177. if(! ($_GET[$page_var_name]>0)){
  178. $_GET[$page_var_name]=1;
  179. $pagenow=1;
  180. }
  181. else
  182. $pagenow=$_GET[$page_var_name];
  183. $sn="page_".rand(1000,9999);
  184. if ($pagenow>1){
  185. $get_args[$page_var_name]=1;
  186. $str=$str."<a href='".sm_url($get_args)."' class='prev'><span class='pagenum'>首页</span></a>";
  187. $get_args[$page_var_name]=$pagenow-1;
  188. $str =$str."<a href='".sm_url($get_args)."' class='prev'><span class='pagenum'> 上一页</span></a>";
  189. }else{
  190. $str=$str."<a class='prev' title='已经是第一页了'><span class='pagenum'>首页</span></a>";
  191. $str =$str."<a class='prev' title='已经是第一页了'><span class='pagenum'> 上一页</span></a>";
  192. }
  193. $startpage=$pagenow-$l;
  194. $endpage=$pagenow+$r;
  195. if($startpage<1) $startpage=1;
  196. if($endpage>=$pagecount) $endpage=$pagecount;
  197. for($jj=$startpage;$jj<=$endpage;$jj++){
  198. if($jj==$pagenow)
  199. $str=$str."<a class='on' href=".sm_url($get_args)."><span class='current pagenum'>".$jj."</span></a>";
  200. else{
  201. $get_args[$page_var_name]=$jj;
  202. $str=$str."<a href='".sm_url($get_args)."'><span>".$jj."</span></a>";
  203. }
  204. }
  205. if($pagenow<$pagecount){
  206. $get_args[$page_var_name]=$pagenow+1;
  207. $str=$str."<a href='".sm_url($get_args)."' class='next'><span class=''>下一页</span></a>";
  208. $get_args[$page_var_name]=$pagecount;
  209. $str=$str."<a href='".sm_url($get_args)."' class='next'><span class=''>尾页</span></a>";
  210. }else{
  211. $str=$str."<a class='next' title='已经是最后一页了'><span class=''>下一页</span></a>";
  212. $str=$str."<a class='next' title='已经是最后一页了'><span class=''>尾页</span></a>";
  213. }
  214. return $str;
  215. }
  216. /** static class smSql 帮助构造SQL语句的小工具类; */
  217. class smSql{
  218. var $pagesize=20;
  219. static function escape_string($v){
  220. return mysql_escape_string($v);
  221. }
  222. /** update 构造更新SQL
  223. *@param $table string 要更新的数据表名
  224. *@param $array array要更新的数据
  225. *@param $condition string更新条件
  226. *@param $limit integer 更新的条数;
  227. */
  228. static function update($table, $array, $condition,$limit=1){
  229. if(is_array($array)){
  230. $sql = "UPDATE `".$table."` SET ";
  231. $comma = "";
  232. foreach ($array AS $_key => $_val){
  233. $sql .= $comma."`".$_key."` = '".self::escape_string($_val)."'";
  234. $comma = ", ";
  235. }
  236. if ($condition){
  237. $sql .= " WHERE ".$condition;
  238. }
  239. $sql .= " LIMIT $limit";
  240. return $sql;
  241. }
  242. else{
  243. return false;
  244. }
  245. }
  246. /** select 构造查询SQL
  247. *
  248. * @param $table string表名字
  249. * @param $columns string 要查找的列,默认是"*"
  250. * @param $conditions string ,默认是null,请给出sql语句 where子句where后面的部分
  251. * @param $order string
  252. * @param $limit string
  253. * @param $group string
  254. */
  255. static function select($table,$columns="*",$conditions=null,$order=null,$limit=null,$group=null,$join=null,$on=null){
  256. if($columns===NULL)
  257. $columns="*";
  258. if(is_array($columns))
  259. $cols=join(",",$columns);
  260. else
  261. $cols=$columns;
  262. $sql=" SELECT ".$columns." FROM ".$table;
  263. if(!is_null($join)){
  264. $sql.=" $join ";
  265. }
  266. if(!is_null($on)){
  267. $sql.="on $on";
  268. }
  269. if(!is_null($conditions))
  270. $sql.=" WHERE ".$conditions;
  271. if(!is_null($group))
  272. $sql.=" GROUP BY ".$group;
  273. if(!is_null($order))
  274. $sql.=" ORDER BY ".$order;
  275. if(!is_null($limit))
  276. $sql.=" LIMIT ".$limit;
  277. return $sql;
  278. }
  279. /*** count 构造count类语句,注意构造出的是count(*) as c ;*/
  280. static function count($table,$conditions=null,$order=null,$limit=null,$group=null,$join=null,$on){
  281. return self::SELECT($table,"count(*) as c",$conditions,$order,$limit,$group,$join,$on);
  282. }
  283. /** insert 得到插入语句的SQL
  284. *@param $table string 数据表名字
  285. *@param $array array 要插入的一行数据
  286. *@param $type 要么是INSERT要么是REPLACE,这决定生成的sql语句是insert into 还是replace into
  287. **/
  288. static function insert($table,$array,$type="INSERT"){
  289. if (is_array($array)){
  290. $comma = $key = $value = "";
  291. foreach ($array AS $_key => $_val){
  292. $key .= $comma."`".$_key."` ";
  293. $value .= $comma."'".self::escape_string($_val)."'";
  294. $comma = ", ";
  295. }
  296. $sql = "$type INTO ".$table. "(".$key.") VALUES (".$value.")";
  297. return $sql;
  298. }
  299. }
  300. /** delete 得到删除语句的SQL
  301. * @param $table string 数据表名字
  302. * @param $condition string 条件
  303. * @param $limit string limit字段
  304. */
  305. static function delete($table,$condition,$limit="1"){
  306. $sql="DELETE FROM `".mysql_escape_string($table)."` WHERE ".$condition." LIMIT ".$limit;
  307. return $sql;
  308. }
  309. }
  310. /*** _sm_mysql 连接Mysql的实际函数 */
  311. function _sm_mysql($id){
  312. global $sm_config;
  313. if(!is_array($sm_config["mysql"][$id])){
  314. throw new smException("MYSQL configuration 'sm_config[\"mysql\"][$id]' not exists");
  315. }
  316. $config=$sm_config["mysql"][$id];
  317. $conn=mysql_connect($config["host"],$config["user"],$config["password"],1);
  318. $switch=mysql_select_db($config["database"],$conn);
  319. smDoEvent("select_db",$conn);
  320. if(!is_resource($conn) || !$switch){
  321. throw new smException("Mysql error:Can't connect to hosts with : -h ".$config["host"]." -u ".$config["user"]." -p ".substr($config["password"],0,2)."*** ".$config["database"]);
  322. }
  323. if(!empty($sm_config["prepare_sql"])) sm_query($sm_config["prepare_sql"]."",$conn);
  324. return $conn;
  325. }
  326. /*** sm_dbo 返回一个连接对象
  327. * @param integer $id 在sm_config里的mysql相关配置索引;*/
  328. function sm_dbo($id=0){
  329. global $sm_config,$sm_temp;
  330. return $sm_temp["connections"][$id]=is_resource($sm_temp["connections"][$id])?$sm_temp["connections"][$id]:_sm_mysql($id);
  331. }
  332. /***
  333. * sm_query 执行一条sql查询并返回结果
  334. * @modified at :2012.3.26 23:32
  335. * @doc 从现在起,必须明确指定第二个参数(mysql连接资源).
  336. */
  337. function sm_query($sql,$conn){
  338. global $sm_config,$sm_temp;
  339. if($sm_config["sql_debug"]){
  340. $sm_temp["sqls"][]=$sql;
  341. }
  342. if($sm_config["sql_debug"]){
  343. error_log($sql);
  344. }
  345. smDoEvent("before_query",$sql);
  346. $ret = mysql_query($sql,$conn);
  347. if(!$ret){
  348. if(is_null($conn)){
  349. smDoEvent("query_fail",array("sql"=>$sql,"error_no"=>mysql_error()));
  350. throw new smException("mysql error:sql:$sql,error descrption:".mysql_errno().":".str_replace("\n","",mysql_error()));
  351. }
  352. else{
  353. smDoEvent("query_fail",array("sql"=>$sql,"error_no"=>mysql_error($conn)));
  354. throw new smException("mysql error:sql:$sql,error descrption:".mysql_errno($conn).":".str_replace("\n","",mysql_error($conn)));
  355. }
  356. }else{
  357. smDoEvent("query_succeed",array("sql"=>$sql,"resource"=>$ret));
  358. }
  359. smDoEvent("after_query",$sql);
  360. return $ret;
  361. }
  362. /** sm_fetch_row 取出sql查询的一条结果
  363. * @modified at 2012.3.26 23:33
  364. * @doc 从现在起,必须明确地传入第二个参数(mysql链接)
  365. */
  366. function sm_fetch_row($sql,$conn){
  367. global $sm_config,$sm_temp;
  368. $rs=sm_query($sql,$conn);
  369. $sm_temp["last_rs"]=$rs;
  370. return empty($rs)? null:mysql_fetch_assoc($rs);
  371. }
  372. /*
  373. * sm_fetch_rows 取出sql查询的多条结果
  374. * @modified at 2012.3.26 23:34
  375. * @doc 从现在起,必须明确地传入第二个参数(mysql链接)
  376. */
  377. function sm_fetch_rows($sql,$conn,$type=MYSQL_ASSOC){
  378. global $sm_config,$sm_temp;
  379. $rs=sm_query($sql,$conn);
  380. $sm_temp["last_rs"]=$rs;
  381. if(!empty($rs)){
  382. $rows=array();
  383. while($row=mysql_fetch_array($rs,$type)){
  384. $rows[]=$row;
  385. }
  386. return $rows;
  387. }
  388. }
  389. function sm_free_result(){
  390. global $sm_config,$sm_temp;
  391. if($sm_temp["rs"])
  392. mysql_free_result($sm_temp["rs"]);
  393. }
  394. /** smObject class
  395. * 实现一个比较灵活的功能,调用它的属性时,会自动地创建数据库,创建缓存对象等.
  396. **/
  397. class smObject {
  398. /** 数据表的默认主键 */
  399. public $default_primary_key = "id";
  400. /** 存放回调钩子 */
  401. public $callbacks=array();
  402. /** 设置对某个属性调用时触发的钩子 */
  403. public function set_callback($name,$callback){
  404. $this->callbacks[$name]=$callback;
  405. }
  406. /*** __get
  407. * the main magic method
  408. */
  409. public function __get($name){
  410. global $sm_config,$sm_temp,$sm_data;
  411. if(!empty($sm_config[$name]))
  412. return $sm_config[$name];
  413. if(!empty($sm_temp[$name]))
  414. return $sm_temp[$name];
  415. if(!empty($sm_data[$name]))
  416. return $sm_data[$name];
  417. if($this->callbacks[$name]){
  418. $sm_temp[$name]=$this->callbacks[$name]();
  419. return $sm_temp[$name];
  420. }
  421. if($name=="db"){
  422. $sm_temp[$name]=new smDB();
  423. $sm_temp[$name]->prepare_dbo();
  424. return $sm_temp[$name];
  425. }
  426. if($name=="form"){
  427. $sm_temp[$name]=new smForm();
  428. return $sm_temp[$name];
  429. }
  430. if(preg_match("/^get_(.*)+$/",$name)){
  431. $id = substr($name,4,strlen($name));
  432. $sm_temp["get_".$id]=$_GET[$id];
  433. return $sm_temp["get_$id"];
  434. }
  435. if(preg_match("/^env_(.*)+$/",$name)){
  436. $id = substr($name,4,strlen($name));
  437. $sm_temp["env_".$id]=$_SERVER[$id];
  438. return $sm_temp["env_$id"];
  439. }
  440. if(preg_match("/^post_(.*)+$/",$name)){
  441. $id = substr($name,5,strlen($name));
  442. $sm_temp["post_".$id]=$_POST[$id];
  443. return $sm_temp["post_$id"];
  444. }
  445. if(preg_match("/^db_(.*)+$/",$name)){
  446. $id = substr($name,3,strlen($name));
  447. $link = sm_dbo($id);
  448. $dbObject = new smDB();
  449. $dbObject->rconn($link);
  450. $dbObject->wconn($link);
  451. $dbObject->prepare_dbo();
  452. $sm_temp["db_".$id]=$dbObject;
  453. return $sm_temp["db_$id"];
  454. }
  455. if(preg_match("/^cache_(.*)$/",$name)){
  456. $cache_group = substr($name,6,strlen($name));
  457. $cache = new smCache($cache_group);
  458. $sm_temp[$name]=$cache;
  459. return $cache;
  460. }
  461. }
  462. /**
  463. * 1. close mysql links;
  464. * */
  465. function __destruct(){
  466. global $sm_temp;
  467. if($sm_temp["connections"])
  468. foreach($sm_temp["connections"] as $conn){
  469. mysql_close($conn);
  470. }
  471. }
  472. }
  473. /** class smException ,就是一个空类,继承了exception */
  474. class smException extends Exception{}
  475. /** Chainable 是一个比较特别的类,是基本上所有的方法返回的都是对象自己本身;
  476. * 主要是使用就是设置一个属性;
  477. * 调用法是:$smChainable->attribute_name(attribute_value);
  478. **/
  479. class smChainable {
  480. var $attrs=array();
  481. function set($name,$value){
  482. $this->attrs[$name]=$value;
  483. return $this;
  484. }
  485. function __call($name,$args){
  486. //smDoEvent("before_magic_call",array("method"=>"$name","args"=>$args,"class"=>get_class($this),"object"=>$this));
  487. $this->set($name,$args[0]);
  488. return $this;
  489. }
  490. /** 删除所有附加的属性;*/
  491. function reset(){
  492. $this->attrs=array();
  493. }
  494. }
  495. /** class smCache 调用memcache 取缓存;*/
  496. class smCache {
  497. private $_servers;
  498. private $_memcache;
  499. public $attrs=array("expire"=>7200,"flag"=>0);
  500. /*** __construct */
  501. function __construct($group_id){
  502. global $sm_config;
  503. if(defined("SAE_MYSQL_USER")){
  504. $mem=memcache_init();
  505. }else{
  506. $mem=new memcache();
  507. foreach($sm_config["memcache"][$group_id] as $server){
  508. $mem->addServer($server["host"],$server["port"]);
  509. }
  510. }
  511. $this->_memcache=$mem;
  512. }
  513. /** * get 读缓存值 */
  514. function get($key){
  515. return $this->_memcache->get($key);
  516. }
  517. /*** set 设置缓存值;*/
  518. function set($key,$val,$expire=7200){
  519. return $this->_memcache->set($key,$val,$this->attrs["flag"],$this->attrs["expire"]);
  520. }
  521. /** 删除memcache key */
  522. function delete($key){
  523. return $this->_memcache->delete($key);
  524. }
  525. function __destruct(){
  526. $this->_memcache->close();
  527. }
  528. }
  529. /**
  530. * smDB 是数据操作类
  531. */
  532. class smDB extends smChainable {
  533. public $_rconn=null;
  534. public $_wconn=null;
  535. protected $_pagesize=null;
  536. protected $_page_var = "page";
  537. var $_extra_args = null;
  538. var $_pagestr = null;
  539. /**
  540. * 重置属性(主要是重置查询条件)
  541. * */
  542. function reset(){
  543. $this->attrs= array("where"=>null,"group"=>null,"order"=>null,"limit"=>null,"select"=>null);
  544. return 1;
  545. }
  546. /**
  547. * 预备数据库连接;
  548. * */
  549. function prepare_dbo(){
  550. if(!$this->_rconn){
  551. if($this->attrs["rconn"])
  552. $this->_rconn=$this->attrs["rconn"];
  553. else
  554. $this->_rconn=sm_dbo(1);
  555. }
  556. if(!$this->_wconn){
  557. if($this->attrs["wconn"])
  558. $this->_wconn=$this->attrs["wconn"];
  559. else
  560. $this->_wconn=sm_dbo(0);
  561. }
  562. return $this;
  563. }
  564. function __construct(){
  565. global $sm_config;
  566. $this->_pagesize=($sm_config["pagesize"]>0)?$sm_config["pagesize"]:20;
  567. $this->reset();
  568. }
  569. /** 返回符合条件的若干行 */
  570. function rows($clear=true){
  571. global $sm;
  572. if($this->attrs["cache_key"]&&($tmp=$sm->cache_group_1->get($this->attrs["cache_key"]))){
  573. if(!empty($tmp))
  574. return $tmp;
  575. }
  576. $sql=smSql::select($this->attrs["table"],$this->attrs["select"],$this->attrs["where"],$this->attrs["order_by"],$this->attrs["limit"],$this->attrs["group_by"],$this->attrs["join"],$this->attrs["on"]);
  577. $rows=sm_fetch_rows($sql,$this->_rconn);
  578. if($this->attrs["cache_key"])
  579. $sm->cache_group_1->set($this->attrs["cache_key"],$rows);
  580. if($clear)
  581. $this->reset();
  582. return $rows;
  583. }
  584. /** 查询一条记录 **/
  585. function row($clear=true){
  586. global $sm;
  587. if($this->attrs["cache_key"]&&($tmp=$sm->cache_group_1->get($this->attrs["cache_key"]))){
  588. if(!empty($tmp))
  589. return $tmp;
  590. }
  591. $sql=smSql::select($this->attrs["table"],$this->attrs["select"],$this->attrs["where"],$this->attrs["order_by"],$this->attrs["limit"],$this->attrs["group_by"],$this->attrs["join"],$this->attrs["on"]);
  592. $row=sm_fetch_row($sql,$this->_rconn);
  593. if($this->attrs["cache_key"])
  594. $sm->cache_group_1->set($this->attrs["cache_key"],$row);
  595. if($clear)
  596. $this->reset();
  597. return $row;
  598. }
  599. /** 查询出一页的数据,并自动处理分页 */
  600. function page($clear=true){
  601. if(!($_GET[$this->_page_var]>0))
  602. $pagenow=1;
  603. else
  604. $pagenow=$_GET[$this->_page_var];
  605. $limit=($pagenow-1)*$this->_pagesize.",".$this->_pagesize;
  606. $this->limit($limit);
  607. $rows=$this->rows(false);
  608. $total=$this->count(false);
  609. $pagestr = sm_pagenav_default($total,$this->_pagesize,$this->_pagestr,$this->_extra_args,$this->_page_var,3,3);
  610. $this->reset();
  611. return array("total"=>$total,"entries"=>$rows,"page"=>$pagestr);
  612. }
  613. /** 查询符合条件的记录的行数 */
  614. function count($clear=true){
  615. $sql=smSql::select($this->attrs["table"],"count(*) as c",$this->attrs["where"],$this->attrs["order_by"],"1",$this->attrs["group_by"],$this->attrs["join"],$this->attrs["on"]);
  616. $row=sm_fetch_row($sql,$this->_rconn);
  617. if($clear)
  618. $this->reset();
  619. return $row["c"];
  620. }
  621. /** get last inserted id */
  622. function insert_id(){
  623. return mysql_insert_id($this->_wconn);
  624. }
  625. /** 取得受影响的行数 */
  626. function affected_rows(){
  627. return mysql_affected_rows($this->_wconn);
  628. }
  629. /*** update_by 根据条件更新数据;*/
  630. function update($clear=true){
  631. if(!$this->attrs["limit"])
  632. $this->set("limit",1);
  633. $sql=smSql::update($this->attrs["table"],$this->attrs["values"],$this->attrs["where"],$this->attrs["limit"]);
  634. if($clear)
  635. $this->reset();
  636. return sm_query($sql,$this->_wconn);
  637. }
  638. /** 删除符合条件的记录 */
  639. function delete($clear=true){
  640. if(!$this->attrs["limit"])
  641. $this->set("limit",1);
  642. $sql=smSql::delete($this->attrs["table"],$this->attrs["where"],$this->attrs["limit"]);
  643. if($clear)
  644. $this->reset();
  645. return sm_query($sql,$this->_wconn);
  646. }
  647. /** smDB::delete 的别名 */
  648. function remove($clear=true){
  649. return $this->delete($clear);
  650. }
  651. /** 插入一条记录 */
  652. function insert($type="INSERT",$clear=true){
  653. $sql=smSql::insert($this->attrs["table"],$this->attrs["values"],$type);
  654. if($clear)
  655. $this->reset();
  656. return sm_query($sql,$this->_wconn);
  657. }
  658. /** smDB::Create的别名 */
  659. function create($type="INSERT",$clear=true){
  660. return $this->insert($type,$clear);
  661. }
  662. /** 直接执行一条sql语句 */
  663. function query($sql){
  664. return sm_query($sql,$this->_wconn);
  665. }
  666. }
  667. /**
  668. * @brief smApplication Mvc 功能主要在这里实现
  669. *
  670. * 这里只实现特别简单的MVC功能,一般建议用户将app目录设置为./app/,controller文件就旅行团在app/***.php里,
  671. * 而views层的文件则放在./app/views/{controller}/{action}.php里。
  672. */
  673. class smApplication{
  674. public $_app="smapplication";
  675. public $_name="smapplication";
  676. public $_last_action="index";
  677. public $before_filters=array();
  678. public $after_filters=array();
  679. function __construct($name="smapplication"){
  680. global $sm_config;
  681. $this->_name=$name;
  682. if(!class_exists($name)){
  683. include_once($sm_config["app_root"]."/app/".strtolower($name).".php");
  684. $this->_app = new $name($name);
  685. }else{
  686. $this->_app=$this;
  687. }
  688. }
  689. /*** _before_filter */
  690. function _before_filter($action){
  691. $var_name = "before_filters_$action";
  692. foreach($this->$var_name as $method){
  693. $this->$method();
  694. }
  695. foreach($this->before_filters as $method){
  696. $this->$method();
  697. }
  698. }
  699. /*** _after_filter */
  700. function _after_filter($action){
  701. $var_name = "after_filters_$action";
  702. foreach($this->$var_name as $method){
  703. $this->$method();
  704. }
  705. foreach($this->after_filters as $method){
  706. $this->$method();
  707. }
  708. }
  709. /*** method_miss */
  710. private function _method_missing($method) {
  711. throw new smException("method missing:".$this->_name."->".$method);
  712. }
  713. /*** v include the view files;*/
  714. function v($action=null,$template_type="php"){
  715. global $sm_config,$sm_temp;
  716. $sm_temp["template_type"]=$template_type;
  717. if(is_null($action))
  718. $action=$this->_last_action;
  719. else
  720. $this->_last_action=$action;
  721. $mod=$this->_name;
  722. unset($_GET["use_layout"]);
  723. if($sm_config["use_layout"]){
  724. //如果使用布局并且布局文件存在...
  725. if (is_file($sm_config["app_root"] . "/app/layouts/$mod.php"))
  726. return include $sm_config["app_root"] . "/app/layouts/$mod.php";
  727. elseif (is_file($sm_config["app_root"] . "/app/layouts/application.php"))
  728. return include $sm_config["app_root"] . "/app/layouts/application.php";
  729. elseif (is_file($sm_config["app_root"] . "/app/views/$mod/$action.php"))
  730. return include $sm_config["app_root"] . "/app/views/$mod/$action.php";
  731. else
  732. return '';
  733. }
  734. else{
  735. return include($sm_config["app_root"]."/app/views/$mod/$action.php");
  736. }
  737. }
  738. /*** dispatch run the filters and real action method;*/
  739. public function dispatch($action){
  740. global $sm_config;
  741. $this->_last_action =$this->_app->_last_action= $action;
  742. $methods=get_class_methods($this->_app);
  743. if(
  744. (in_array($action,$methods) && ($method=$action)) ||
  745. ( in_array("action_".$action,$methods) &&($method="action_".$action))){
  746. $this->_app->_before_filter($action);
  747. $this->_app->$method();
  748. $this->_app->_after_filter($action);
  749. return true;
  750. }
  751. $this->_app->_method_missing($action); // 调用method_missing方法;
  752. return false;
  753. }
  754. function redirect($args,$action=null,$controller=null){
  755. if($action === NULL) $action=$this->_last_action;
  756. if($controller === NULL) $controller = $_GET["controller"];
  757. if(!$args["action"])
  758. $args["action"]=$action;
  759. if(!$args["controller"])
  760. $args["controller"]=$controller;
  761. header("Location:".sm_url($args));
  762. exit();
  763. }
  764. public function yield(){
  765. global $sm_config,$sm_temp;
  766. if($sm_temp["template_type"]=="html")
  767. return include sm_template($sm_config["app_root"]."/app/views/".$this->_name."/".$this->_last_action.".html");
  768. else
  769. return include($sm_config["app_root"]."/app/views/".$this->_name."/".$this->_last_action.".php");
  770. }
  771. /*** __get magic method;*/
  772. public function __get($var){
  773. return array();
  774. }
  775. }
  776. /** class Form ,旨在减化生成表单的一些操作;**/
  777. class smForm extends smChainable{
  778. private $_form_values=array();
  779. private $_form_name="";
  780. function reset(){
  781. $this->attrs=array();
  782. return true;
  783. }
  784. function html($tag,$inner=""){
  785. $str="<$tag ";
  786. foreach($this->attrs as $k=>$v){
  787. if($v!==NULL)
  788. $str .= "$k=\"".htmlspecialchars($v)."\" ";
  789. }
  790. $this->reset();
  791. if(in_array($tag,array( "input","button","img","link")))
  792. $html=$str."/>";
  793. else
  794. $html=$str.">".$inner."</$tag>";
  795. $this->reset();
  796. return $html;
  797. }
  798. /** 设定form表单的名称和初始值;
  799. *
  800. * @param $name String 一般设置为表的名字;
  801. * @param $values Array 各个域的值;
  802. **/
  803. function __construct($name="",$values=null){
  804. $this->form($name,$values);
  805. }
  806. function form($name,$values=null){
  807. $this->_form_name=$name;
  808. $this->_form_values=$values;
  809. return $this;
  810. }
  811. /** Form表单的<form action=** method="***">部分
  812. *
  813. * @param $action String,Form表单的提交地址。
  814. * @param $html_attrs Array,Form表单附加的其他属性;
  815. */
  816. function openform($action,$html_attrs=array("method"=>"POST"),$upload=false){
  817. if($upload){
  818. $html_attrs["enctype"]="multipart/form-data";
  819. }
  820. $str="<form action='$action' ";
  821. foreach($html_attrs as $k=>$v){
  822. $str.=" $k='".$v."' ";
  823. }
  824. $str.= ">";
  825. return $str;
  826. }
  827. function closeform(){
  828. return "</form>";
  829. }
  830. function caption($field_name,$caption=null){
  831. if($caption===NULL)
  832. $caption=$field_name.":";
  833. $this->set("for", $this->_form_name."_".$field_name);
  834. $html=$this->build("label","$field_name",$caption);
  835. $this->reset();
  836. return $html;
  837. }
  838. /** 输出一个textarea 标记;
  839. *
  840. * @param $field_name String 域名字;
  841. */
  842. function textarea($field_name){
  843. $value=$this->_get_value($field_name,$this->attrs);
  844. $html= $this->_left("textarea",$field_name,$this->attrs);
  845. $html.=">".htmlspecialchars($value)."</textarea>";
  846. $this->reset();
  847. return $html;
  848. }
  849. /** 输出一个文本输入框 */
  850. function textbox($field_name){
  851. $value=$this->_get_value($field_name,$this->attrs);
  852. $this->set("value",$value);
  853. $html=$this->build("input",$field_name,$this->attrs);
  854. $this->reset();
  855. return $html;
  856. }
  857. /** 属出一个checkbox */
  858. function checkbox($field_name){
  859. if(!isset($this->attrs["value"]))
  860. throw new smException("check_box must specific a value");
  861. $this->set("type","checkbox");
  862. $checked_value=$this->_get_value($field_name,array());
  863. if($checked_value==$this->attrs["value"])
  864. $this->set("checked","checked");
  865. $html=$this->build("input",$field_name,$this->attrs);
  866. $this->reset();
  867. return $html;
  868. }
  869. /** 输出一个提交按钮 */
  870. function submitbox($value="提交"){
  871. $this->attrs["type"]="submit";
  872. $html=$this->build("button","",$value,$this->attrs);
  873. $this->reset();
  874. return $html;
  875. }
  876. /** 输出一个SELECT下拉框
  877. * @param $field_name String,字段域名字
  878. * @param $values Array,一个二维数组;比如:array(array("1","属性1"),array("2","属性2"),array(3,"属性3"))
  879. */
  880. function selectbox($field_name,$values){
  881. $value=$this->_get_value($field_name,$this->attrs);
  882. $select_html = $this->_left("select",$field_name,$this->attrs);
  883. $strs=array();
  884. foreach($values as $v){
  885. if(sizeof($v)!=2) throw new smException("you assign a bad value for select ,file:".__FILE__.",line:".__LINE__);
  886. if(!empty($value) && $v[0]==$value ){
  887. $temp=$strs[]=$this->build("option","",$v[1],array("value"=>$v[0],"selected"=>"selected"));
  888. }else{
  889. $strs[]=$this->build("option","",$v[1],array("value"=>$v[0]));
  890. }
  891. }
  892. $this->reset();
  893. return "$select_html>".join("",$strs)."</select>";
  894. }
  895. /** smForm类未明确给出的形形色色的其他各种HTML标记
  896. *
  897. * @param $name String HTML tag 的种类,可以是img,marquee,fieldset,iframe等等;
  898. * @param $args Array,一个有三个项的数组,第一个项是数据域名字,第二个是HTML属性,第三个是包含在标记里的innerhtml。
  899. */
  900. function build($tag_name,$field_name,$inner_html="",$html_attrs=NULL){
  901. $left_htmls = $this->_left($tag_name,$field_name,$html_attrs);
  902. if(in_array($tag_name,array(
  903. "input","img","link")))
  904. {
  905. $str.=$left_htmls."/>";
  906. }else{
  907. $str.=$left_htmls.">".$inner_html."</$tag_name>";
  908. }
  909. return $str;
  910. }
  911. function _get_value($field_name,$html_attrs){
  912. if(!empty($this->_form_values)){
  913. $value=$this->_form_values[$field_name];
  914. }
  915. if(!empty($html_attrs["value"]))
  916. $value=$html_attrs["value"];
  917. return $value;
  918. }
  919. function _left($tag_name,$field_name,$html_attrs=null){
  920. if($field_name){
  921. if($tag_name!="label"){
  922. $str="<".$tag_name." ";
  923. if(empty($html_attrs["id"])){
  924. $str.="id=\"".$this->_form_name."_".$field_name."\" ";
  925. }
  926. if(empty($html_attrs["name"])){
  927. $str.="name=\"".$this->_form_name."[".$field_name."]\" ";
  928. }
  929. }else{
  930. $str="<".$tag_name." ";
  931. }
  932. }
  933. else{
  934. $str="<".$tag_name." ";
  935. }
  936. if($html_attrs===NULL)
  937. $html_attrs=$this->attrs;
  938. foreach($html_attrs as $k=>$v){
  939. if($v!==NULL)
  940. $str .=$k."=\"".htmlspecialchars($v)."\" ";
  941. }
  942. return $str;
  943. }
  944. }
  945. /** run_sm 跑MVC流程
  946. * @param $controller controller名字;
  947. * @param $action action名字;
  948. */
  949. function run_sm($controller=null,$action=null) {
  950. global $sm_temp,$sm_config;
  951. if(is_null($controller))
  952. $sm_temp["controller"]=empty($_GET["controller"])? "smapplication":strtolower($_GET["controller"]);
  953. else
  954. $sm_temp["controller"]=$controller;
  955. if(is_null($action))
  956. $sm_temp["action"]=empty($_GET["action"])? "index":strtolower($_GET["action"]);
  957. else
  958. $sm_temp["action"]=$action;
  959. smDoEvent("before_run_sm",array("controller"=>$sm_temp["controller"],"action"=>$sm_temp["action"]));
  960. if(!class_exists($sm_temp["controller"]))
  961. include_once($sm_config["app_root"]."/app/".strtolower($sm_temp["controller"]).".php");
  962. $app=new $sm_temp["controller"]($sm_temp["controller"]);
  963. return $app->dispatch($sm_temp["action"]);
  964. }
  965. /* url转换器,1为请求转换,就是把类似q-替换为question/view
  966. 2为反向转换,就是把类似/question/view/替换为q-
  967. */
  968. function sm_urlmap($var, $direction=1) {
  969. global $sm_config;
  970. $replaces=$sm_config["url_maps"];
  971. (2 == $direction) && $replaces = array_flip($replaces);
  972. return str_replace(array_keys($replaces), array_values($replaces), $var);
  973. }
  974. /**
  975. * URL静态化的处理
  976. */
  977. function sm_open_shorturl(){
  978. global $sm_config,$sm_temp;
  979. $url=$_SERVER["REQUEST_URI"];
  980. $url=sm_urlmap($url,1);
  981. $parsed_patterns=(sm_compile_models($sm_config["url_routes"],$sm_config["url_namespace"]));
  982. $sm_temp["compiled_url_routes"]=$parsed_patterns;
  983. $url_parsed=sm_handle_url($parsed_patterns,$url);
  984. if($url_parsed["params"]) foreach($url_parsed["params"] as $k=>$v){
  985. if(preg_match("/\?/",$v)){
  986. $_GET[$k]=array_shift(explode("?",$v));
  987. }else{
  988. $_GET[$k]=$v;
  989. }
  990. }
  991. $sm_temp["url_pattern"]=$url_parsed["current_template"];
  992. $sm_temp["use_shorturl"]=true;
  993. }
  994. function sm_get_url_fields($pat){
  995. preg_match_all("/{([a-zA-Z\_]*)}/i",$pat,$regs);
  996. return $regs[1];
  997. }
  998. function sm_compile_models($models,$namespace=""){
  999. foreach($models as $k=>$v){
  1000. if(is_array($v)&&!is_numeric($k)){
  1001. $pat=$k;$field_rules=$v;
  1002. }else{
  1003. $field_rules=array();$pat=$v;
  1004. }
  1005. $fields=sm_get_url_fields($pat);
  1006. foreach($fields as $field){
  1007. if(!isset($field_rules[$field]))
  1008. $field_rules[$field]="([^.^\/]+)";
  1009. }
  1010. $pat = $namespace.$pat;
  1011. $real_pattern=str_replace("/","\/",$pat);
  1012. $real_pattern=str_replace("{","(?<",$real_pattern);
  1013. foreach($field_rules as $f=>$rule){
  1014. $real_pattern=str_replace($f."}",$f.">".$rule.")",$real_pattern);
  1015. }
  1016. $real_pattern="/^".$real_pattern."/";
  1017. $list[]=array("rules"=>$field_rules,"pat"=>$pat,"real_pattern"=>$real_pattern,"fields"=>$fields);
  1018. }
  1019. return $list;
  1020. }
  1021. function sm_handle_url($patterns,$url){
  1022. foreach($patterns as $pat){
  1023. if(preg_match($pat["real_pattern"],$url,$regs)){
  1024. $current_pattern=$pat["real_pattern"];
  1025. $current_template=$pat["pat"];
  1026. foreach($pat["fields"] as $f){
  1027. $params[$f]=$regs[$f];
  1028. }
  1029. return array("current_pattern"=>$current_pattern,"current_template"=>$current_template,"params"=>$params);
  1030. }
  1031. }
  1032. return false;
  1033. }
  1034. /** * sm_undo_magic_quotes_array 和sm_fixgpc用于解决有的服务器打开了magic_gpc设置的问题; * */
  1035. function sm_undo_magic_quotes_array($array){
  1036. return is_array($array) ? array_map('undo_magic_quotes_array',$array) : str_replace("\\'", "'", str_replace("\\\"", "\"", str_replace("\\\\", "\\", str_replace("\\\x00", "\x00", $array))));
  1037. }
  1038. /** 修正magic_quotes这个愚蠢的烦人的恼火的功能带来的不爽 */
  1039. function sm_fixgpc(){
  1040. if(get_magic_quotes_gpc()){
  1041. $_GET = sm_undo_magic_quotes_array($_GET);
  1042. $_POST = sm_undo_magic_quotes_array($_POST);
  1043. $_COOKIE = sm_undo_magic_quotes_array($_COOKIE);
  1044. $_FILES = sm_undo_magic_quotes_array($_FILES);
  1045. $_REQUEST = sm_undo_magic_quotes_array($_REQUEST);
  1046. }
  1047. }
  1048. $sm= new smObject();
  1049. sm_fixgpc();