Authored by 梁志锋

Merge remote-tracking branch 'origin/master' into beta

Too many changes to show.

To preserve performance only 34 of 34+ files are displayed.

  1 +<?php return function ($in, $debugopt = 1) {
  2 + $cx = array(
  3 + 'flags' => array(
  4 + 'jstrue' => false,
  5 + 'jsobj' => false,
  6 + 'spvar' => true,
  7 + 'prop' => false,
  8 + 'method' => false,
  9 + 'mustlok' => true,
  10 + 'echo' => false,
  11 + 'debug' => $debugopt,
  12 + ),
  13 + 'constants' => array(),
  14 + 'helpers' => array(),
  15 + 'blockhelpers' => array(),
  16 + 'hbhelpers' => array(),
  17 + 'partials' => array(),
  18 + 'scopes' => array(),
  19 + 'sp_vars' => array('root' => $in),
  20 + 'lcrun' => 'Plugin\LCRun3',
  21 +
  22 + );
  23 +
  24 + return '<!DOCTYPE html>
  25 +<html>
  26 +<head>
  27 + <meta charset="UTF-8">
  28 + <title>'.htmlentities((string)Plugin\LCRun3::v($cx, $in, array('staticTitle')), ENT_QUOTES, 'UTF-8').'</title>
  29 + <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, minimum-scale=1, user-scalable=no">
  30 + <style>
  31 + *{margin: 0;padding: 0;}
  32 + #coupon-container {width: 100%;}
  33 + #coupon-container img {width: 100%; height: auto; display: block;overflow: hidden;}
  34 + .img-box {width: 100%;position: relative;}
  35 + .img-box .href {width: 50%; height: 100%;position: absolute;top: 0;}
  36 + .img-box .href-left {left: 0}
  37 + .img-box .href-right {right: 0}
  38 + .img-box .href-center {width: 90%;height: 100%;position: absolute;top: 0;left: 5%;}
  39 + .show-more {height: 100%;width: 25%;position: absolute;top: 0;right: 10%;}
  40 + .yoho-tip {position: fixed;display: none;text-align: center;width: 70%;padding: 34px 0;top: 50%;left: 50%;margin-left: -35%;margin-top: -45px;background-color: #000;opacity: 0.9;color: #fff;font-size: 18px;border: none;border-radius: 10px;}
  41 + </style>
  42 + <link rel="dns-prefetch" href="//cdn.yoho.cn">
  43 + <link rel="dns-prefetch" href="//static.yohobuy.com">
  44 +</head>
  45 +<body>
  46 + <div id="coupon-container" param="'.htmlentities((string)Plugin\LCRun3::v($cx, $in, array('activityId')), ENT_QUOTES, 'UTF-8').'" isLogged="'.htmlentities((string)Plugin\LCRun3::v($cx, $in, array('isLogged')), ENT_QUOTES, 'UTF-8').'">
  47 + <img src="'.htmlentities((string)Plugin\LCRun3::v($cx, $in, array('jsUrl')), ENT_QUOTES, 'UTF-8').'/cuxiao/img/newuser/160107/01.jpg">
  48 + <img src="'.htmlentities((string)Plugin\LCRun3::v($cx, $in, array('jsUrl')), ENT_QUOTES, 'UTF-8').'/cuxiao/img/newuser/160107/02.jpg">
  49 + <img src="'.htmlentities((string)Plugin\LCRun3::v($cx, $in, array('jsUrl')), ENT_QUOTES, 'UTF-8').'/cuxiao/img/newuser/160107/03-a.jpg">
  50 + <img src="'.htmlentities((string)Plugin\LCRun3::v($cx, $in, array('jsUrl')), ENT_QUOTES, 'UTF-8').'/cuxiao/img/newuser/160107/line-1.jpg">
  51 + <img src="'.htmlentities((string)Plugin\LCRun3::v($cx, $in, array('jsUrl')), ENT_QUOTES, 'UTF-8').'/cuxiao/img/newuser/160107/04-a.jpg">
  52 + <div class="img-box">
  53 + <img src="'.htmlentities((string)Plugin\LCRun3::v($cx, $in, array('jsUrl')), ENT_QUOTES, 'UTF-8').'/cuxiao/img/newuser/160107/05-a.jpg">
  54 + <a class="href href-right" href="'.htmlentities((string)Plugin\LCRun3::v($cx, $in, array('url_yohope')), ENT_QUOTES, 'UTF-8').'"></a>
  55 + </div>
  56 + <div class="img-box">
  57 + <img src="'.htmlentities((string)Plugin\LCRun3::v($cx, $in, array('jsUrl')), ENT_QUOTES, 'UTF-8').'/cuxiao/img/newuser/160107/06.jpg">
  58 + <a class="href href-center" href="'.htmlentities((string)Plugin\LCRun3::v($cx, $in, array('url_mycoupon')), ENT_QUOTES, 'UTF-8').'"></a>
  59 + </div>
  60 + <img src="'.htmlentities((string)Plugin\LCRun3::v($cx, $in, array('jsUrl')), ENT_QUOTES, 'UTF-8').'/cuxiao/img/newuser/160107/line-2.jpg">
  61 +
  62 + <img src="'.htmlentities((string)Plugin\LCRun3::v($cx, $in, array('jsUrl')), ENT_QUOTES, 'UTF-8').'/cuxiao/img/newuser/160107/07.jpg">
  63 + <div class="img-box">
  64 + <img src="'.htmlentities((string)Plugin\LCRun3::v($cx, $in, array('jsUrl')), ENT_QUOTES, 'UTF-8').'/cuxiao/img/newuser/160107/08.jpg">
  65 + <a class="href href-left" href="'.htmlentities((string)Plugin\LCRun3::v($cx, $in, array('url_more')), ENT_QUOTES, 'UTF-8').'"></a>
  66 + <a class="href href-right" href="'.htmlentities((string)Plugin\LCRun3::v($cx, $in, array('url_more')), ENT_QUOTES, 'UTF-8').'"></a>
  67 + </div>
  68 + <div class="img-box">
  69 + <img src="'.htmlentities((string)Plugin\LCRun3::v($cx, $in, array('jsUrl')), ENT_QUOTES, 'UTF-8').'/cuxiao/img/newuser/160107/09.jpg">
  70 + <span class="href href-left get-coupon" href="'.htmlentities((string)Plugin\LCRun3::v($cx, $in, array('jumpUrl')), ENT_QUOTES, 'UTF-8').'" param="17443"></span>
  71 + <span class="href href-right get-coupon" href="'.htmlentities((string)Plugin\LCRun3::v($cx, $in, array('jumpUrl')), ENT_QUOTES, 'UTF-8').'" param="17445"></span>
  72 + </div>
  73 + <img src="'.htmlentities((string)Plugin\LCRun3::v($cx, $in, array('jsUrl')), ENT_QUOTES, 'UTF-8').'/cuxiao/img/newuser/160107/line-1.jpg">
  74 + <div class="img-box">
  75 + <img src="'.htmlentities((string)Plugin\LCRun3::v($cx, $in, array('jsUrl')), ENT_QUOTES, 'UTF-8').'/cuxiao/img/newuser/160107/10.jpg">
  76 + <a class="href href-left" href="'.htmlentities((string)Plugin\LCRun3::v($cx, $in, array('url_more')), ENT_QUOTES, 'UTF-8').'"></a>
  77 + <a class="href href-right" href="'.htmlentities((string)Plugin\LCRun3::v($cx, $in, array('url_1')), ENT_QUOTES, 'UTF-8').'"></a>
  78 + </div>
  79 + <div class="img-box">
  80 + <img src="'.htmlentities((string)Plugin\LCRun3::v($cx, $in, array('jsUrl')), ENT_QUOTES, 'UTF-8').'/cuxiao/img/newuser/160107/11.jpg">
  81 + <span class="href href-left get-coupon" href="'.htmlentities((string)Plugin\LCRun3::v($cx, $in, array('jumpUrl')), ENT_QUOTES, 'UTF-8').'" param="17463"></span>
  82 + <span class="href href-right get-coupon" href="'.htmlentities((string)Plugin\LCRun3::v($cx, $in, array('jumpUrl')), ENT_QUOTES, 'UTF-8').'" param="17451"></span>
  83 + </div>
  84 + <img src="'.htmlentities((string)Plugin\LCRun3::v($cx, $in, array('jsUrl')), ENT_QUOTES, 'UTF-8').'/cuxiao/img/newuser/160107/line-1.jpg">
  85 + <div class="img-box">
  86 + <img src="'.htmlentities((string)Plugin\LCRun3::v($cx, $in, array('jsUrl')), ENT_QUOTES, 'UTF-8').'/cuxiao/img/newuser/160107/12.jpg">
  87 + <a class="href href-left" href="'.htmlentities((string)Plugin\LCRun3::v($cx, $in, array('url_2')), ENT_QUOTES, 'UTF-8').'"></a>
  88 + <a class="href href-right" href="'.htmlentities((string)Plugin\LCRun3::v($cx, $in, array('url_3')), ENT_QUOTES, 'UTF-8').'"></a>
  89 + </div>
  90 + <div class="img-box">
  91 + <img src="'.htmlentities((string)Plugin\LCRun3::v($cx, $in, array('jsUrl')), ENT_QUOTES, 'UTF-8').'/cuxiao/img/newuser/160107/13.jpg">
  92 + <span class="href href-left get-coupon" href="'.htmlentities((string)Plugin\LCRun3::v($cx, $in, array('jumpUrl')), ENT_QUOTES, 'UTF-8').'" param="17461"></span>
  93 + <span class="href href-right get-coupon" href="'.htmlentities((string)Plugin\LCRun3::v($cx, $in, array('jumpUrl')), ENT_QUOTES, 'UTF-8').'" param="17459"></span>
  94 + </div>
  95 + <img src="'.htmlentities((string)Plugin\LCRun3::v($cx, $in, array('jsUrl')), ENT_QUOTES, 'UTF-8').'/cuxiao/img/newuser/160107/line-1.jpg">
  96 + <div class="img-box">
  97 + <img src="'.htmlentities((string)Plugin\LCRun3::v($cx, $in, array('jsUrl')), ENT_QUOTES, 'UTF-8').'/cuxiao/img/newuser/160107/14.jpg">
  98 + <a class="href href-left" href="'.htmlentities((string)Plugin\LCRun3::v($cx, $in, array('url_4')), ENT_QUOTES, 'UTF-8').'"></a>
  99 + <a class="href href-right" href="'.htmlentities((string)Plugin\LCRun3::v($cx, $in, array('url_5')), ENT_QUOTES, 'UTF-8').'"></a>
  100 + </div>
  101 + <div class="img-box">
  102 + <img src="'.htmlentities((string)Plugin\LCRun3::v($cx, $in, array('jsUrl')), ENT_QUOTES, 'UTF-8').'/cuxiao/img/newuser/160107/15.jpg">
  103 + <span class="href href-left get-coupon" href="'.htmlentities((string)Plugin\LCRun3::v($cx, $in, array('jumpUrl')), ENT_QUOTES, 'UTF-8').'" param="17453"></span>
  104 + <span class="href href-right get-coupon" href="'.htmlentities((string)Plugin\LCRun3::v($cx, $in, array('jumpUrl')), ENT_QUOTES, 'UTF-8').'" param="17455"></span>
  105 + </div>
  106 + <img src="'.htmlentities((string)Plugin\LCRun3::v($cx, $in, array('jsUrl')), ENT_QUOTES, 'UTF-8').'/cuxiao/img/newuser/160107/line-1.jpg">
  107 + <div class="img-box">
  108 + <img src="'.htmlentities((string)Plugin\LCRun3::v($cx, $in, array('jsUrl')), ENT_QUOTES, 'UTF-8').'/cuxiao/img/newuser/160107/16.jpg">
  109 + <a class="href href-left" href="'.htmlentities((string)Plugin\LCRun3::v($cx, $in, array('url_6')), ENT_QUOTES, 'UTF-8').'"></a>
  110 + </div>
  111 + <div class="img-box">
  112 + <img src="'.htmlentities((string)Plugin\LCRun3::v($cx, $in, array('jsUrl')), ENT_QUOTES, 'UTF-8').'/cuxiao/img/newuser/160107/17.jpg">
  113 + <span class="href href-left get-coupon" href="'.htmlentities((string)Plugin\LCRun3::v($cx, $in, array('jumpUrl')), ENT_QUOTES, 'UTF-8').'" param="17449"></span>
  114 + </div>
  115 + <img src="'.htmlentities((string)Plugin\LCRun3::v($cx, $in, array('jsUrl')), ENT_QUOTES, 'UTF-8').'/cuxiao/img/newuser/160107/line-1.jpg">
  116 +
  117 + <img src="'.htmlentities((string)Plugin\LCRun3::v($cx, $in, array('jsUrl')), ENT_QUOTES, 'UTF-8').'/cuxiao/img/newuser/160107/24-1.jpg">
  118 + <div class="img-box">
  119 + <img src="'.htmlentities((string)Plugin\LCRun3::v($cx, $in, array('jsUrl')), ENT_QUOTES, 'UTF-8').'/cuxiao/img/newuser/160107/24-2.jpg">
  120 + <a class="show-more" href="'.htmlentities((string)Plugin\LCRun3::v($cx, $in, array('url_help')), ENT_QUOTES, 'UTF-8').'"></a>
  121 + </div>
  122 + <img src="'.htmlentities((string)Plugin\LCRun3::v($cx, $in, array('jsUrl')), ENT_QUOTES, 'UTF-8').'/cuxiao/img/newuser/160107/24-3.jpg">
  123 + <img src="'.htmlentities((string)Plugin\LCRun3::v($cx, $in, array('jsUrl')), ENT_QUOTES, 'UTF-8').'/cuxiao/img/newuser/160107/line-2.jpg">
  124 + <img src="'.htmlentities((string)Plugin\LCRun3::v($cx, $in, array('jsUrl')), ENT_QUOTES, 'UTF-8').'/cuxiao/img/newuser/160107/25-1-a.jpg">
  125 + <img src="'.htmlentities((string)Plugin\LCRun3::v($cx, $in, array('jsUrl')), ENT_QUOTES, 'UTF-8').'/cuxiao/img/newuser/160107/25-2-a.jpg">
  126 + <img src="'.htmlentities((string)Plugin\LCRun3::v($cx, $in, array('jsUrl')), ENT_QUOTES, 'UTF-8').'/cuxiao/img/newuser/160107/25-3-a.jpg">
  127 + <img src="'.htmlentities((string)Plugin\LCRun3::v($cx, $in, array('jsUrl')), ENT_QUOTES, 'UTF-8').'/cuxiao/img/newuser/160107/26-a.jpg">
  128 + <img src="'.htmlentities((string)Plugin\LCRun3::v($cx, $in, array('jsUrl')), ENT_QUOTES, 'UTF-8').'/cuxiao/img/newuser/160107/27-a.jpg">
  129 + </div>
  130 + <script type="text/javascript" src="'.htmlentities((string)Plugin\LCRun3::v($cx, $in, array('jsUrl')), ENT_QUOTES, 'UTF-8').'/cuxiao/js/jquery.min.js"></script>
  131 + <script type="text/javascript" src="'.htmlentities((string)Plugin\LCRun3::v($cx, $in, array('jsUrl')), ENT_QUOTES, 'UTF-8').'/cuxiao/js/newuser/coupon2.js"></script>
  132 +</body>
  133 +</html>';
  134 +}
  135 +?>
@@ -23,11 +23,11 @@ @@ -23,11 +23,11 @@
23 <div id="coupon-container" param="{{activityId}}" isLogged="{{isLogged}}"> 23 <div id="coupon-container" param="{{activityId}}" isLogged="{{isLogged}}">
24 <img src="{{jsUrl}}/cuxiao/img/newuser/160107/01.jpg"> 24 <img src="{{jsUrl}}/cuxiao/img/newuser/160107/01.jpg">
25 <img src="{{jsUrl}}/cuxiao/img/newuser/160107/02.jpg"> 25 <img src="{{jsUrl}}/cuxiao/img/newuser/160107/02.jpg">
26 - <img src="{{jsUrl}}/cuxiao/img/newuser/160107/03.jpg"> 26 + <img src="{{jsUrl}}/cuxiao/img/newuser/160107/03-a.jpg">
27 <img src="{{jsUrl}}/cuxiao/img/newuser/160107/line-1.jpg"> 27 <img src="{{jsUrl}}/cuxiao/img/newuser/160107/line-1.jpg">
28 - <img src="{{jsUrl}}/cuxiao/img/newuser/160107/04.jpg"> 28 + <img src="{{jsUrl}}/cuxiao/img/newuser/160107/04-a.jpg">
29 <div class="img-box"> 29 <div class="img-box">
30 - <img src="{{jsUrl}}/cuxiao/img/newuser/160107/05.jpg"> 30 + <img src="{{jsUrl}}/cuxiao/img/newuser/160107/05-a.jpg">
31 <a class="href href-right" href="{{url_yohope}}"></a> 31 <a class="href href-right" href="{{url_yohope}}"></a>
32 </div> 32 </div>
33 <div class="img-box"> 33 <div class="img-box">
@@ -98,11 +98,11 @@ @@ -98,11 +98,11 @@
98 </div> 98 </div>
99 <img src="{{jsUrl}}/cuxiao/img/newuser/160107/24-3.jpg"> 99 <img src="{{jsUrl}}/cuxiao/img/newuser/160107/24-3.jpg">
100 <img src="{{jsUrl}}/cuxiao/img/newuser/160107/line-2.jpg"> 100 <img src="{{jsUrl}}/cuxiao/img/newuser/160107/line-2.jpg">
101 - <img src="{{jsUrl}}/cuxiao/img/newuser/160107/25-1.jpg">  
102 - <img src="{{jsUrl}}/cuxiao/img/newuser/160107/25-2.jpg">  
103 - <img src="{{jsUrl}}/cuxiao/img/newuser/160107/25-3.jpg">  
104 - <img src="{{jsUrl}}/cuxiao/img/newuser/160107/26.jpg">  
105 - <img src="{{jsUrl}}/cuxiao/img/newuser/160107/27.jpg"> 101 + <img src="{{jsUrl}}/cuxiao/img/newuser/160107/25-1-a.jpg">
  102 + <img src="{{jsUrl}}/cuxiao/img/newuser/160107/25-2-a.jpg">
  103 + <img src="{{jsUrl}}/cuxiao/img/newuser/160107/25-3-a.jpg">
  104 + <img src="{{jsUrl}}/cuxiao/img/newuser/160107/26-a.jpg">
  105 + <img src="{{jsUrl}}/cuxiao/img/newuser/160107/27-a.jpg">
106 </div> 106 </div>
107 <script type="text/javascript" src="{{jsUrl}}/cuxiao/js/jquery.min.js"></script> 107 <script type="text/javascript" src="{{jsUrl}}/cuxiao/js/jquery.min.js"></script>
108 <script type="text/javascript" src="{{jsUrl}}/cuxiao/js/newuser/coupon2.js"></script> 108 <script type="text/javascript" src="{{jsUrl}}/cuxiao/js/newuser/coupon2.js"></script>
  1 +<?php
  2 +namespace Hood;
  3 +
  4 +use Yaf\Controller_Abstract;
  5 +use Hood\Helper\View as hoodView;
  6 +use Yaf;
  7 +use Hood\Validator as hoodValidator;
  8 +
  9 +class Action extends Controller_Abstract
  10 +{
  11 + private $_viewLink = array();
  12 +
  13 + private $_viewScript = array();
  14 +
  15 + private $_headTitle;
  16 +
  17 + private $_headmeta;
  18 +
  19 + /**
  20 + * Meta
  21 + * @return \Hood\Helper\View\Meta
  22 + */
  23 + public function _headMeta()
  24 + {
  25 + if (empty($this->_headmeta)) {
  26 + $this->_headmeta = new hoodView\Meta();
  27 + $this->getView()->assign("_headmeta", $this->_headmeta);
  28 + }
  29 + return $this->_headmeta;
  30 + }
  31 +
  32 +
  33 + /**
  34 + * Script
  35 + * @return \Hood\Helper\View\Script
  36 + */
  37 + public function _viewScript($scriptName = '_headScript')
  38 + {
  39 + if (!isset($this->_viewScript[$scriptName])) {
  40 + $this->_viewScript[$scriptName] = new hoodView\Script();
  41 + $this->getView()->assign($scriptName, $this->_viewScript[$scriptName]);
  42 + }
  43 + return $this->_viewScript[$scriptName];
  44 + }
  45 +
  46 + /**
  47 + *
  48 + * @return \Hood\Helper\View\Link
  49 + */
  50 + public function _viewLink($linkName = '_headLink')
  51 + {
  52 + if (!isset($this->_viewLink[$linkName])) {
  53 + $this->_viewLink[$linkName] = new hoodView\Link();
  54 + $this->getView()->assign($linkName, $this->_viewLink[$linkName]);
  55 + }
  56 + return $this->_viewLink[$linkName];
  57 + }
  58 +
  59 + /**
  60 + * Title
  61 + * @return \Hood\Helper\View\Title
  62 + */
  63 + public function _headTitle($title)
  64 + {
  65 + if (empty($this->_headTitle)) {
  66 + $this->_headTitle = new hoodView\Title();
  67 + $this->getView()->assign("_headTitle", $this->_headTitle);
  68 + }
  69 + return $this->_headTitle->headTitle($title);
  70 + }
  71 +
  72 + /**
  73 + * js 跳转 并 提示
  74 + *
  75 + * @param String $url
  76 + * @param String $expression
  77 + */
  78 + protected function helpJsRedirect($message = '', $script = "history.back();")
  79 + {
  80 + $html = '';
  81 + if (!empty($message)) {
  82 + header("content-type: text/html; charset=utf-8");
  83 + $message = str_replace("\n", "\\n", $message);
  84 + $html .= "<script language=\"javascript\">";
  85 + $html .= "alert(\"{$message}\");";
  86 + $html .= "</script>";
  87 + }
  88 + $html .= "<script language=\"javascript\">";
  89 + $html .= $script;
  90 + $html .= "</script>";
  91 + die($html);
  92 + }
  93 +
  94 + /**
  95 + * 跳转
  96 + * @param String $url
  97 + */
  98 + protected function helpLocation($url)
  99 + {
  100 + header('Location: ' . $url);
  101 + }
  102 +
  103 + /**
  104 + * refresh跳转
  105 + * @param $url
  106 + * @param string $message
  107 + */
  108 + protected function helpRefresh($url, $message = '')
  109 + {
  110 + $html = '';
  111 + if (!empty($message)) {
  112 + header("content-type: text/html; charset=utf-8");
  113 + $message = str_replace("\n", "\\n", $message);
  114 + $html .= "<script language=\"javascript\">";
  115 + $html .= "alert(\"{$message}\");";
  116 + $html .= "</script>";
  117 + }
  118 + $html .= "<script language=\"javascript\">";
  119 + $html .= "window.location.href='{$url}';";
  120 + $html .= "</script>";
  121 + echo $html;
  122 + }
  123 +
  124 + /**
  125 + * JSON输出
  126 + * @param $code
  127 + * @param null $message
  128 + * @param null $data
  129 + */
  130 + protected function helpJsonResult($code, $message = null, $data = null)
  131 + {
  132 + header('Content-type: application/json');
  133 + echo json_encode(array('code' => $code, 'message' => $message, 'data' => $data));
  134 + exit();
  135 + }
  136 +
  137 + /**
  138 + * JSON输出
  139 + * @param array $data
  140 + */
  141 + protected function helpJson(array $data)
  142 + {
  143 + header('Content-type: application/json');
  144 + echo json_encode($data);
  145 + exit();
  146 + }
  147 +
  148 + /**
  149 + * JSONP Callback输出,用于远程调用
  150 + * @param $callbackString
  151 + * @param $code
  152 + * @param null $message
  153 + * @param null $data
  154 + */
  155 + protected function helpJsonCallbackResult($callbackString, $code, $message = null, $data = null)
  156 + {
  157 + header('Content-type: application/json');
  158 + echo $callbackString . "(";
  159 + echo json_encode(array('code' => $code, 'message' => $message, 'data' => $data));
  160 + echo ")";
  161 + exit();
  162 + }
  163 +
  164 +
  165 + /**
  166 + * @param string $namespace
  167 + * @return \Hood\Core\Session\SessionNamespace
  168 + */
  169 + public function session($namespace = 'session_default', $sessionName = null)
  170 + {
  171 + return Session::start($namespace, $sessionName);
  172 + }
  173 +
  174 + /**
  175 + * 数据校验
  176 + * @param array $data
  177 + * @param array $rules
  178 + * @param array $messagesAttribute
  179 + * @return Helper\Validation\Validator
  180 + */
  181 + public function validator(array $data, array $rules, array $messagesAttribute = array())
  182 + {
  183 + return hoodValidator::make($data, $rules, $messagesAttribute);
  184 + }
  185 +}
  1 +<?php
  2 +/**
  3 + * Created by PhpStorm.
  4 + * User: Zip
  5 + * Date: 14/12/9
  6 + * Time: 下午7:40
  7 + */
  8 +
  9 +namespace Hood;
  10 +
  11 +use Hood\Cache\Memcached as Mcd;
  12 +use Hood\Cache\Memcache as Mc;
  13 +use Hood\Cache\CacheRedis;
  14 +use Hood\Cache\FileCache;
  15 +
  16 +class Cache
  17 +{
  18 + /**
  19 + *
  20 + * @param null $node
  21 + * @return Mcd
  22 + */
  23 + static public function Memcached($node = null, $childNode = 'hosts')
  24 + {
  25 + $mc = new Mcd();
  26 + $mc->setNode($node)->setChildNodes($childNode);
  27 + return $mc;
  28 + }
  29 +
  30 + /**
  31 + * @param null $node
  32 + * @param string $childNode
  33 + * @return Mc
  34 + */
  35 + static public function Memcache($node = null, $childNode = 'hosts')
  36 + {
  37 + $mc = new Mc();
  38 + $mc->setNode($node)->setChildNodes($childNode);
  39 + return $mc;
  40 + }
  41 +
  42 + /**
  43 + * @return CacheRedis
  44 + */
  45 + static public function Redis()
  46 + {
  47 + $servers = array();
  48 + $persistentID = '';
  49 + return new CacheRedis($servers, $persistentID);
  50 + }
  51 +
  52 +
  53 + /**
  54 + *
  55 + * @param null $childNode
  56 + * @param string $node
  57 + * @param null $cachePath
  58 + * @return FileCache
  59 + */
  60 + static public function File($childNode = null, $node = 'cache', $cachePath = null)
  61 + {
  62 + return new FileCache($childNode, $node, $cachePath);
  63 + }
  64 +}
  1 +<?php
  2 +/**
  3 + * Created by PhpStorm.
  4 + * User: Zip
  5 + * Date: 14/12/9
  6 + * Time: 下午10:35
  7 + */
  8 +
  9 +namespace Hood\Cache;
  10 +
  11 +interface CacheInterface
  12 +{
  13 + /**
  14 + * @param $key
  15 + * @return mixed
  16 + */
  17 + public function get($key);
  18 +
  19 + /**
  20 + * @param $key
  21 + * @param $value
  22 + * @param $minutes
  23 + * @return mixed
  24 + */
  25 + public function add($key, $value, $minutes);
  26 +
  27 + /**
  28 + * @param $key
  29 + * @param $value
  30 + * @param $minutes
  31 + * @return mixed
  32 + */
  33 + public function set($key, $value, $minutes);
  34 +
  35 + /**
  36 + * @param $key
  37 + * @param int $value
  38 + * @return mixed
  39 + */
  40 + public function increment($key, $value = 1);
  41 +
  42 + /**
  43 + * @param $key
  44 + * @param int $value
  45 + * @return mixed
  46 + */
  47 + public function decrement($key, $value = 1);
  48 +
  49 + /**
  50 + * @param $key
  51 + * @return mixed
  52 + */
  53 + public function delete($key);
  54 +
  55 + /**
  56 + * @param $tagName
  57 + * @return $this
  58 + */
  59 + public function tag($tagName);
  60 +}
  1 +<?php
  2 +/**
  3 + * Created by PhpStorm.
  4 + * User: Zip
  5 + * Date: 14/11/23
  6 + * Time: 上午1:39
  7 + */
  8 +
  9 +namespace Hood\Cache;
  10 +
  11 +use \Redis;
  12 +
  13 +class CacheRedis
  14 +{
  15 +
  16 + /**
  17 + *
  18 + * Enter description here ...
  19 + * @var Redis
  20 + */
  21 + private $redis;
  22 +
  23 + private $timeout = 2.5;
  24 +
  25 + public function __construct(array $servers, $persistentID = '')
  26 + {
  27 + if (empty($servers)) {
  28 + throw new Q_Cache_Exception('redis server is null.');
  29 + }
  30 + $this->redis = new Redis();
  31 + $this->redis->connect($servers['host'], $servers['port'], $this->timeout);
  32 + }
  33 +
  34 + /**
  35 + *
  36 + * 返回key所关联的字符串值,如果key不存在则返回特殊值nil。
  37 + * @param String $key
  38 + * @return Mixed or nil
  39 + */
  40 + public function get($key)
  41 + {
  42 + assert(is_string($key));
  43 + return $this->redis->get($key);
  44 + }
  45 +
  46 + /**
  47 + *
  48 + * 将字符串值value关联到key
  49 + * @param String $key
  50 + * @param Mixed $val
  51 + * @return bool
  52 + */
  53 + public function set($key, $val)
  54 + {
  55 + assert(is_string($key));
  56 + return $this->redis->set($key, $val);
  57 + }
  58 +
  59 + /**
  60 + *
  61 + * 同时设置一个或多个key-value对。
  62 + * @param array $keys
  63 + * @return bool
  64 + */
  65 + public function mset(array $keys)
  66 + {
  67 + return $this->redis->mset($keys);
  68 + }
  69 +
  70 + /**
  71 + *
  72 + * 返回所有(一个或多个)给定key的值.如果某个指定key不存在,那么返回特殊值nil。因此,该命令永不失败。
  73 + * @param array $keys
  74 + * @return Mixed
  75 + */
  76 + public function mget(array $keys)
  77 + {
  78 + return $this->redis->mget($keys);
  79 + }
  80 +
  81 + /**
  82 + *
  83 + * 返回key中字符串值的子字符串,字符串的截取范围由start和end两个偏移量决定(包括start和end在内)。
  84 + * 负数偏移量表示从字符串最后开始计数,-1表示最后一个字符,-2表示倒数第二个,以此类推
  85 + * @param String $key
  86 + * @param Integer $start
  87 + * @param Integer $end
  88 + * @return String
  89 + */
  90 + public function getRange($key, $start, $end)
  91 + {
  92 + assert(is_string($key));
  93 + return $this->redis->getRange($key, $start, $end);
  94 + }
  95 +
  96 + /**
  97 + *
  98 + * 删除数据 ( 返回删除个数 )
  99 + * @param String $key
  100 + * @return bool
  101 + */
  102 + public function del($key)
  103 + {
  104 + assert(is_string($key));
  105 + return $this->redis->del($key);
  106 + }
  107 +
  108 + /**
  109 + * 查找符合给定模式的key。
  110 + *
  111 + * 可以使用正则
  112 + * =========================================
  113 + * *命中数据库中所有key
  114 + * h?llo命中hello, hallo and hxllo等
  115 + * h*llo命中hllo和heeeeello等
  116 + * h[ae]llo命中hello和hallo,但不命中hillo
  117 + * =========================================
  118 + * KEYS的速度非常快,但在一个大的数据库中使用它仍然可能造成性能问题,如果你需要从一个数据集中查找特定的key,你最好还是用集合(set)结构。
  119 + * @param String $keys
  120 + * @return Mixed
  121 + */
  122 + public function keys($keys)
  123 + {
  124 + return $this->redis->keys($keys);
  125 + }
  126 +
  127 + /**
  128 + *
  129 + * 选择数据库
  130 + * @param String $db
  131 + * @return bool
  132 + */
  133 + public function select($db = 9)
  134 + {
  135 + return $this->redis->select($db);
  136 + }
  137 +
  138 + /**
  139 + *
  140 + * 获取 hash 集合中的键值
  141 + * @param String $hashName
  142 + * @param String $key
  143 + * @param Mixed $val
  144 + * @return Mixed
  145 + */
  146 + public function hget($hashName, $key, $val)
  147 + {
  148 + assert(is_string($hashName)) && assert(is_string($key));
  149 + return $this->redis->hget($hashName, $key, $val);
  150 + }
  151 +
  152 + /**
  153 + *
  154 + * 将哈希表key中的域field的值设为value。
  155 + * @param String $hashName
  156 + * @param String $key
  157 + * @param Mixed $val
  158 + * @return bool
  159 + */
  160 + public function hset($hashName, $key, $val)
  161 + {
  162 + assert(is_string($hashName)) && assert(is_string($key));
  163 + return $this->redis->hset($hashName, $key, $val);
  164 + }
  165 +
  166 + /**
  167 + *
  168 + * 排序
  169 + *
  170 + * @param String $key
  171 + * @param array $options
  172 + * 'by' => 'some_pattern_*',
  173 + * 'limit' => array(0, 1),
  174 + * 'get' => 'some_other_pattern_*' or an array of patterns,
  175 + * 'sort' => 'asc' or 'desc',
  176 + * 'alpha' => TRUE,
  177 + * 'store' => 'external-key'
  178 + * @return array
  179 + */
  180 + public function sort($key, array $options = array())
  181 + {
  182 + assert(is_string($key));
  183 + return $this->redis->sort($key, $options);
  184 + }
  185 +
  186 + /**
  187 + *
  188 + * 从当前数据库中随机返回(不删除)一个key。
  189 + * @return String or Mixed
  190 + */
  191 + public function randomkey()
  192 + {
  193 + return $this->redis->randomKey();
  194 + }
  195 +
  196 + /**
  197 + *
  198 + * 返回给定key的剩余生存时间(time to live)(以秒为单位)。
  199 + * @param String $key
  200 + * @return Integer
  201 + */
  202 + public function ttl($key)
  203 + {
  204 + assert(is_string($key));
  205 + return $this->redis->ttl($key);
  206 + }
  207 +
  208 + /**
  209 + *
  210 + * 检查给定key是否存在
  211 + * @param String $key
  212 + * @return bool
  213 + */
  214 + public function exists($key)
  215 + {
  216 + assert(is_string($key));
  217 + return $this->redis->exists($key);
  218 + }
  219 +
  220 + /**
  221 + *
  222 + * 移动key 到另外一个数据库
  223 + * @param String $key
  224 + * @param Integer $dbName
  225 + * @return bool
  226 + */
  227 + public function move($key, $dbName)
  228 + {
  229 + assert(is_string($key));
  230 + return $this->redis->move($key, $dbName);
  231 + }
  232 +
  233 + /**
  234 + *
  235 + * 将key改名为newkey
  236 + * @param String $key
  237 + * @param String $newKey
  238 + * @return bool
  239 + */
  240 + public function rename($key, $newKey)
  241 + {
  242 + assert(is_string($key)) && assert(is_string($newKey));
  243 + return $this->redis->rename($key, $newKey);
  244 + }
  245 +
  246 + /**
  247 + *
  248 + * 返回key所储存的值的类型
  249 + * @param String $key
  250 + * @return Mixed
  251 + * ================================
  252 + * none(key不存在) string(字符串) list(列表) set(集合) zset(有序集) hash(哈希表)
  253 + * ================================
  254 + */
  255 + public function type($key)
  256 + {
  257 + return $this->redis->type($key);
  258 + }
  259 +
  260 + /**
  261 + *
  262 + * 为给定key设置生存时间
  263 + * @param String $key
  264 + * @param Integer $expire
  265 + * @return bool
  266 + */
  267 + public function setTimeout($key, $expire)
  268 + {
  269 + assert(is_string($key)) && assert(is_int($expire));
  270 + return $this->redis->setTimeout($key, $expire);
  271 + }
  272 +
  273 + /**
  274 + *
  275 + * 不同在于EXPIREAT命令接受的时间参数是UNIX时间戳(unix timestamp)。
  276 + * @param String $key
  277 + * @param Integer $expire
  278 + * @return bool
  279 + */
  280 + public function expireAt($key, $expire)
  281 + {
  282 + assert(is_string($key)) && assert(is_int($expire));
  283 + return $this->redis->expireAt($key, $expire);
  284 + }
  285 +
  286 + /**
  287 + *
  288 + * 移除给定key的生存时间
  289 + * @param String $key
  290 + * @return bool
  291 + */
  292 + public function persist($key)
  293 + {
  294 + assert(is_string($key));
  295 + return $this->redis->persist($key);
  296 + }
  297 +
  298 + /**
  299 + *
  300 + * 将值value关联到key,并将key的生存时间设为seconds(以秒为单位)
  301 + * @param String $key
  302 + * @param Mixed $val
  303 + * @param Integer $expire
  304 + * @return bool
  305 + */
  306 + public function setex($key, $val, $expire)
  307 + {
  308 + assert(is_string($key)) && assert(is_int($expire));
  309 + return $this->redis->setex($key, $expire, $val);
  310 + }
  311 +
  312 + /**
  313 + *
  314 + * 如果key已经存在并且是一个字符串,APPEND命令将value追加到key原来的值之后
  315 + * @param String $key
  316 + * @param Mixed $val
  317 + * @return bool
  318 + */
  319 + public function append($key, $val)
  320 + {
  321 + assert(is_string($key));
  322 + return $this->redis->append($key, $val);
  323 + }
  324 +
  325 + /**
  326 + *
  327 + * 将给定key的值设为value,并返回key的旧值
  328 + * @param String $key
  329 + * @param Mixed $val
  330 + * @return Mixed
  331 + */
  332 + public function getSet($key, $val)
  333 + {
  334 + assert(is_string($key));
  335 + return $this->redis->getSet($key, $val);
  336 + }
  337 +
  338 + /**
  339 + *
  340 + * 返回key所储存的字符串值的长度
  341 + * @param String $key
  342 + * @return integer
  343 + */
  344 + public function strlen($key)
  345 + {
  346 + return $this->redis->strlen($key);
  347 + }
  348 +
  349 + /**
  350 + *
  351 + * 将key中储存的数字值减一
  352 + * @param String $key
  353 + * @return Integer
  354 + */
  355 + public function decr($key)
  356 + {
  357 + assert(is_string($key));
  358 + return $this->redis->decr($key);
  359 + }
  360 +
  361 + /**
  362 + *
  363 + * 将key所储存的值减去减量decrement。
  364 + * @param String $key
  365 + * @param Integer $value
  366 + * @return intger
  367 + */
  368 + public function decrBy($key, $value = 1)
  369 + {
  370 + assert(is_string($key)) && assert(is_int($value));
  371 + return $this->redis->decrBy($key, $value);
  372 + }
  373 +
  374 + /**
  375 + *
  376 + * 将key中储存的数字值增一
  377 + * @param String $key
  378 + * @param Integer $val
  379 + * @return Integer
  380 + */
  381 + public function incrBy($key, $val = 1)
  382 + {
  383 + return $this->redis->incrBy($key, $val);
  384 + }
  385 +
  386 + /**
  387 + *
  388 + * 同时将多个field - value(域-值)对设置到哈希表key中
  389 + * @param String $key
  390 + * @param array $vals
  391 + * @return bool
  392 + */
  393 + public function hMset($hashKey, array $keys)
  394 + {
  395 + assert(is_string($hashKey));
  396 + return $this->redis->hMset($hashKey, $keys);
  397 + }
  398 +
  399 + /**
  400 + *
  401 + * 返回哈希表key中,一个或多个给定域的值
  402 + * @param String $hashKey
  403 + * @param array $keys
  404 + * @return Mixed
  405 + */
  406 + public function hmGet($hashKey, array $keys)
  407 + {
  408 + assert(is_string($hashKey));
  409 + return $this->redis->hmGet($hashKey, $keys);
  410 + }
  411 +
  412 + /**
  413 + *
  414 + * 返回哈希表key中,所有的域和值
  415 + * @param String $hashKey
  416 + * @return Mixed
  417 + */
  418 + public function hGetAll($hashKey)
  419 + {
  420 + assert(is_string($hashKey));
  421 + return $this->redis->hGetAll($hashKey);
  422 + }
  423 +
  424 + /**
  425 + *
  426 + * 删除哈希表key中的一个或多个指定域
  427 + * @param String $hashKey
  428 + * @return bool
  429 + */
  430 + public function hDel($hashKey, $hashKey2 = null, $hashKeyN = null)
  431 + {
  432 + $this->redis->hDel($hashKey, $hashKey2, $hashKeyN);
  433 + }
  434 +
  435 + /**
  436 + *
  437 + * 返回哈希表key中域的数量
  438 + * @param String $hashKey
  439 + * @return Integer
  440 + */
  441 + public function hLen($hashKey)
  442 + {
  443 + return $this->redis->hLen($hashKey);
  444 + }
  445 +
  446 + /**
  447 + *
  448 + * 查看哈希表key中,给定域field是否存在
  449 + * @param String $hashKey
  450 + * @return bool
  451 + */
  452 + public function hExists($key, $hashKey)
  453 + {
  454 + return $this->redis->hExists($key, $hashKey);
  455 + }
  456 +
  457 + /**
  458 + *
  459 + * 为哈希表key中的域field的值加上增量increment。
  460 + * @param String $hashKey
  461 + * @param String $key
  462 + * @param Integer $member
  463 + * @return Integer
  464 + */
  465 + public function hincrby($hashKey, $key, $member)
  466 + {
  467 + return $this->redis->hIncrBy($hashKey, $key, $member);
  468 + }
  469 +
  470 + /**
  471 + *
  472 + * 返回哈希表key中的所有域
  473 + * @param String $hashKey
  474 + * @return array
  475 + */
  476 + public function hKeys($hashKey)
  477 + {
  478 + return $this->redis->hKeys($hashKey);
  479 + }
  480 +
  481 + /**
  482 + *
  483 + * 返回哈希表key中的所有值
  484 + * @param String $hashKey
  485 + * @return Array
  486 + */
  487 + public function hVals($hashKey)
  488 + {
  489 + return $this->redis->hVals($hashKey);
  490 + }
  491 + ###########################
  492 + # 表 List
  493 + ###########################
  494 + /**
  495 + *
  496 + * 将值value插入到列表key的表头
  497 + * @param String $key
  498 + * @param Mixed $value
  499 + * @return bool
  500 + */
  501 + public function lPush($key, $value)
  502 + {
  503 + assert(is_string($key));
  504 + return $this->redis->lPush($key, $value);
  505 + }
  506 +
  507 + /**
  508 + *
  509 + * 将值value插入到列表key的表头,当且仅当key存在并且是一个列表
  510 + * @param String $key
  511 + * @param Mixed $value
  512 + * @return bool
  513 + */
  514 + public function lPushx($key, $value)
  515 + {
  516 + assert(is_string($key));
  517 + return $this->redis->lPushx($key, $value);
  518 + }
  519 +
  520 + /**
  521 + *
  522 + * 将值value插入到列表key的表尾
  523 + * @param String $key
  524 + * @param Mixed $value
  525 + * @return bool
  526 + */
  527 + public function rPush($key, $value)
  528 + {
  529 + assert(is_string($key));
  530 + return $this->redis->rPush($key, $value);
  531 + }
  532 +
  533 + /**
  534 + *
  535 + * 将值value插入到列表key的表尾,当且仅当key存在并且是一个列表
  536 + * @param String $key
  537 + * @param Mixed $value
  538 + * @return bool
  539 + */
  540 + public function rPushx($key, $value)
  541 + {
  542 + assert(is_string($key));
  543 + return $this->redis->rPushx($key, $value);
  544 + }
  545 +
  546 + /**
  547 + *
  548 + * 移除并返回列表key的头元素
  549 + * @param String $key
  550 + * @return bool or nil
  551 + */
  552 + public function lPop($key)
  553 + {
  554 + return $this->redis->lPop($key);
  555 + }
  556 +
  557 + /**
  558 + *
  559 + * 移除并返回列表key的尾元素
  560 + * @param String $key
  561 + * @return bool or nil
  562 + */
  563 + public function rPop($key)
  564 + {
  565 + return $this->redis->rPop($key);
  566 + }
  567 +
  568 + /**
  569 + *
  570 + * BLPOP是列表的阻塞式(blocking)弹出原语
  571 + * ===================================
  572 + * 类似 Gearman 等待移除
  573 + * ===================================
  574 + * @param array $keys
  575 + * @param Integer $timeout
  576 + * @return array
  577 + */
  578 + public function blPop(array $keys, $timeout = 2)
  579 + {
  580 + return $this->redis->blPop($keys, (int)$timeout);
  581 + }
  582 +
  583 + /**
  584 + *
  585 + * BRPOP是列表的阻塞式(blocking)弹出原语。
  586 + * ===================================
  587 + * 类似 Gearman 等待移除
  588 + * ===================================
  589 + * @param array $keys
  590 + * @param Integer $timeout
  591 + *
  592 + */
  593 + public function brPop(array $keys, $timeout = 2)
  594 + {
  595 + return $this->redis->brPop($keys, (int)$timeout);
  596 + }
  597 +
  598 + /**
  599 + * TODO
  600 + * 返回列表key的长度。
  601 + */
  602 + public function llen()
  603 + {
  604 +
  605 + }
  606 +
  607 + /**
  608 + *
  609 + * 返回列表key中指定区间内的元素,区间以偏移量start和stop指定。
  610 + * @param String $key
  611 + * @param Integer $start
  612 + * @param Integer $end
  613 + * @return array
  614 + */
  615 + public function lRange($key, $start = 0, $end = 0)
  616 + {
  617 + return $this->redis->lRange($key, (int)$start, (int)$end);
  618 + }
  619 +
  620 + /**
  621 + *
  622 + * 根据参数count的值,移除列表中与参数value相等的元素
  623 + * ============================================
  624 + * count的值可以是以下几种:
  625 + * count > 0: 从表头开始向表尾搜索,移除与value相等的元素,数量为count
  626 + * count < 0: 从表尾开始向表头搜索,移除与value相等的元素,数量为count的绝对值
  627 + * count = 0: 移除表中所有与value相等的值
  628 + * ============================================
  629 + * @param String $key
  630 + * @param String $value
  631 + * @param Integer $count
  632 + * @return Integer
  633 + */
  634 + public function lRem($key, $value, $count)
  635 + {
  636 + $this->redis->lRem((string)$key, (string)$value, (int)$count);
  637 + }
  638 +
  639 + /**
  640 + *
  641 + * 将列表key下标为index的元素的值甚至为value
  642 + * (当index参数超出范围,或对一个空列表(key不存在)进行LSET时,返回一个错误)
  643 + * @param String $key
  644 + * @param Integer $index
  645 + * @param String $value
  646 + * @return bool
  647 + */
  648 + public function lSet($key, $index, $value)
  649 + {
  650 + return $this->redis->lSet((string)$key, (int)$index, (string)$value);
  651 + }
  652 +
  653 + /**
  654 + *
  655 + * 对一个列表进行修剪(trim),就是说,让列表只保留指定区间内的元素,不在指定区间之内的元素都将被删除
  656 + * @param String $key
  657 + * @param Integer $start
  658 + * @param Integer $stop
  659 + * @return bool
  660 + */
  661 + public function lTrim($key, $start, $stop)
  662 + {
  663 + return $this->redis->lTrim((string)$key, (int)$start, (int)$stop);
  664 + }
  665 +
  666 + /**
  667 + *
  668 + * 返回列表key中,下标为index的元素
  669 + * @param String $key
  670 + * @param Integer $index
  671 + * @return bool or nil
  672 + */
  673 + public function lGet($key, $index)
  674 + {
  675 + return $this->redis->lGet((string)$key, (int)$index);
  676 + }
  677 +
  678 + ##################################################################
  679 + # SET
  680 + ##################################################################
  681 + /**
  682 + *
  683 + * 将一个或多个member元素加入到集合key当中,已经存在于集合的member元素将被忽略
  684 + * @param String $key
  685 + * @param Mixed $value
  686 + * @return bool
  687 + */
  688 + public function sAdd($skey, $value)
  689 + {
  690 + return $this->redis->sAdd($skey, $value);
  691 + }
  692 +
  693 + /**
  694 + *
  695 + * ( 扩展 ) 将一个或多个member元素加入到集合key当中,已经存在于集合的member元素将被忽略
  696 + * @param String $key
  697 + * @param Mixed $value
  698 + * @param Integer $expiration
  699 + * @return bool
  700 + */
  701 + public function sAdd2($skey, $value, $expiration = 0)
  702 + {
  703 + $result = $this->redis->sAdd($skey, $value);
  704 + $this->redis->setTimeout($skey, $expiration);
  705 + return $result;
  706 + }
  707 +
  708 + /**
  709 + *
  710 + * 移除集合key中的一个或多个member元素,不存在的member元素会被忽略
  711 + * @param String $key
  712 + * @param String $member
  713 + * @return bool
  714 + */
  715 + public function sRem($skey, $member)
  716 + {
  717 + return $this->redis->sRem((string)$skey, (string)$member);
  718 + }
  719 +
  720 + /**
  721 + *
  722 + * 返回集合key中的所有成员
  723 + * @param String $key
  724 + * @return array
  725 + */
  726 + public function sMembers($skey)
  727 + {
  728 + return $this->redis->sMembers((string)$skey);
  729 + }
  730 +
  731 + /**
  732 + *
  733 + * 判断member元素是否是集合key的成员
  734 + * @param String $key
  735 + * @param String $value
  736 + */
  737 + public function sIsMember($skey, $value)
  738 + {
  739 + return $this->redis->sIsMember((string)$skey, (string)$value);
  740 + }
  741 +
  742 + /**
  743 + *
  744 + * 返回集合key的基数(集合中元素的数量)
  745 + * @param String $skey
  746 + * @return Integer
  747 + */
  748 + public function sCard($skey)
  749 + {
  750 + return $this->redis->sCard((string)$skey);
  751 + }
  752 +
  753 + /**
  754 + *
  755 + * 将member元素从source集合移动到destination集合
  756 + * @param String $srcKey
  757 + * @param String $dstKey
  758 + * @param String $member
  759 + * @return bool
  760 + */
  761 + public function sMove($srcKey, $dstKey, $member)
  762 + {
  763 + return $this->redis->sMove((string)$srcKey, (string)$dstKey, (string)$member);
  764 + }
  765 +
  766 + /**
  767 + *
  768 + * 移除并返回集合中的一个随机元素
  769 + * @param String $skey
  770 + * @return string or bool
  771 + */
  772 + public function sPop($skey)
  773 + {
  774 + return $this->redis->sPop((string)$skey);
  775 + }
  776 +
  777 + /**
  778 + *
  779 + * 返回集合中的一个随机元素。
  780 + * @param String $skey
  781 + * @return array or nil
  782 + */
  783 + public function sRandMember($skey)
  784 + {
  785 + return $this->redis->sRandMember((string)$skey);
  786 + }
  787 +
  788 + ########################################################
  789 + # 有序集(Sorted Set)
  790 + ########################################################
  791 + /**
  792 + *
  793 + * 将一个或多个member元素及其score值加入到有序集key当中
  794 + * @param String $zKey
  795 + * @param Integer $score
  796 + * @param String $value
  797 + * @return Integer
  798 + */
  799 + public function zAdd($zKey, $score, $value)
  800 + {
  801 + assert(is_string($zKey)) && assert(is_int($score)) && assert(is_string($value));
  802 + return $this->redis->zAdd($zKey, $score, $value);
  803 + }
  804 +
  805 + /**
  806 + *
  807 + * 移除有序集key中的一个或多个成员,不存在的成员将被忽略
  808 + * @param String $zKey
  809 + * @param String $member
  810 + * @return Integer
  811 + */
  812 + public function zRem($zKey, $member)
  813 + {
  814 + return $this->redis->zRem((string)$zKey, (string)$member);
  815 + }
  816 +
  817 + /**
  818 + *
  819 + * 返回有序集key的基数
  820 + * @param String $zKey
  821 + * @return Integer
  822 + */
  823 + public function zSize($zKey)
  824 + {
  825 + return $this->redis->zSize((string)$zKey);
  826 + }
  827 +
  828 + /**
  829 + *
  830 + * 返回有序集key中,score值在min和max之间(默认包括score值等于min或max)的成员
  831 + * @param String $zKey
  832 + * @param Integer $start
  833 + * @param Integer $end
  834 + * @return array
  835 + */
  836 + public function zCount($zKey, $start, $end)
  837 + {
  838 + return $this->redis->zCount($zKey, $start, $end);
  839 + }
  840 +
  841 + /**
  842 + *
  843 + * 返回有序集key中,成员member的score值
  844 + * @param String $zKey
  845 + * @param String $member
  846 + * @return String
  847 + */
  848 + public function zScore($zKey, $member)
  849 + {
  850 + return $this->redis->zScore($zKey, $member);
  851 + }
  852 +
  853 + /**
  854 + *
  855 + * 为有序集key的成员member的score值加上增量increment
  856 + * @param String $zKey
  857 + * @param Integer $value
  858 + * @param String $member
  859 + * @return Integer
  860 + */
  861 + public function zIncrBy($zKey, $value, $member)
  862 + {
  863 + return $this->redis->zIncrBy($zKey, $value, $member);
  864 + }
  865 +
  866 + /**
  867 + *
  868 + * 返回有序集key中,指定区间内的成员
  869 + * @param String $zKey
  870 + * @param Integer $start
  871 + * @param Integer $end
  872 + * @param bool $withscores
  873 + * @return bool ( 默认False无键值/True有键值 )
  874 + */
  875 + public function zRange($zKey, $start, $end, $withscores = false)
  876 + {
  877 + return $this->redis->zRange($zKey, $start, $end, $withscores);
  878 + }
  879 +
  880 + /**
  881 + *
  882 + * 返回有序集key中,指定区间内的成员
  883 + * 其中成员的位置按score值递减(从大到小)来排列
  884 + * @param String $zKey
  885 + * @param Integer $start
  886 + * @param Integer $end
  887 + * @param bool $withscores
  888 + * @return bool ( 默认False无键值/True有键值 )
  889 + */
  890 + public function zRevRange($zKey, $start, $end, $withscores = false)
  891 + {
  892 + return $this->redis->zRevRange($zKey, $start, $end, $withscores);
  893 + }
  894 +
  895 + /**
  896 + *
  897 + * 返回有序集key中,所有score值介于min和max之间(包括等于min或max)的成员。有序集成员按score值递增(从小到大 or 从大到小)次序排列
  898 + * @param String $zKey
  899 + * @param Integer $start
  900 + * @param Integer $end
  901 + * @param array $options
  902 + * @return array
  903 + * =========================================================
  904 + * $redis->zRangeByScore('key', 0, 3);
  905 + * array('val0', 'val2')
  906 + * $redis->zRangeByScore('key', 0, 3, array('withscores' => TRUE);
  907 + * array('val0' => 0, 'val2' => 2)
  908 + * $redis->zRangeByScore('key', 0, 3, array('limit' => array(1, 1));
  909 + * array('val2' => 2)
  910 + * $redis->zRangeByScore('key', 0, 3, array('limit' => array(1, 1));
  911 + * array('val2')
  912 + * $redis->zRangeByScore('key', 0, 3, array('withscores' => TRUE, 'limit' => array(1, 1));
  913 + * array('val2' => 2)
  914 + * =========================================================
  915 + *
  916 + */
  917 + public function zRangeByScore($zKey, $start, $end, array $options)
  918 + {
  919 + return $this->redis->zRangeByScore($zKey, $start, $end, $options);
  920 + }
  921 +
  922 + /**
  923 + *
  924 + * 返回有序集key中成员member的排名。其中有序集成员按score值递增(从小到大 or 从大到小)顺序排列
  925 + * @param String $zKey
  926 + * @param String $member
  927 + * @param String $order ( desc or asc )
  928 + * @return array
  929 + */
  930 + public function zRank($zKey, $member, $order = 'desc')
  931 + {
  932 + return $order == 'desc' ? $this->redis->zRank($zKey, $member) : $this->redis->zRevRank($zKey, $member);
  933 + }
  934 +
  935 + /**
  936 + * 移除有序集key中,指定排名(rank)区间内的所有成员
  937 + * 区间分别以下标参数start和stop指出,包含start和stop在内
  938 + * @param String $zKey
  939 + * @param Integer $start
  940 + * @param Integer $end
  941 + * @return Integer
  942 + */
  943 + public function zRemRangeByRank($zKey, $start, $end)
  944 + {
  945 + return $this->redis->zRemRangeByRank($zKey, $start, $end);
  946 + }
  947 +
  948 + public function tag($tagName)
  949 + {
  950 + }
  951 +
  952 + /**
  953 + * 移除有序集key中,指定(socre)区间内的所有成员
  954 + * 区间分别以下标参数start和stop指出,包含start和stop在内
  955 + * @param String $zKey
  956 + * @param Integer $start
  957 + * @param Integer $end
  958 + * @return Integer
  959 + */
  960 + public function zRemRangeByScore($zKey, $start, $end)
  961 + {
  962 + return $this->redis->zRemRangeByScore($zKey, $start, $end);
  963 + }
  964 +
  965 + public function zRevRangeByScore($zkey, $start, $end, array $options)
  966 + {
  967 + return $this->redis->zRevRangeByScore($zkey, $start, $end, $options);
  968 + }
  969 +
  970 + /**
  971 + * 发布消息
  972 + *
  973 + * @param String $channel
  974 + * @param String $message
  975 + * @return Integer
  976 + */
  977 + public function publish($channel, $message)
  978 + {
  979 + return $this->redis->publish($channel, $message);
  980 + }
  981 +
  982 + /**
  983 + * 订阅消息
  984 + * @param String $channel
  985 + * @return String
  986 + */
  987 + public function subscribe(array $channel, $callback)
  988 + {
  989 + return $this->redis->subscribe($channel, $callback);
  990 + }
  991 +
  992 + /**
  993 + * 退订
  994 + * @param String $channel
  995 + */
  996 + public function unsubscribe($channel)
  997 + {
  998 + return $this->redis->unsubscribe($channel);
  999 + }
  1000 +
  1001 + /**
  1002 + * 按照模式匹配订阅多个频道
  1003 + *
  1004 + * @param String $pattern (如:news.* 可订阅news.开头的所有频道)
  1005 + */
  1006 + public function psubscribe($pattern, $callback)
  1007 + {
  1008 + return $this->redis->psubscribe($pattern, $callback);
  1009 + }
  1010 +
  1011 + /**
  1012 + * 退订给定模式的所有渠道
  1013 + *
  1014 + * @param String $pattern
  1015 + */
  1016 + public function punsubscribe($pattern)
  1017 + {
  1018 + return $this->redis->punsubscribe($pattern);
  1019 + }
  1020 +
  1021 + public function pubsub($pattern)
  1022 + {
  1023 + return $this->redis->pubsub($pattern);
  1024 + }
  1025 +}
  1 +<?php
  2 +
  3 +namespace Hood\Cache;
  4 +
  5 +use Hood\Core\Root;
  6 +use Yaf\Exception;
  7 +
  8 +/**
  9 + * Description of cache
  10 + *
  11 + * @author 13011908
  12 + */
  13 +class FileCache extends Root implements CacheInterface
  14 +{
  15 +
  16 + const DEFAULT_EXPIRE = 3600;
  17 +
  18 + protected static $default = 'file';
  19 + protected static $instances = array();
  20 + protected $_cache_dir;
  21 + protected $_tag = null;
  22 +
  23 + private $section = 'file';
  24 + private $node = 'cache';
  25 +
  26 + public function __construct($childNode = null, $node = 'cache', $cachePath = null)
  27 + {
  28 + if ($cachePath == null) {
  29 + $server = $this->getServerHost('cache');
  30 + $this->node = ($node == null ? 'cache' : $node);
  31 + $_pathList = $cachePath = $server->getServerConfig($this->section, $this->node);
  32 + if ($childNode == null && is_array($cachePath)) {
  33 + $cachePath = (sys_get_temp_dir() . 'cached' . DIRECTORY_SEPARATOR);
  34 + } else {
  35 + $cachePath = $_pathList[$childNode];
  36 + }
  37 + }
  38 + $this->initFileInfo($cachePath);
  39 + }
  40 +
  41 + private function initFileInfo($directory)
  42 + {
  43 + try {
  44 + $this->_cache_dir = new \SplFileInfo($directory);
  45 + } // PHP < 5.3 exception handle
  46 + catch (ErrorException $e) {
  47 + $this->_cache_dir = $this->_make_directory($directory, 0777, TRUE);
  48 + } // PHP >= 5.3 exception handle
  49 + catch (UnexpectedValueException $e) {
  50 + $this->_cache_dir = $this->_make_directory($directory, 0777, TRUE);
  51 + }
  52 +
  53 + // If the defined directory is a file, get outta here
  54 + if ($this->_cache_dir->isFile()) {
  55 + throw new Exception('Unable to create cache directory as a file already exists : ' . $this->_cache_dir->getRealPath());
  56 + }
  57 +
  58 + if (!$this->_cache_dir->isDir()) {
  59 + $this->_cache_dir = $this->_make_directory($directory, 0777, TRUE);
  60 + }
  61 +
  62 + // Check the read status of the directory
  63 + if (!$this->_cache_dir->isReadable()) {
  64 + throw new Exception('Unable to read from the cache directory ' . $this->_cache_dir->getRealPath());
  65 + }
  66 +
  67 + // Check the write status of the directory
  68 + if (!$this->_cache_dir->isWritable()) {
  69 + throw new Exception('Unable to write to the cache directory ' . $this->_cache_dir->getRealPath());
  70 + }
  71 + }
  72 +
  73 + public function add($key, $value, $minutes)
  74 + {
  75 + }
  76 +
  77 + public function increment($key, $value = 1)
  78 + {
  79 + $tag = $this->_tag;
  80 + if ($get = $this->get($key)) {
  81 + if (preg_match('/^\d+$/', $get)) {
  82 + $value = intval($get) + $value;
  83 + } else {
  84 + return false;
  85 + }
  86 + }
  87 + if ($tag) {
  88 + $this->tag($tag);
  89 + }
  90 + return $this->set($key, $value);
  91 + }
  92 +
  93 + public function decrement($key, $value = 1)
  94 + {
  95 + $tag = $this->_tag;
  96 + if ($get = $this->get($key)) {
  97 + if (preg_match('/^\d+$/', $get)) {
  98 + $value = intval($get) - $value;
  99 + } else {
  100 + return false;
  101 + }
  102 + }
  103 + if ($tag) {
  104 + $this->tag($tag);
  105 + }
  106 + return $this->set($key, $value);
  107 + }
  108 +
  109 + public function tag($tagName = null)
  110 + {
  111 + if ($tagName) {
  112 + $this->_tag = md5($tagName);
  113 + return $this;
  114 + } elseif (!empty($this->_tag)) {
  115 + $tag = $this->_tag;
  116 + unset($this->_tag);
  117 + return $tag . DIRECTORY_SEPARATOR;
  118 + } else {
  119 + return '';
  120 + }
  121 + }
  122 +
  123 + public static function instance($group = NULL)
  124 + {
  125 + // If there is no group supplied
  126 + if ($group === NULL) {
  127 + // Use the default setting
  128 + $group = self::$default;
  129 + }
  130 +
  131 + if (isset(self::$instances[$group])) {
  132 + // Return the current group if initiated already
  133 + return self::$instances[$group];
  134 + }
  135 + // Create a new cache type instance
  136 + self::$instances[$group] = new self();
  137 + // Return the instance
  138 + return self::$instances[$group];
  139 + }
  140 +
  141 + /**
  142 + * Retrieve a cached value entry by id.
  143 + *
  144 + * // Retrieve cache entry from file group
  145 + * $data = self::instance('file')->get('foo');
  146 + *
  147 + * // Retrieve cache entry from file group and return 'bar' if miss
  148 + * $data = self::instance('file')->get('foo', 'bar');
  149 + *
  150 + * @param string id of cache to entry
  151 + * @param string default value to return if cache miss
  152 + * @return mixed
  153 + * @throws Cache_Exception
  154 + */
  155 + public function get($id, $default = NULL)
  156 + {
  157 + $filename = self::filename($this->_sanitize_id($id));
  158 + $directory = $this->_resolve_directory($filename);
  159 +
  160 + // Wrap operations in try/catch to handle notices
  161 + try {
  162 + // Open file
  163 + $file = new \SplFileInfo($directory . $filename);
  164 +
  165 + // If file does not exist
  166 + if (!$file->isFile()) {
  167 + // Return default value
  168 + return $default;
  169 + } else {
  170 + // Open the file and parse data
  171 + $created = $file->getMTime();
  172 + $data = $file->openFile();
  173 + $lifetime = $data->fgets();
  174 +
  175 + // If we're at the EOF at this point, corrupted!
  176 + if ($data->eof()) {
  177 + return false;
  178 + throw new Exception(__METHOD__ . ' corrupted cache file!');
  179 + }
  180 +
  181 + $cache = '';
  182 +
  183 + while ($data->eof() === FALSE) {
  184 + $cache .= $data->fgets();
  185 + }
  186 +
  187 + // Test the expiry
  188 + if (($created + (int)$lifetime) < time()) {
  189 + // Delete the file
  190 + $this->_delete_file($file, NULL, TRUE);
  191 + return $default;
  192 + } else {
  193 + return unserialize($cache);
  194 + }
  195 + }
  196 + } catch (ErrorException $e) {
  197 + // Handle ErrorException caused by failed unserialization
  198 + if ($e->getCode() === E_NOTICE) {
  199 + throw new Exception(__METHOD__ . ' failed to unserialize cached object with message : ' . $e->getMessage());
  200 + }
  201 +
  202 + // Otherwise throw the exception
  203 + throw $e;
  204 + }
  205 + }
  206 +
  207 + /**
  208 + * Set a value to cache with id and lifetime
  209 + *
  210 + * $data = 'bar';
  211 + *
  212 + * // Set 'bar' to 'foo' in file group, using default expiry
  213 + * self::instance('file')->set('foo', $data);
  214 + *
  215 + * // Set 'bar' to 'foo' in file group for 30 seconds
  216 + * self::instance('file')->set('foo', $data, 30);
  217 + *
  218 + * @param string id of cache entry
  219 + * @param string data to set to cache
  220 + * @param integer lifetime in seconds
  221 + * @return boolean
  222 + */
  223 + public function set($id, $data, $lifetime = NULL)
  224 + {
  225 + $filename = self::filename($this->_sanitize_id($id));
  226 + $directory = $this->_resolve_directory($filename);
  227 + // If lifetime is NULL
  228 + if ($lifetime === NULL) {
  229 + // Set to the default expiry
  230 + $lifetime = self::DEFAULT_EXPIRE;
  231 + }
  232 +
  233 + // Open directory
  234 + $dir = new \SplFileInfo($directory);
  235 +
  236 + // If the directory path is not a directory
  237 + if (!$dir->isDir()) {
  238 + // Create the directory
  239 + if (!mkdir($directory, 0777, TRUE)) {
  240 + throw new Exception(__METHOD__ . ' unable to create directory : ' . $directory);
  241 + }
  242 +
  243 + // chmod to solve potential umask issues
  244 + chmod($directory, 0777);
  245 + }
  246 +
  247 + // Open file to inspect
  248 + $resouce = new \SplFileInfo($directory . $filename);
  249 + $file = $resouce->openFile('w');
  250 +
  251 + try {
  252 + $data = $lifetime . "\n" . serialize($data);
  253 + $file->fwrite($data, strlen($data));
  254 + return (bool)$file->fflush();
  255 + } catch (ErrorException $e) {
  256 + // If serialize through an error exception
  257 + if ($e->getCode() === E_NOTICE) {
  258 + // Throw a caching error
  259 + throw new Exception(__METHOD__ . ' failed to serialize data for caching with message : ' . $e->getMessage());
  260 + }
  261 +
  262 + // Else rethrow the error exception
  263 + throw $e;
  264 + }
  265 + }
  266 +
  267 + protected static function filename($string)
  268 + {
  269 + return sha1($string) . '.cache';
  270 + }
  271 +
  272 + /**
  273 + * Delete a cache entry based on id
  274 + *
  275 + * // Delete 'foo' entry from the file group
  276 + * self::instance('file')->delete('foo');
  277 + *
  278 + * @param string id to remove from cache
  279 + * @return boolean
  280 + */
  281 + public function delete($id)
  282 + {
  283 + $filename = self::filename($this->_sanitize_id($id));
  284 + $directory = $this->_resolve_directory($filename);
  285 +
  286 + return $this->_delete_file(new \SplFileInfo($directory . $filename), NULL, TRUE);
  287 + }
  288 +
  289 + /**
  290 + * Delete all cache entries.
  291 + *
  292 + * Beware of using this method when
  293 + * using shared memory cache systems, as it will wipe every
  294 + * entry within the system for all clients.
  295 + *
  296 + * // Delete all cache entries in the file group
  297 + * self::instance('file')->delete_all();
  298 + *
  299 + * @return boolean
  300 + */
  301 + public function delete_all()
  302 + {
  303 + return $this->_delete_file($this->_cache_dir, TRUE);
  304 + }
  305 +
  306 + protected function _delete_file(\SplFileInfo $file, $retain_parent_directory = FALSE, $ignore_errors = FALSE, $only_expired = FALSE)
  307 + {
  308 + // Allow graceful error handling
  309 + try {
  310 + // If is file
  311 + if ($file->isFile()) {
  312 + try {
  313 + if ($only_expired === FALSE) {
  314 + // We want to delete the file
  315 + $delete = TRUE;
  316 + } // Otherwise...
  317 + else {
  318 + // Assess the file expiry to flag it for deletion
  319 + $json = $file->openFile('r')->current();
  320 + $data = json_decode($json);
  321 + $delete = $data->expiry < time();
  322 + }
  323 +
  324 + // If the delete flag is set delete file
  325 + if ($delete === TRUE)
  326 + return @unlink($file->getRealPath());
  327 + else
  328 + return FALSE;
  329 + } catch (ErrorException $e) {
  330 + // Catch any delete file warnings
  331 + if ($e->getCode() === E_WARNING) {
  332 + throw new Exception(__METHOD__ . ' failed to delete file : ' . $file->getRealPath());
  333 + }
  334 + }
  335 + } // Else, is directory
  336 + elseif ($file->isDir()) {
  337 + // Create new DirectoryIterator
  338 + $files = new DirectoryIterator($file->getPathname());
  339 +
  340 + // Iterate over each entry
  341 + while ($files->valid()) {
  342 + // Extract the entry name
  343 + $name = $files->getFilename();
  344 +
  345 + // If the name is not a dot
  346 + if ($name != '.' AND $name != '..') {
  347 + // Create new file resource
  348 + $fp = new \SplFileInfo($files->getRealPath());
  349 + // Delete the file
  350 + $this->_delete_file($fp);
  351 + }
  352 +
  353 + // Move the file pointer on
  354 + $files->next();
  355 + }
  356 +
  357 + // If set to retain parent directory, return now
  358 + if ($retain_parent_directory) {
  359 + return TRUE;
  360 + }
  361 +
  362 + try {
  363 + // Remove the files iterator
  364 + // (fixes Windows PHP which has permission issues with open iterators)
  365 + unset($files);
  366 +
  367 + // Try to remove the parent directory
  368 + return rmdir($file->getRealPath());
  369 + } catch (ErrorException $e) {
  370 + // Catch any delete directory warnings
  371 + if ($e->getCode() === E_WARNING) {
  372 + throw new Exception(__METHOD__ . ' failed to delete directory : ' . $file->getRealPath());
  373 + }
  374 + throw $e;
  375 + }
  376 + } else {
  377 + // We get here if a file has already been deleted
  378 + return FALSE;
  379 + }
  380 + } // Catch all exceptions
  381 + catch (Exception $e) {
  382 + // If ignore_errors is on
  383 + if ($ignore_errors === TRUE) {
  384 + // Return
  385 + return FALSE;
  386 + }
  387 + // Throw exception
  388 + throw $e;
  389 + }
  390 + }
  391 +
  392 + protected function _resolve_directory($filename)
  393 + {
  394 + return $this->_cache_dir->getRealPath() . DIRECTORY_SEPARATOR . $this->tag() . $filename[0] . $filename[1] . DIRECTORY_SEPARATOR;
  395 + }
  396 +
  397 + protected function _sanitize_id($id)
  398 + {
  399 + // Change slashes and spaces to underscores
  400 + return str_replace(array('/', '\\', ' '), '_', $id);
  401 + }
  402 +
  403 + /**
  404 + * Makes the cache directory if it doesn't exist. Simply a wrapper for
  405 + * `mkdir` to ensure DRY principles
  406 + *
  407 + * @see http://php.net/manual/en/function.mkdir.php
  408 + * @param string directory
  409 + * @param string mode
  410 + * @param string recursive
  411 + * @param string context
  412 + * @return \SplFileInfo
  413 + * @throws Cache_Exception
  414 + */
  415 + protected function _make_directory($directory, $mode = 0777, $recursive = FALSE, $context = NULL)
  416 + {
  417 + if (!mkdir($directory, $mode, $recursive)) {
  418 + throw new Exception('Failed to create the defined cache directory : ' . $directory);
  419 + }
  420 + chmod($directory, $mode);
  421 +
  422 + return new \SplFileInfo($directory);;
  423 + }
  424 +
  425 + /**
  426 + * Garbage collection method that cleans any expired
  427 + * cache entries from the cache.
  428 + *
  429 + * @return void
  430 + */
  431 + public function garbage_collect()
  432 + {
  433 + $this->_delete_file($this->_cache_dir, TRUE, FALSE, TRUE);
  434 + return;
  435 + }
  436 +
  437 +}
  1 +<?php
  2 +/**
  3 + * Created by PhpStorm.
  4 + * User: Zip
  5 + * Date: 15/4/28
  6 + * Time: 下午3:16
  7 + */
  8 +
  9 +namespace Hood\Cache;
  10 +
  11 +use Hood\Core\Root;
  12 +
  13 +class Memcache extends Root implements CacheInterface
  14 +{
  15 + private $mcInstances = array();
  16 +
  17 + private $persistentIDs = array();
  18 +
  19 + private $section = 'memcached';
  20 +
  21 + private $node = 'servers';
  22 +
  23 + private $tagName = '';
  24 +
  25 + private $prefix = '';
  26 +
  27 + private $persistentID = 'hood.cache';
  28 +
  29 + private $childNodes = 'hosts';
  30 +
  31 + public function __construct($prefix = '', $persistentID = 'hood.cache')
  32 + {
  33 + parent::__construct();
  34 + $this->prefix = $prefix;
  35 + $this->persistentIDs[] = $this->persistentID = $persistentID;
  36 + }
  37 +
  38 + public function init()
  39 + {
  40 + if (isset($this->mcInstances[$this->persistentID])) {
  41 + $mc = $this->mcInstances[$this->persistentID];
  42 + } else {
  43 + $instance = new \Memcache();
  44 + $server = $this->getServerHost('cache');
  45 + $_serverHosts = $server->getServerConfig($this->section, $this->node);
  46 + $mcServers = $this->_makeHosts($server->getServer($_serverHosts[$this->childNodes], 2));
  47 + foreach ($mcServers as $key => $val) {
  48 + $weight = 100;
  49 + if (count($val) == 3) {
  50 + list($host, $port, $weight) = $val;
  51 + } else {
  52 + list($host, $port) = $val;
  53 + }
  54 + $instance->addServer($host, $port, $this->persistentID, $weight);
  55 + }
  56 + $this->mcInstances[$this->persistentID] = $mc = $instance;
  57 + }
  58 + return $mc;
  59 + }
  60 +
  61 + /**
  62 + * 组织host
  63 + * @param array $hosts
  64 + * @return array
  65 + */
  66 + private function _makeHosts(array $hosts)
  67 + {
  68 + $_server = array();
  69 + foreach ($hosts as $key => $val) {
  70 + $_server[] = explode(':', $val);
  71 + }
  72 + return $_server;
  73 + }
  74 +
  75 + /**
  76 + * 设置mc配置的块节点
  77 + * @param $node
  78 + * @return $this
  79 + */
  80 + public function setNode($node = null)
  81 + {
  82 + if ($node != null) $this->node = $node;
  83 + return $this;
  84 + }
  85 +
  86 + /**
  87 + * 设置子节点
  88 + * @param $childNode
  89 + * @return $this
  90 + */
  91 + public function setChildNodes($childNode)
  92 + {
  93 + $this->childNodes = $childNode;
  94 + return $this;
  95 + }
  96 +
  97 + /**
  98 + * 构建tag
  99 + * @param bool $mode
  100 + * @return string
  101 + */
  102 + private function _makeTag($mode = false)
  103 + {
  104 + if (empty($this->tagName)) return '';
  105 + $_tagVal = $this->init()->get($this->tagName);
  106 + if (empty($_tagVal) && $mode == true) {
  107 + $_tagVal = md5(microtime() . mt_rand() . uniqid());
  108 + $this->init()->set($this->tagName, $_tagVal, 0);
  109 + }
  110 + unset($this->tagName);
  111 + return empty($_tagVal) ? '' : $_tagVal . '.';
  112 + }
  113 +
  114 + /**
  115 + * 检索一个元素
  116 + * @param $key
  117 + * @param callable $flags
  118 + * @return mixed
  119 + */
  120 + public function get($key, &$flags = \MEMCACHE_COMPRESSED)
  121 + {
  122 + return $this->init()->get($this->_makeTag() . $key, $flags);
  123 + }
  124 +
  125 + /**
  126 + * 向一个新的key下面增加一个元素
  127 + * @param $key
  128 + * @param $value
  129 + * @param $expiration
  130 + * @return bool
  131 + */
  132 + public function add($key, $value, $expiration = 0)
  133 + {
  134 + return $this->init()->add($this->_makeTag(true) . $key, $value, $expiration);
  135 + }
  136 +
  137 +
  138 + /**
  139 + * 减小数值元素的值
  140 + * @param $key
  141 + * @param int $offset
  142 + * @return int
  143 + */
  144 + public function decrement($key, $offset = 1)
  145 + {
  146 + return $this->init()->decrement($this->_makeTag() . $key, $offset);
  147 + }
  148 +
  149 + /**
  150 + * @param $key
  151 + * @param int $time
  152 + * @return bool
  153 + */
  154 + public function delete($key, $time = 0)
  155 + {
  156 + return $this->init()->delete($this->_makeTag() . $key, $time);
  157 + }
  158 +
  159 +
  160 + /**
  161 + * 增加数值元素的值
  162 + * @param $key
  163 + * @param int $offset
  164 + * @param int $initialValue
  165 + * @param int $expiry
  166 + * @return int
  167 + */
  168 + public function increment($key, $offset = 1, $initialValue = 0, $expiry = 0)
  169 + {
  170 + return $this->init()->increment($this->_makeTag() . $key, $offset, $initialValue, $expiry);
  171 + }
  172 +
  173 +
  174 + /**
  175 + * 设置
  176 + * @param $key
  177 + * @param $value
  178 + * @param int $expiration
  179 + * @return bool
  180 + */
  181 + public function set($key, $var, $expire = 0, $flag = \MEMCACHE_COMPRESSED)
  182 + {
  183 + return $this->init()->set($this->_makeTag(true) . $key, $var, $flag, $expire);
  184 + }
  185 +
  186 + /**
  187 + * 设置tag
  188 + * @param $tagName
  189 + * @return $this
  190 + */
  191 + public function tag($tagName)
  192 + {
  193 + $this->tagName = $tagName;
  194 + return $this;
  195 + }
  196 +}
  1 +<?php
  2 +/**
  3 + * Created by PhpStorm.
  4 + * User: Zip
  5 + * Date: 14/11/23
  6 + * Time: 上午1:39
  7 + */
  8 +
  9 +namespace Hood\Cache;
  10 +
  11 +use Hood\Core\Root;
  12 +use Hood\Debug\DebugException;
  13 +
  14 +class Memcached extends Root implements CacheInterface
  15 +{
  16 + private $mcInstances = array();
  17 +
  18 + private $persistentIDs = array();
  19 +
  20 + private $timeout = 150;
  21 +
  22 + private $section = 'memcached';
  23 +
  24 + private $node = 'servers';
  25 +
  26 + private $tagName = '';
  27 +
  28 + private $prefix = '';
  29 +
  30 + private $persistentID = 'hood.cache';
  31 +
  32 + private $childNodes = 'hosts';
  33 +
  34 + public function __construct($prefix = '', $persistentID = 'hood.cache')
  35 + {
  36 + parent::__construct();
  37 + $this->prefix = $prefix;
  38 + $this->persistentIDs[] = $this->persistentID = $persistentID;
  39 + }
  40 +
  41 + /**
  42 + * 设置子节点
  43 + * @param $childNode
  44 + * @return $this
  45 + */
  46 + public function setChildNodes($childNode)
  47 + {
  48 + $this->childNodes = $childNode;
  49 + return $this;
  50 + }
  51 +
  52 + /**
  53 + * 设置前缀
  54 + * @param $prefix
  55 + * @return $this
  56 + */
  57 + public function setPrefix($prefix)
  58 + {
  59 + $this->prefix = $prefix;
  60 + return $this;
  61 + }
  62 +
  63 + /**
  64 + * 设置共享连接ID
  65 + * @param $persistentID
  66 + * @return $this
  67 + */
  68 + public function setPersistentID($persistentID)
  69 + {
  70 + $this->persistentID = $persistentID;
  71 + return $this;
  72 + }
  73 +
  74 + /**
  75 + * @param $persistentID
  76 + * @return \Memcached
  77 + * @throws \Hood\Debug\DebugException
  78 + */
  79 + private function init()
  80 + {
  81 + if (isset($this->mcInstances[$this->persistentID])) {
  82 + $mc = $this->mcInstances[$this->persistentID];
  83 + } else {
  84 + $instance = new \Memcached();
  85 + $instance->setOption(\Memcached::OPT_PREFIX_KEY, $this->prefix);
  86 + $instance->setOption(\Memcached::OPT_DISTRIBUTION, \Memcached::DISTRIBUTION_CONSISTENT); // 开启一致性哈希 取模(默认)/ 一致性
  87 + $instance->setOption(\Memcached::OPT_LIBKETAMA_COMPATIBLE, true);//ketama算法兼容 设置为md5并且分布算法将会 采用带有权重的一致性hash分布
  88 + $instance->setOption(\Memcached::OPT_CONNECT_TIMEOUT, $this->timeout);
  89 + if (count($instance->getServerList()) < 1) {
  90 + $server = $this->getServerHost('cache');
  91 + $_serverHosts = $server->getServerConfig($this->section, $this->node);
  92 + if (empty($_serverHosts[$this->childNodes])) {
  93 + throw new DebugException('Memcache Host Config is Null.');
  94 + }
  95 + $mcServers = $this->_makeHosts($server->getServer($_serverHosts[$this->childNodes], 2));
  96 + $instance->addServers($mcServers);
  97 + unset($mcServers);
  98 + }
  99 + $this->mcInstances[$this->persistentID] = $mc = $instance;
  100 + }
  101 + return $mc;
  102 + }
  103 +
  104 +
  105 + /**
  106 + * 设置mc配置的块
  107 + * @param $section
  108 + * @return $this
  109 + */
  110 + public function setSection($section)
  111 + {
  112 + $this->section = $section;
  113 + return $this;
  114 + }
  115 +
  116 + /**
  117 + * 设置mc配置的块节点
  118 + * @param $node
  119 + * @return $this
  120 + */
  121 + public function setNode($node = null)
  122 + {
  123 + if ($node != null) $this->node = $node;
  124 + return $this;
  125 + }
  126 +
  127 + /**
  128 + * 组织host
  129 + * @param array $hosts
  130 + * @return array
  131 + */
  132 + private function _makeHosts(array $hosts)
  133 + {
  134 + $_server = array();
  135 + foreach ($hosts as $key => $val) {
  136 + $_server[] = explode(':', $val);
  137 + }
  138 + return $_server;
  139 + }
  140 +
  141 + /**
  142 + * 构建tag
  143 + * @param bool $mode
  144 + * @return string
  145 + */
  146 + private function _makeTag($mode = false)
  147 + {
  148 + if (empty($this->tagName)) return '';
  149 + $_tagVal = $this->init()->get($this->tagName);
  150 + if (empty($_tagVal) && $mode == true) {
  151 + $_tagVal = md5(microtime() . mt_rand() . uniqid());
  152 + $this->init()->set($this->tagName, $_tagVal, 0);
  153 + }
  154 + unset($this->tagName);
  155 + return empty($_tagVal) ? '' : $_tagVal . '.';
  156 + }
  157 +
  158 + /**
  159 + * 检索一个元素
  160 + * @param $key
  161 + * @param callable $cache_cb
  162 + * @param float $cas_token
  163 + * @return mixed
  164 + */
  165 + public function get($key, $cacheCb = null, &$casToken = null)
  166 + {
  167 + return $this->init()->get($this->_makeTag() . $key, $cacheCb, $casToken);
  168 + }
  169 +
  170 + /**
  171 + * 向一个新的key下面增加一个元素
  172 + * @param $key
  173 + * @param $value
  174 + * @param $expiration
  175 + * @return bool
  176 + */
  177 + public function add($key, $value, $expiration = 0)
  178 + {
  179 + return $this->init()->add($this->_makeTag(true) . $key, $value, $expiration);
  180 + }
  181 +
  182 + /**
  183 + * 向已存在元素后追加数据
  184 + * @param $key
  185 + * @param $value
  186 + * @return bool
  187 + */
  188 + public function append($key, $value)
  189 + {
  190 + return $this->init()->append($this->_makeTag(true) . $key, $value);
  191 + }
  192 +
  193 + /**
  194 + * 比较并交换值
  195 + * @param $casToken
  196 + * @param $key
  197 + * @param $value
  198 + * @param int $expiration
  199 + * @return bool
  200 + */
  201 + public function cas($casToken, $key, $value, $expiration = 0)
  202 + {
  203 + return $this->init()->cas($casToken, $this->_makeTag(true) . $key, $value, $expiration);
  204 + }
  205 +
  206 + /**
  207 + * 减小数值元素的值
  208 + * @param $key
  209 + * @param int $offset
  210 + * @return int
  211 + */
  212 + public function decrement($key, $offset = 1)
  213 + {
  214 + return $this->init()->decrement($this->_makeTag() . $key, $offset);
  215 + }
  216 +
  217 + /**
  218 + * @param $key
  219 + * @param int $time
  220 + * @return bool
  221 + */
  222 + public function delete($key, $time = 0)
  223 + {
  224 + return $this->init()->delete($this->_makeTag() . $key, $time);
  225 + }
  226 +
  227 + /**
  228 + * 删除多个数据
  229 + * @param array $keys
  230 + * @param int $time
  231 + * @return bool
  232 + */
  233 + public function deleteMulti(array $keys, $time = 0)
  234 + {
  235 + return $this->init()->deleteMulti($this->_makeMultiKey($keys), $time);
  236 + }
  237 +
  238 + /**
  239 + * 组合多key 数据
  240 + * @param $keys
  241 + * @return array
  242 + */
  243 + private function _makeMultiKey($keys, $mode = false)
  244 + {
  245 + $_keys = array();
  246 + $tag = $this->_makeTag($mode);
  247 + foreach ($keys as $key) {
  248 + $_keys[] = $tag . $key;
  249 + }
  250 + return $_keys;
  251 + }
  252 +
  253 + /**
  254 + * 请求多个元素
  255 + * @param array $keys
  256 + * @param null $withCas
  257 + * @param callable $valueCb
  258 + * @return bool
  259 + */
  260 + public function getDelayed(array $keys, $withCas = null, callable $valueCb = null)
  261 + {
  262 + return $this->init()->getDelayed($this->_makeMultiKey($keys), $withCas, $valueCb);
  263 + }
  264 +
  265 + /**
  266 + * 抓取所有剩余的结果
  267 + * @return array
  268 + */
  269 + public function fetchAll()
  270 + {
  271 + return $this->init()->fetchAll();
  272 + }
  273 +
  274 + /**
  275 + * 检索多个元素
  276 + * @param array $keys
  277 + * @param array $cas_tokens
  278 + * @param null $flags
  279 + * @return mixed
  280 + */
  281 + public function getMulti(array $keys, array &$casTokens = null, $flags = null)
  282 + {
  283 + return $this->init()->getMulti($this->_makeMultiKey($keys), $casTokens, $flags);
  284 + }
  285 +
  286 + /**
  287 + * 增加数值元素的值
  288 + * @param $key
  289 + * @param int $offset
  290 + * @param int $initialValue
  291 + * @param int $expiry
  292 + * @return int
  293 + */
  294 + public function increment($key, $offset = 1, $initialValue = 0, $expiry = 0)
  295 + {
  296 + return $this->init()->increment($this->_makeTag() . $key, $offset, $initialValue, $expiry);
  297 + }
  298 +
  299 + /**
  300 + * 检查memcache是否长连接
  301 + * @return bool
  302 + */
  303 + public function isPersistent()
  304 + {
  305 + return $this->init()->isPersistent();
  306 + }
  307 +
  308 + /**
  309 + * 设置
  310 + * @param $key
  311 + * @param $value
  312 + * @param int $expiration
  313 + * @return bool
  314 + */
  315 + public function set($key, $value, $expiration = 0)
  316 + {
  317 + return $this->init()->set($this->_makeTag(true) . $key, $value, $expiration);
  318 + }
  319 +
  320 + /**
  321 + * 设置多个数据
  322 + * @param array $items
  323 + * @param int $expiration
  324 + * @return bool
  325 + */
  326 + public function setMulti(array $items, $expiration = 0)
  327 + {
  328 + $_items = array();
  329 + $tag = $this->_makeTag(true);
  330 + foreach ($items as $key => $val) {
  331 + $_items[$tag . $key] = $val;
  332 + }
  333 + return $this->init()->setMulti($_items, $expiration);
  334 + }
  335 +
  336 + /**
  337 + * 设置tag
  338 + * @param $tagName
  339 + * @return $this
  340 + */
  341 + public function tag($tagName)
  342 + {
  343 + $this->tagName = $tagName;
  344 + return $this;
  345 + }
  346 +
  347 + /**
  348 + * 清除服务列表
  349 + * @return $this
  350 + */
  351 + public function resetServerList()
  352 + {
  353 + $this->init()->resetServerList();
  354 + return $this;
  355 + }
  356 +}
  1 +#File
  2 + 缓存路径配置在cache.config.ini里面,如果config里面不设置路径的话使用系统默认的临时文件路径
  3 + [file]
  4 + cache=/tmp/yoho
  5 + $file = Cache::File();
  6 +
  7 + [file]
  8 + cache.path = /tmp/yoho
  9 + $file = Cache::File('path');
  10 +
  11 + [file]
  12 + fileCache.path = /tmp/yoho
  13 + $file = Cache::File('path','fileCache');
  14 +
  15 + 实现了get、set、del 等方法
  16 + $file = Cache::File('path','cache');
  17 + $file->set('a', '00');
  18 + $file->get('a');
  1 +<?php
  2 +/**
  3 + * Created by PhpStorm.
  4 + * User: Zip
  5 + * Date: 1/27/15
  6 + * Time: 10:50 PM
  7 + */
  8 +
  9 +namespace Hood\Cache\Ssdb;
  10 +
  11 +class Client
  12 +{
  13 + private $debug = false;
  14 + public $sock = null;
  15 + private $_closed = false;
  16 + private $recv_buf = '';
  17 + private $_easy = false;
  18 + public $last_resp = null;
  19 +
  20 + function __construct($host, $port, $timeout_ms = 2000)
  21 + {
  22 + $timeout_f = (float)$timeout_ms / 1000;
  23 + $this->sock = @stream_socket_client("$host:$port", $errno, $errstr, $timeout_f);
  24 + if (!$this->sock) {
  25 + throw new SSDBException("$errno: $errstr");
  26 + }
  27 + $timeout_sec = intval($timeout_ms / 1000);
  28 + $timeout_usec = ($timeout_ms - $timeout_sec * 1000) * 1000;
  29 + @stream_set_timeout($this->sock, $timeout_sec, $timeout_usec);
  30 + if (function_exists('stream_set_chunk_size')) {
  31 + @stream_set_chunk_size($this->sock, 1024 * 1024);
  32 + }
  33 + }
  34 +
  35 + /**
  36 + * After this method invoked with yesno=true, all requesting methods
  37 + * will not return a Response object.
  38 + * And some certain methods like get/zget will return false
  39 + * when response is not ok(not_found, etc)
  40 + */
  41 + function easy()
  42 + {
  43 + $this->_easy = true;
  44 + }
  45 +
  46 + function close()
  47 + {
  48 + if (!$this->_closed) {
  49 + @fclose($this->sock);
  50 + $this->_closed = true;
  51 + $this->sock = null;
  52 + }
  53 + }
  54 +
  55 + function closed()
  56 + {
  57 + return $this->_closed;
  58 + }
  59 +
  60 + private $batch_mode = false;
  61 + private $batch_cmds = array();
  62 +
  63 + function batch()
  64 + {
  65 + $this->batch_mode = true;
  66 + $this->batch_cmds = array();
  67 + return $this;
  68 + }
  69 +
  70 + function multi()
  71 + {
  72 + return $this->batch();
  73 + }
  74 +
  75 + function exec()
  76 + {
  77 + $ret = array();
  78 + foreach ($this->batch_cmds as $op) {
  79 + list($cmd, $params) = $op;
  80 + $this->send_req($cmd, $params);
  81 + }
  82 + foreach ($this->batch_cmds as $op) {
  83 + list($cmd, $params) = $op;
  84 + $resp = $this->recv_resp($cmd, $params);
  85 + $resp = $this->check_easy_resp($cmd, $resp);
  86 + $ret[] = $resp;
  87 + }
  88 + $this->batch_mode = false;
  89 + $this->batch_cmds = array();
  90 + return $ret;
  91 + }
  92 +
  93 + function request()
  94 + {
  95 + $args = func_get_args();
  96 + $cmd = array_shift($args);
  97 + return $this->__call($cmd, $args);
  98 + }
  99 +
  100 + private $async_auth_password = null;
  101 +
  102 + function auth($password)
  103 + {
  104 + $this->async_auth_password = $password;
  105 + return null;
  106 + }
  107 +
  108 + function __call($cmd, $params = array())
  109 + {
  110 + $cmd = strtolower($cmd);
  111 + if ($this->async_auth_password !== null) {
  112 + $pass = $this->async_auth_password;
  113 + $this->async_auth_password = null;
  114 + $auth = $this->__call('auth', array($pass));
  115 + if ($auth !== true) {
  116 + throw new Exception("Authentication failed");
  117 + }
  118 + }
  119 +
  120 + if ($this->batch_mode) {
  121 + $this->batch_cmds[] = array($cmd, $params);
  122 + return $this;
  123 + }
  124 +
  125 + try {
  126 + if ($this->send_req($cmd, $params) === false) {
  127 + $resp = new Response('error', 'send error');
  128 + } else {
  129 + $resp = $this->recv_resp($cmd, $params);
  130 + }
  131 + } catch (SSDBException $e) {
  132 + if ($this->_easy) {
  133 + throw $e;
  134 + } else {
  135 + $resp = new Response('error', $e->getMessage());
  136 + }
  137 + }
  138 +
  139 + if ($resp->code == 'noauth') {
  140 + $msg = $resp->message;
  141 + throw new Exception($msg);
  142 + }
  143 +
  144 + $resp = $this->check_easy_resp($cmd, $resp);
  145 + return $resp;
  146 + }
  147 +
  148 + private function check_easy_resp($cmd, $resp)
  149 + {
  150 + $this->last_resp = $resp;
  151 + if ($this->_easy) {
  152 + if ($resp->not_found()) {
  153 + return NULL;
  154 + } else if (!$resp->ok() && !is_array($resp->data)) {
  155 + return false;
  156 + } else {
  157 + return $resp->data;
  158 + }
  159 + } else {
  160 + $resp->cmd = $cmd;
  161 + return $resp;
  162 + }
  163 + }
  164 +
  165 + function multi_set($kvs = array())
  166 + {
  167 + $args = array();
  168 + foreach ($kvs as $k => $v) {
  169 + $args[] = $k;
  170 + $args[] = $v;
  171 + }
  172 + return $this->__call(__FUNCTION__, $args);
  173 + }
  174 +
  175 + function multi_hset($name, $kvs = array())
  176 + {
  177 + $args = array($name);
  178 + foreach ($kvs as $k => $v) {
  179 + $args[] = $k;
  180 + $args[] = $v;
  181 + }
  182 + return $this->__call(__FUNCTION__, $args);
  183 + }
  184 +
  185 + function multi_zset($name, $kvs = array())
  186 + {
  187 + $args = array($name);
  188 + foreach ($kvs as $k => $v) {
  189 + $args[] = $k;
  190 + $args[] = $v;
  191 + }
  192 + return $this->__call(__FUNCTION__, $args);
  193 + }
  194 +
  195 + function incr($key, $val = 1)
  196 + {
  197 + $args = func_get_args();
  198 + return $this->__call(__FUNCTION__, $args);
  199 + }
  200 +
  201 + function decr($key, $val = 1)
  202 + {
  203 + $args = func_get_args();
  204 + return $this->__call(__FUNCTION__, $args);
  205 + }
  206 +
  207 + function zincr($name, $key, $score = 1)
  208 + {
  209 + $args = func_get_args();
  210 + return $this->__call(__FUNCTION__, $args);
  211 + }
  212 +
  213 + function zdecr($name, $key, $score = 1)
  214 + {
  215 + $args = func_get_args();
  216 + return $this->__call(__FUNCTION__, $args);
  217 + }
  218 +
  219 + function zadd($key, $score, $value)
  220 + {
  221 + $args = array($key, $value, $score);
  222 + return $this->__call('zset', $args);
  223 + }
  224 +
  225 + function zRevRank($name, $key)
  226 + {
  227 + $args = func_get_args();
  228 + return $this->__call("zrrank", $args);
  229 + }
  230 +
  231 + function zRevRange($name, $offset, $limit)
  232 + {
  233 + $args = func_get_args();
  234 + return $this->__call("zrrange", $args);
  235 + }
  236 +
  237 + function hincr($name, $key, $val = 1)
  238 + {
  239 + $args = func_get_args();
  240 + return $this->__call(__FUNCTION__, $args);
  241 + }
  242 +
  243 + function hdecr($name, $key, $val = 1)
  244 + {
  245 + $args = func_get_args();
  246 + return $this->__call(__FUNCTION__, $args);
  247 + }
  248 +
  249 + private function send_req($cmd, $params)
  250 + {
  251 + $req = array($cmd);
  252 + foreach ($params as $p) {
  253 + if (is_array($p)) {
  254 + $req = array_merge($req, $p);
  255 + } else {
  256 + $req[] = $p;
  257 + }
  258 + }
  259 + return $this->send($req);
  260 + }
  261 +
  262 + private function recv_resp($cmd, $params)
  263 + {
  264 + $resp = $this->recv();
  265 + if ($resp === false) {
  266 + return new Response('error', 'Unknown error');
  267 + } else if (!$resp) {
  268 + return new Response('disconnected', 'Connection closed');
  269 + }
  270 + if ($resp[0] == 'noauth') {
  271 + $errmsg = isset($resp[1]) ? $resp[1] : '';
  272 + return new Response($resp[0], $errmsg);
  273 + }
  274 + switch ($cmd) {
  275 + case 'dbsize':
  276 + case 'ping':
  277 + case 'qset':
  278 + case 'getbit':
  279 + case 'setbit':
  280 + case 'countbit':
  281 + case 'strlen':
  282 + case 'set':
  283 + case 'setx':
  284 + case 'setnx':
  285 + case 'zset':
  286 + case 'hset':
  287 + case 'qpush':
  288 + case 'qpush_front':
  289 + case 'qpush_back':
  290 + case 'qtrim_front':
  291 + case 'qtrim_back':
  292 + case 'del':
  293 + case 'zdel':
  294 + case 'hdel':
  295 + case 'hsize':
  296 + case 'zsize':
  297 + case 'qsize':
  298 + case 'hclear':
  299 + case 'zclear':
  300 + case 'qclear':
  301 + case 'multi_set':
  302 + case 'multi_del':
  303 + case 'multi_hset':
  304 + case 'multi_hdel':
  305 + case 'multi_zset':
  306 + case 'multi_zdel':
  307 + case 'incr':
  308 + case 'decr':
  309 + case 'zincr':
  310 + case 'zdecr':
  311 + case 'hincr':
  312 + case 'hdecr':
  313 + case 'zget':
  314 + case 'zrank':
  315 + case 'zrrank':
  316 + case 'zcount':
  317 + case 'zsum':
  318 + case 'zremrangebyrank':
  319 + case 'zremrangebyscore':
  320 + if ($resp[0] == 'ok') {
  321 + $val = isset($resp[1]) ? intval($resp[1]) : 0;
  322 + return new Response($resp[0], $val);
  323 + } else {
  324 + $errmsg = isset($resp[1]) ? $resp[1] : '';
  325 + return new Response($resp[0], $errmsg);
  326 + }
  327 + case 'zavg':
  328 + if ($resp[0] == 'ok') {
  329 + $val = isset($resp[1]) ? floatval($resp[1]) : (float)0;
  330 + return new Response($resp[0], $val);
  331 + } else {
  332 + $errmsg = isset($resp[1]) ? $resp[1] : '';
  333 + return new Response($resp[0], $errmsg);
  334 + }
  335 + case 'get':
  336 + case 'substr':
  337 + case 'getset':
  338 + case 'hget':
  339 + case 'qget':
  340 + case 'qfront':
  341 + case 'qback':
  342 + if ($resp[0] == 'ok') {
  343 + if (count($resp) == 2) {
  344 + return new Response('ok', $resp[1]);
  345 + } else {
  346 + return new Response('server_error', 'Invalid response');
  347 + }
  348 + } else {
  349 + $errmsg = isset($resp[1]) ? $resp[1] : '';
  350 + return new Response($resp[0], $errmsg);
  351 + }
  352 + break;
  353 + case 'qpop':
  354 + case 'qpop_front':
  355 + case 'qpop_back':
  356 + if ($resp[0] == 'ok') {
  357 + $size = 1;
  358 + if (isset($params[1])) {
  359 + $size = intval($params[1]);
  360 + }
  361 + if ($size <= 1) {
  362 + if (count($resp) == 2) {
  363 + return new Response('ok', $resp[1]);
  364 + } else {
  365 + return new Response('server_error', 'Invalid response');
  366 + }
  367 + } else {
  368 + $data = array_slice($resp, 1);
  369 + return new Response('ok', $data);
  370 + }
  371 + } else {
  372 + $errmsg = isset($resp[1]) ? $resp[1] : '';
  373 + return new Response($resp[0], $errmsg);
  374 + }
  375 + break;
  376 + case 'keys':
  377 + case 'zkeys':
  378 + case 'hkeys':
  379 + case 'hlist':
  380 + case 'zlist':
  381 + case 'qslice':
  382 + if ($resp[0] == 'ok') {
  383 + $data = array();
  384 + if ($resp[0] == 'ok') {
  385 + $data = array_slice($resp, 1);
  386 + }
  387 + return new Response($resp[0], $data);
  388 + } else {
  389 + $errmsg = isset($resp[1]) ? $resp[1] : '';
  390 + return new Response($resp[0], $errmsg);
  391 + }
  392 + case 'auth':
  393 + case 'exists':
  394 + case 'hexists':
  395 + case 'zexists':
  396 + if ($resp[0] == 'ok') {
  397 + if (count($resp) == 2) {
  398 + return new Response('ok', (bool)$resp[1]);
  399 + } else {
  400 + return new Response('server_error', 'Invalid response');
  401 + }
  402 + } else {
  403 + $errmsg = isset($resp[1]) ? $resp[1] : '';
  404 + return new Response($resp[0], $errmsg);
  405 + }
  406 + break;
  407 + case 'multi_exists':
  408 + case 'multi_hexists':
  409 + case 'multi_zexists':
  410 + if ($resp[0] == 'ok') {
  411 + if (count($resp) % 2 == 1) {
  412 + $data = array();
  413 + for ($i = 1; $i < count($resp); $i += 2) {
  414 + $data[$resp[$i]] = (bool)$resp[$i + 1];
  415 + }
  416 + return new Response('ok', $data);
  417 + } else {
  418 + return new Response('server_error', 'Invalid response');
  419 + }
  420 + } else {
  421 + $errmsg = isset($resp[1]) ? $resp[1] : '';
  422 + return new Response($resp[0], $errmsg);
  423 + }
  424 + break;
  425 + case 'scan':
  426 + case 'rscan':
  427 + case 'zscan':
  428 + case 'zrscan':
  429 + case 'zrange':
  430 + case 'zrrange':
  431 + case 'hscan':
  432 + case 'hrscan':
  433 + case 'hgetall':
  434 + case 'multi_hsize':
  435 + case 'multi_zsize':
  436 + case 'multi_get':
  437 + case 'multi_hget':
  438 + case 'multi_zget':
  439 + if ($resp[0] == 'ok') {
  440 + if (count($resp) % 2 == 1) {
  441 + $data = array();
  442 + for ($i = 1; $i < count($resp); $i += 2) {
  443 + if ($cmd[0] == 'z') {
  444 + $data[$resp[$i]] = intval($resp[$i + 1]);
  445 + } else {
  446 + $data[$resp[$i]] = $resp[$i + 1];
  447 + }
  448 + }
  449 + return new Response('ok', $data);
  450 + } else {
  451 + return new Response('server_error', 'Invalid response');
  452 + }
  453 + } else {
  454 + $errmsg = isset($resp[1]) ? $resp[1] : '';
  455 + return new Response($resp[0], $errmsg);
  456 + }
  457 + break;
  458 + default:
  459 + return new Response($resp[0], array_slice($resp, 1));
  460 + }
  461 + return new Response('error', 'Unknown command: $cmd');
  462 + }
  463 +
  464 + private function send($data)
  465 + {
  466 + $ps = array();
  467 + foreach ($data as $p) {
  468 + $ps[] = strlen($p);
  469 + $ps[] = $p;
  470 + }
  471 + $s = join("\n", $ps) . "\n\n";
  472 + if ($this->debug) {
  473 + echo '> ' . str_replace(array("\r", "\n"), array('\r', '\n'), $s) . "\n";
  474 + }
  475 + try {
  476 + while (true) {
  477 + $ret = @fwrite($this->sock, $s);
  478 + if ($ret === false) {
  479 + $this->close();
  480 + throw new SSDBException('Connection lost');
  481 + }
  482 + $s = substr($s, $ret);
  483 + if (strlen($s) == 0) {
  484 + break;
  485 + }
  486 + @fflush($this->sock);
  487 + }
  488 + } catch (Exception $e) {
  489 + $this->close();
  490 + throw new SSDBException($e->getMessage());
  491 + }
  492 + return $ret;
  493 + }
  494 +
  495 + private function recv()
  496 + {
  497 + $this->step = self::STEP_SIZE;
  498 + while (true) {
  499 + $ret = $this->parse();
  500 + if ($ret === null) {
  501 + try {
  502 + $data = @fread($this->sock, 1024 * 1024);
  503 + if ($this->debug) {
  504 + echo '< ' . str_replace(array("\r", "\n"), array('\r', '\n'), $data) . "\n";
  505 + }
  506 + } catch (Exception $e) {
  507 + $data = '';
  508 + }
  509 + if ($data === false || $data === '') {
  510 + if (feof($this->sock)) {
  511 + $this->close();
  512 + throw new SSDBException('Connection lost');
  513 + } else {
  514 + throw new SSDBTimeoutException('Connection timeout');
  515 + }
  516 + }
  517 + $this->recv_buf .= $data;
  518 +# echo "read " . strlen($data) . " total: " . strlen($this->recv_buf) . "\n";
  519 + } else {
  520 + return $ret;
  521 + }
  522 + }
  523 + }
  524 +
  525 + const STEP_SIZE = 0;
  526 + const STEP_DATA = 1;
  527 + public $resp = array();
  528 + public $step;
  529 + public $block_size;
  530 +
  531 + private function parse()
  532 + {
  533 + $spos = 0;
  534 + $epos = 0;
  535 + $buf_size = strlen($this->recv_buf);
  536 + // performance issue for large reponse
  537 + //$this->recv_buf = ltrim($this->recv_buf);
  538 + while (true) {
  539 + $spos = $epos;
  540 + if ($this->step === self::STEP_SIZE) {
  541 + $epos = strpos($this->recv_buf, "\n", $spos);
  542 + if ($epos === false) {
  543 + break;
  544 + }
  545 + $epos += 1;
  546 + $line = substr($this->recv_buf, $spos, $epos - $spos);
  547 + $spos = $epos;
  548 +
  549 + $line = trim($line);
  550 + if (strlen($line) == 0) { // head end
  551 + $this->recv_buf = substr($this->recv_buf, $spos);
  552 + $ret = $this->resp;
  553 + $this->resp = array();
  554 + return $ret;
  555 + }
  556 + $this->block_size = intval($line);
  557 + $this->step = self::STEP_DATA;
  558 + }
  559 + if ($this->step === self::STEP_DATA) {
  560 + $epos = $spos + $this->block_size;
  561 + if ($epos <= $buf_size) {
  562 + $n = strpos($this->recv_buf, "\n", $epos);
  563 + if ($n !== false) {
  564 + $data = substr($this->recv_buf, $spos, $epos - $spos);
  565 + $this->resp[] = $data;
  566 + $epos = $n + 1;
  567 + $this->step = self::STEP_SIZE;
  568 + continue;
  569 + }
  570 + }
  571 + break;
  572 + }
  573 + }
  574 +
  575 + // packet not ready
  576 + if ($spos > 0) {
  577 + $this->recv_buf = substr($this->recv_buf, $spos);
  578 + }
  579 + return null;
  580 + }
  581 +}
  1 +<?php
  2 +/**
  3 + * Created by PhpStorm.
  4 + * User: Zip
  5 + * Date: 1/27/15
  6 + * Time: 10:30 PM
  7 + */
  8 +
  9 +namespace Hood\Cache\Ssdb;
  10 +
  11 +
  12 +class Response
  13 +{
  14 + public $cmd;
  15 + public $code;
  16 + public $data = null;
  17 + public $message;
  18 +
  19 + function __construct($code = 'ok', $data_or_message = null)
  20 + {
  21 + $this->code = $code;
  22 + if ($code == 'ok') {
  23 + $this->data = $data_or_message;
  24 + } else {
  25 + $this->message = $data_or_message;
  26 + }
  27 + }
  28 +
  29 + function __toString()
  30 + {
  31 + if ($this->code == 'ok') {
  32 + $s = $this->data === null ? '' : json_encode($this->data);
  33 + } else {
  34 + $s = $this->message;
  35 + }
  36 + return sprintf('%-13s %12s %s', $this->cmd, $this->code, $s);
  37 + }
  38 +
  39 + function ok()
  40 + {
  41 + return $this->code == 'ok';
  42 + }
  43 +
  44 + function not_found()
  45 + {
  46 + return $this->code == 'not_found';
  47 + }
  48 +}
  1 +<?php
  2 +/**
  3 + * Created by PhpStorm.
  4 + * User: Zip
  5 + * Date: 1/27/15
  6 + * Time: 10:51 PM
  7 + */
  8 +
  9 +namespace Hood\Cache\Ssdb;
  10 +
  11 +
  12 +class SSDBException extends \Exception {
  13 +
  14 +}
  1 +<?php
  2 +/**
  3 + * Created by PhpStorm.
  4 + * User: Zip
  5 + * Date: 1/27/15
  6 + * Time: 10:51 PM
  7 + */
  8 +
  9 +namespace Hood\Cache\Ssdb;
  10 +
  11 +
  12 +class SSDBTimeoutException extends SSDBException {
  13 +
  14 +}
  1 +<?php
  2 +/**
  3 + * Created by PhpStorm.
  4 + * User: Zip
  5 + * Date: 1/27/15
  6 + * Time: 11:25 PM
  7 + */
  8 +
  9 +namespace Hood\Cache\Ssdb;
  10 +
  11 +
  12 +class SimpleSSDB extends Client
  13 +{
  14 +
  15 + private $node;
  16 +
  17 + private $childNode;
  18 +
  19 + function __construct($host, $port, $timeout_ms = 2000)
  20 + {
  21 + parent::__construct($host, $port, $timeout_ms);
  22 + $this->easy();
  23 + }
  24 +
  25 + public function setNode($node)
  26 + {
  27 +
  28 + }
  29 +
  30 + public function setChildNodes($childNode)
  31 + {
  32 +
  33 + }
  34 +
  35 +}
  1 +<?php
  2 +/**
  3 + * Created by PhpStorm.
  4 + * User: Zip
  5 + * Date: 14/12/16
  6 + * Time: 下午5:05
  7 + */
  8 +
  9 +namespace Hood;
  10 +
  11 +use Hood\Concurrent\Yar;
  12 +use Hood\Concurrent\Http;
  13 +
  14 +class Concurrent
  15 +{
  16 + /**
  17 + * @param $url
  18 + * @return Yar\Client
  19 + */
  20 + static public function yarClient($url)
  21 + {
  22 + return new Yar\Client($url);
  23 + }
  24 +
  25 + /**
  26 + * @param $uri
  27 + * @return Yar\Concurrent
  28 + */
  29 + static public function yarConcurrent($uri)
  30 + {
  31 + return new Yar\Concurrent($uri);
  32 + }
  33 +
  34 + /**
  35 + *
  36 + * @return Http\CurlMulti
  37 + */
  38 + static public function curlMulti()
  39 + {
  40 + return new Http\CurlMulti();
  41 + }
  42 +}
  1 +<?php
  2 +/**
  3 + * Created by PhpStorm.
  4 + * User: Zip
  5 + * Date: 14/12/15
  6 + * Time: 上午2:04
  7 + */
  8 +
  9 +namespace Hood\Concurrent;
  10 +
  11 +
  12 +interface ConcurrentInterface {
  13 +
  14 +}
  1 +<?php
  2 +/**
  3 + * Created by PhpStorm.
  4 + * User: Zip
  5 + * Date: 14/12/22
  6 + * Time: 下午12:23
  7 + */
  8 +
  9 +namespace Hood\Concurrent\Http;
  10 +
  11 +
  12 +class Curl extends CurlAbstract
  13 +{
  14 +
  15 + /**
  16 + * GET方式网络请求
  17 + * @param $url
  18 + * @param array $data
  19 + * @param int $timeout
  20 + * @return mixed
  21 + */
  22 + public static function get($url, array $data = array(), $timeout = 20)
  23 + {
  24 + $ch = curl_init(self::makeUrl($url, $data));
  25 + curl_setopt($ch, CURLOPT_HEADER, 0);
  26 + curl_setopt($ch, CURLOPT_TIMEOUT, $timeout);
  27 + curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
  28 + $result = curl_exec($ch);
  29 + curl_close($ch);
  30 + return $result;
  31 + }
  32 +
  33 +
  34 + /**
  35 + * post提交数据
  36 + * @param $url
  37 + * @param $data
  38 + * @param int $timeout
  39 + * @param array $header
  40 + * @param array $cookie
  41 + * @return mixed
  42 + */
  43 + public static function post($url, $data, $timeout = 20, array $header = array(), array $cookie = array())
  44 + {
  45 + $ch = curl_init($url);
  46 + curl_setopt($ch, CURLOPT_HEADER, 0);
  47 + curl_setopt($ch, CURLOPT_TIMEOUT, $timeout);
  48 + if (!empty($header)) {
  49 + curl_setopt($ch, CURLOPT_HTTPHEADER, $header);// array('Content-Type:application/json;charset=UTF-8'));
  50 + }
  51 +
  52 + if (!empty($cookie)) {
  53 + $cookie_str = array();
  54 + foreach ($cookie as $key => $val) {
  55 + $cookie_str[] = urlencode($key) . '=' . urlencode($val);
  56 + }
  57 + curl_setopt($ch, CURLOPT_COOKIE, implode(';', $cookie_str));
  58 + }
  59 +
  60 + curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
  61 + curl_setopt($ch, CURLOPT_POST, true);
  62 + if (!empty($data)) {
  63 + curl_setopt($ch, CURLOPT_POSTFIELDS, $data);
  64 + }
  65 + $result = curl_exec($ch);
  66 +// $code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
  67 + curl_close($ch);
  68 + return $result;
  69 + }
  70 +
  71 +}
  1 +<?php
  2 +/**
  3 + * Created by PhpStorm.
  4 + * User: Zip
  5 + * Date: 15/4/8
  6 + * Time: 下午1:55
  7 + */
  8 +
  9 +namespace Hood\Concurrent\Http;
  10 +
  11 +
  12 +class CurlAbstract
  13 +{
  14 + public static function makeUrl($url, array $data)
  15 + {
  16 + $params = '';
  17 + if (!empty($data)) {
  18 + $params = http_build_query($data, '', '&');
  19 + }
  20 + if (strpos($url, '?') === false) {
  21 + $url = $url . '?' . $params;
  22 + } else {
  23 + if (!empty($params)) {
  24 + $url = $url . '&' . $params;
  25 + }
  26 + }
  27 + return $url;
  28 + }
  29 +}
  1 +<?php
  2 +/**
  3 + * Created by PhpStorm.
  4 + * User: Zip
  5 + * Date: 15/4/7
  6 + * Time: 下午9:15
  7 + */
  8 +
  9 +namespace Hood\Concurrent\Http;
  10 +
  11 +class CurlMulti extends CurlAbstract
  12 +{
  13 +
  14 + private $_curls = array();
  15 +
  16 + private $_handle = NULL;
  17 +
  18 + private $wait_for_connect = false;
  19 +
  20 + private $headerData = array();
  21 +
  22 +
  23 + public function __construct()
  24 + {
  25 + $this->_handle = curl_multi_init();
  26 + }
  27 +
  28 + public function __destruct()
  29 + {
  30 + foreach ($this->_curls as $handle_id => $data) {
  31 + curl_multi_remove_handle($this->_handle, $data['handle']);
  32 + curl_close($data['handle']);
  33 + }
  34 + curl_multi_close($this->_handle);
  35 + }
  36 +
  37 + /**
  38 + * 设置是否等待
  39 + * @param $wait_for_connect
  40 + * @return $this
  41 + */
  42 + public function wait($wait_for_connect)
  43 + {
  44 + $this->wait_for_connect = $wait_for_connect;
  45 + return $this;
  46 + }
  47 +
  48 + /**
  49 + * 设置header
  50 + * @param array $headerData
  51 + * @return $this
  52 + */
  53 + public function header(array $headerData)
  54 + {
  55 + $this->headerData = $headerData;
  56 + return $this;
  57 + }
  58 +
  59 + /**
  60 + * 调用
  61 + * @param $url
  62 + * @param $callback
  63 + * @param $data
  64 + * @return $this
  65 + * @throws Exception
  66 + */
  67 + public function get($url, $callback, array $data = array())
  68 + {
  69 + $ch = curl_init(self::makeUrl($url, $data));
  70 + $this->addHandle($ch, $callback, $data, $this->wait_for_connect);
  71 + return $this;
  72 + }
  73 +
  74 + /**
  75 + * 调用
  76 + * @param $url
  77 + * @param $callback
  78 + * @param $data
  79 + * @return $this
  80 + * @throws Exception
  81 + */
  82 + public function post($url, $callback, $data)
  83 + {
  84 + $this->callRest($url, 'POST', $callback, $data);
  85 + return $this;
  86 + }
  87 +
  88 +
  89 + /**
  90 + * rest 请求方法
  91 + * @param $url
  92 + * @param $method
  93 + * @param $callback
  94 + * @param null $data
  95 + * @return $this
  96 + * @throws Exception
  97 + */
  98 + public function callRest($url, $method, $callback, $data = NULL)
  99 + {
  100 + switch (strtoupper($method)) {
  101 + case 'POST':
  102 + $ch = curl_init($url);
  103 + curl_setopt($ch, CURLOPT_POST, TRUE);
  104 + $this->headerData = array_merge($this->headerData, array("X-HTTP-Method-Override: POST"));
  105 + if ($data != null) {
  106 + curl_setopt($ch, CURLOPT_POSTFIELDS, $data);
  107 + }
  108 + break;
  109 + case 'DELETE':
  110 + $ch = curl_init(self::makeUrl($url, $data));
  111 + $this->headerData = array_merge($this->headerData, array("X-HTTP-Method-Override: DELETE"));
  112 + curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'DELETE');
  113 + break;
  114 + case 'PUT':
  115 + $ch = curl_init($url);
  116 + curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'PUT');
  117 + $this->headerData = array_merge($this->headerData, array("X-HTTP-Method-Override: PUT"));
  118 + curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
  119 + if ($data != null) {
  120 + $params = http_build_query($data, '', '&');
  121 + curl_setopt($ch, CURLOPT_POSTFIELDS, $params);
  122 + curl_setopt($ch, CURLOPT_INFILESIZE, strlen($params));
  123 + }
  124 + break;
  125 + case 'GET':
  126 + $ch = curl_init(self::makeUrl($url, $data));
  127 + $this->headerData = array_merge($this->headerData, array("X-HTTP-Method-Override: GET"));
  128 + break;
  129 + }
  130 + $this->addHandle($ch, $callback, $data, $this->wait_for_connect);
  131 + return $this;
  132 + }
  133 +
  134 + /**
  135 + * 添加一个handle
  136 + * @param $curl_handle
  137 + * @param $callback
  138 + * @param $data
  139 + * @param bool $wait_for_connect #是否等待
  140 + * @return bool
  141 + * @throws Exception
  142 + */
  143 + private function addHandle($curl_handle, $callback, $data, $wait_for_connect = false)
  144 + {
  145 + if (get_resource_type($curl_handle) !== 'curl' || !is_callable($callback)) {
  146 + throw new \Exception("Invalid curl handle or callback");
  147 + }
  148 + curl_setopt($curl_handle, CURLOPT_RETURNTRANSFER, TRUE);
  149 + if (!empty($this->headerData)) {
  150 + curl_setopt($curl_handle, CURLOPT_HTTPHEADER, $this->headerData);
  151 + }
  152 + $this->_curls[(int)$curl_handle] = array(
  153 + 'handle' => $curl_handle,
  154 + 'callback' => $callback,
  155 + 'callback_data' => $data,
  156 + );
  157 + curl_multi_add_handle($this->_handle, $curl_handle);
  158 + if ($wait_for_connect) {
  159 + $this->poll();
  160 + }
  161 + return TRUE;
  162 + }
  163 +
  164 + /**
  165 + * 移除会话中的hendle
  166 + * @param $curl_handle
  167 + * @return bool
  168 + */
  169 + public function removeHandle($curl_handle)
  170 + {
  171 + if (!isset($this->_curls[(int)$curl_handle])) {
  172 + return FALSE;
  173 + }
  174 + curl_multi_remove_handle($this->_handle, $curl_handle);
  175 + unset($this->_curls[(int)$curl_handle]);
  176 + return TRUE;
  177 + }
  178 +
  179 + /**
  180 + * 等待所有会话
  181 + * @return bool
  182 + */
  183 + public function poll()
  184 + {
  185 + $still_running = 0;
  186 + do {
  187 + $result = curl_multi_exec($this->_handle, $still_running);
  188 + if ($result == CURLM_OK) {
  189 + do {
  190 + $messages_in_queue = 0;
  191 + $info = curl_multi_info_read($this->_handle, $messages_in_queue);
  192 + if ($info && isset($info['handle']) && isset($this->_curls[(int)$info['handle']])) {
  193 + $callback_info = $this->_curls[(int)$info['handle']];
  194 + $curl_data = curl_multi_getcontent($info['handle']);
  195 + $curl_info = curl_getinfo($info['handle']);
  196 + call_user_func($callback_info['callback'], $curl_data, $curl_info);
  197 + $this->removeHandle($info['handle']);
  198 + curl_close($info['handle']);
  199 + }
  200 + } while ($messages_in_queue > 0);
  201 + }
  202 + } while ($result == CURLM_CALL_MULTI_PERFORM && $still_running > 0);
  203 + return (boolean)$this->_curls;
  204 + }
  205 +
  206 + /**
  207 + * 设置堵塞中的会话超时时间
  208 + * @param float $timeout
  209 + * @return bool
  210 + */
  211 + public function select($timeout = 1.0)
  212 + {
  213 + $result = $this->poll();
  214 + if ($result) {
  215 + curl_multi_select($this->_handle, $timeout);
  216 + $result = $this->poll();
  217 + }
  218 + return $result;
  219 + }
  220 +
  221 + /**
  222 + * 刷新所有会话超时时间
  223 + * @return bool
  224 + */
  225 + public function finish()
  226 + {
  227 + while ($this->select() === TRUE) {
  228 + }
  229 + return TRUE;
  230 + }
  231 +}
  1 +<?php
  2 +/**
  3 + * Created by PhpStorm.
  4 + * User: Zip
  5 + * Date: 14/12/15
  6 + * Time: 上午2:02
  7 + */
  8 +
  9 +namespace Hood\Concurrent\Yar;
  10 +
  11 +use Hood\Core\Root;
  12 +
  13 +class Client extends Root
  14 +{
  15 + /**
  16 + * @var array
  17 + */
  18 + private $_instances = array();
  19 +
  20 + /**
  21 + * @var \Yar_Client
  22 + */
  23 + private $client;
  24 +
  25 + /**
  26 + * Set timeout to 3s
  27 + * @var int
  28 + */
  29 + private $_timeout = 3000;
  30 +
  31 + /**
  32 + * @param $uri
  33 + */
  34 + public function __construct($uri)
  35 + {
  36 + parent::__construct();
  37 + $yarKey = md5($uri);
  38 + if (!isset($this->_instances[$yarKey])) {
  39 + $this->_instances[$yarKey] = new \Yar_Client($uri);
  40 + }
  41 + $this->client = $this->_instances[$yarKey];
  42 + }
  43 +
  44 + /**
  45 + * 设置yar参数
  46 + * @param $name
  47 + * @param $value
  48 + */
  49 + public function setOpt($name, $value)
  50 + {
  51 + $this->client->setOpt($name, $value);
  52 + return $this;
  53 + }
  54 +
  55 + /**
  56 + * 数据包类型
  57 + * @param string $packagerType
  58 + */
  59 + public function setPackager($packagerType = YAR_PACKAGER_PHP)
  60 + {
  61 + $this->client->setOpt(YAR_OPT_PACKAGER, $packagerType);
  62 + return $this;
  63 + }
  64 +
  65 + /**
  66 + * 连接超时(毫秒为单位)
  67 + * @param $timeout
  68 + */
  69 + public function setConnectTimeout($timeout = 1000)
  70 + {
  71 + $this->client->setOpt(YAR_OPT_CONNECT_TIMEOUT, $timeout);
  72 + return $this;
  73 + }
  74 +
  75 + /**
  76 + * Set timeout to 3s
  77 + * 处理超时(毫秒为单位)
  78 + * @param $timeout
  79 + * @return $this
  80 + */
  81 + public function setTimeout($timeout = 3000)
  82 + {
  83 + $this->client->setOpt(YAR_OPT_TIMEOUT, $timeout);
  84 + return $this;
  85 + }
  86 +
  87 + /**
  88 + * @param $name
  89 + * @param array $arguments
  90 + * @return mixed
  91 + */
  92 + public function __call($method, $parameters)
  93 + {
  94 + return $this->client->__call($method, $parameters);
  95 + }
  96 +}
  1 +<?php
  2 +/**
  3 + * Created by PhpStorm.
  4 + * User: Zip
  5 + * Date: 14/12/15
  6 + * Time: 上午2:02
  7 + */
  8 +
  9 +namespace Hood\Concurrent\Yar;
  10 +
  11 +use Hood\Core\Root;
  12 +
  13 +class Concurrent extends Root
  14 +{
  15 + private $uri;
  16 +
  17 + public function __construct($uri)
  18 + {
  19 + parent::__construct();
  20 + $this->uri = $uri;
  21 + }
  22 +
  23 + /**
  24 + * 注册一个并行的服务调用
  25 + * @param $uri
  26 + * @param $method
  27 + * @param $parameters
  28 + * @param string $callback
  29 + */
  30 + public function call($uri, $method, $parameters, $callback = '')
  31 + {
  32 + \Yar_Concurrent_Client::call($uri, $method, $parameters, $callback);
  33 + }
  34 +
  35 + /**
  36 + * 链式调用
  37 + * @param $method
  38 + * @param $parameters
  39 + * @param string $callback
  40 + * @return $this
  41 + */
  42 + public function calls($method, $parameters, $callback = '')
  43 + {
  44 + $this->call($this->uri, $method, $parameters, $callback);
  45 + return $this;
  46 + }
  47 +
  48 + /**
  49 + * 发送所有注册的并行调用
  50 + * @param string $callback
  51 + * @param callable $errorCallback
  52 + */
  53 + public function loop($callback = '', $errorCallback = '')
  54 + {
  55 + \Yar_Concurrent_Client::loop($callback, $errorCallback);
  56 + }
  57 +
  58 + /**
  59 + * 缓存tag
  60 + * @param $tagName
  61 + * @return $this
  62 + */
  63 + public function tag($tagName)
  64 + {
  65 + $this->_cacheTagName = $tagName;
  66 + return $this;
  67 + }
  68 +
  69 + /**
  70 + * 缓存key
  71 + * @param string $key
  72 + * @param null $prefix
  73 + * @return $this
  74 + */
  75 + public function key($key)
  76 + {
  77 + $this->_cacheKey = (string)$key;
  78 + return $this;
  79 + }
  80 +
  81 + /**
  82 + * 缓存时间
  83 + * @param $expire
  84 + * @return $this
  85 + */
  86 + public function expire($expire)
  87 + {
  88 + $this->_cacheExpire = (int)$expire;
  89 + return $this;
  90 + }
  91 +}
  1 +<?php
  2 +namespace Hood;
  3 +
  4 +use Hood\Debug\DebugException;
  5 +
  6 +class Cookie
  7 +{
  8 + /**
  9 + * 取得所有的cookie值
  10 + *
  11 + * @return array
  12 + * @since 0.2.2
  13 + */
  14 + public static function all()
  15 + {
  16 + return $_COOKIE;
  17 + }
  18 +
  19 + /**
  20 + * @param $name
  21 + * @param string $default
  22 + * @return string
  23 + * @throws DebugException
  24 + */
  25 + public static function get($name, $default = '')
  26 + {
  27 + if (preg_match("/[=,; \t\r\n\013\014]/", $name)) {
  28 + throw new DebugException(sprintf('The cookie name "%s" contains invalid characters.', $name));
  29 + }
  30 + return isset ($_COOKIE [$name]) ? $_COOKIE [$name] : $default;
  31 + }
  32 +
  33 + /**
  34 + * 设置cookie
  35 + * @param string $name
  36 + * @param string $domain
  37 + * @param string $value
  38 + * @param int $expire (0:Session、-1:删除、time():过期时间 )
  39 + * @param string $path
  40 + * @param bool $httponly
  41 + * @param bool $secureAuto
  42 + */
  43 + public static function set($name, $value, $minutes = 0, $path = '/', $domain = null, $secure = false, $httpOnly = true)
  44 + {
  45 + if (preg_match("/[=,; \t\r\n\013\014]/", $name)) {
  46 + throw new DebugException(sprintf('The cookie name "%s" contains invalid characters.', $name));
  47 + }
  48 + $expire = $minutes;
  49 + if ($minutes == 0) {
  50 + $expire = 0;
  51 + } else if ($minutes == -1) {
  52 + $expire = time() - 3600;
  53 + }
  54 + setcookie($name, $value, $expire, $path, $domain, (bool)$secure, $httpOnly);
  55 + }
  56 +}
  1 +<?php
  2 +/**
  3 + * Created by PhpStorm.
  4 + * User: Zip
  5 + * Date: 14/12/7
  6 + * Time: 上午12:45
  7 + */
  8 +
  9 +namespace Hood\Core;
  10 +
  11 +use Hood\Core\Server;
  12 +
  13 +class Root
  14 +{
  15 +
  16 + /**
  17 + * server file
  18 + * @var String
  19 + */
  20 + protected $serviceFile;
  21 +
  22 + /**
  23 + * 应用环境
  24 + * @var string
  25 + */
  26 + protected $applicationEnv;
  27 +
  28 +
  29 + /**
  30 + * 缓存时间
  31 + * @var int
  32 + */
  33 + protected $_cacheExpire = 3600;
  34 +
  35 + /**
  36 + * 缓存
  37 + * @var bool
  38 + */
  39 + protected $_cacheStatus = true;
  40 +
  41 + /**
  42 + * 缓存key
  43 + * @var null
  44 + */
  45 + protected $_cacheKey = null;
  46 +
  47 + /**
  48 + * 缓存tagName
  49 + * @var string
  50 + */
  51 + protected $_cacheTagName = '';
  52 +
  53 +
  54 + /**
  55 + * 删除多个缓存tag
  56 + */
  57 + protected $_delTags = array();
  58 +
  59 +
  60 + public function __construct()
  61 + {
  62 + defined('APPLICATION_ENV') || define('APPLICATION_ENV', 'developer');
  63 + defined('APPLICATION_SYSTEM_CONFIG') || define('APPLICATION_SYSTEM_CONFIG', '/Data/Code/SystemConfig');
  64 + }
  65 +
  66 + /**
  67 + * 获取应用环境
  68 + * @return string
  69 + */
  70 + public function getApplicationEnv()
  71 + {
  72 + return $this->applicationEnv;
  73 + }
  74 +
  75 + /**
  76 + * 设置应用环境
  77 + * @param $env
  78 + * @return $this
  79 + */
  80 + public function setApplicationEnv($env)
  81 + {
  82 + define('APPLICATION_ENV', $env);
  83 + return $this;
  84 + }
  85 +
  86 + /**
  87 + *
  88 + * @param $configFile
  89 + * @return $this
  90 + */
  91 + public function setApplicationSystemConfig($configFile)
  92 + {
  93 + define('APPLICATION_SYSTEM_CONFIG', $configFile);
  94 + return $this;
  95 + }
  96 +
  97 + /**
  98 + * 获取server
  99 + * @param $serviceName
  100 + * @param string $suffix
  101 + * @return Server
  102 + */
  103 + public function getServerHost($serviceName, $suffix = 'config.ini')
  104 + {
  105 + $serviceFileArray = array(
  106 + $serviceName,
  107 + APPLICATION_ENV,
  108 + $suffix
  109 + );
  110 + $this->serviceFile = $serviceFile = APPLICATION_SYSTEM_CONFIG . DIRECTORY_SEPARATOR . implode('.', $serviceFileArray);
  111 + return new Server($serviceFile);
  112 + }
  113 +}
  1 +<?php
  2 +
  3 +namespace Hood\Core\Security;
  4 +/**
  5 + * Class AuthCode
  6 + * @package Hood\Core\Security
  7 + */
  8 +class AuthCode
  9 +{
  10 +
  11 + /**
  12 + * 验证编码
  13 + *
  14 + * @param String $string
  15 + * @param String $operation
  16 + * @param Integer $expiry
  17 + * @param String $key
  18 + * @return String
  19 + */
  20 + private static function auth($string, $key, $expiry = 0, $operation = 'decode')
  21 + {
  22 + $ckey_length = 4;
  23 + $key = md5($key);
  24 + $keya = md5(substr($key, 0, 16));
  25 + $keyb = md5(substr($key, 16, 16));
  26 + $keyc = $ckey_length ? ($operation == 'decode' ? substr($string, 0, $ckey_length) : substr(md5(microtime()), -$ckey_length)) : '';
  27 + $cryptkey = $keya . md5($keya . $keyc);
  28 + $key_length = strlen($cryptkey);
  29 + $string = $operation == 'decode' ? base64_decode(substr($string, $ckey_length)) : sprintf('%010d', $expiry ? $expiry + time() : 0) . substr(md5($string . $keyb), 0, 16) . $string;
  30 + $string_length = strlen($string);
  31 +
  32 + $result = '';
  33 + $box = range(0, 255);
  34 +
  35 + $rndkey = array();
  36 + for ($i = 0; $i <= 255; $i++) {
  37 + $rndkey[$i] = ord($cryptkey[$i % $key_length]);
  38 + }
  39 +
  40 + for ($j = $i = 0; $i < 256; $i++) {
  41 + $j = ($j + $box[$i] + $rndkey[$i]) % 256;
  42 + $tmp = $box[$i];
  43 + $box[$i] = $box[$j];
  44 + $box[$j] = $tmp;
  45 + }
  46 +
  47 + for ($a = $j = $i = 0; $i < $string_length; $i++) {
  48 + $a = ($a + 1) % 256;
  49 + $j = ($j + $box[$a]) % 256;
  50 + $tmp = $box[$a];
  51 + $box[$a] = $box[$j];
  52 + $box[$j] = $tmp;
  53 + $result .= chr(ord($string[$i]) ^ ($box[($box[$a] + $box[$j]) % 256]));
  54 + }
  55 +
  56 + if ($operation == 'decode') {
  57 + if ((substr($result, 0, 10) == 0 || substr($result, 0, 10) - time() > 0) && substr($result, 10, 16) == substr(md5(substr($result, 26) . $keyb), 0, 16)) {
  58 + return substr($result, 26);
  59 + } else {
  60 + return false;
  61 + }
  62 + } else {
  63 + return $keyc . str_replace('=', '', base64_encode($result));
  64 + }
  65 + }
  66 +
  67 + /**
  68 + * 解密
  69 + *
  70 + * @param String $string
  71 + * @param String $key
  72 + * @param Integer $expiry
  73 + * @return String
  74 + */
  75 + public static function decode($string, $key, $expiry = 0)
  76 + {
  77 + return self::auth($string, $key, $expiry, __FUNCTION__);
  78 + }
  79 +
  80 + /**
  81 + * 加密
  82 + *
  83 + * @param String $string
  84 + * @param String $key
  85 + * @param Integer $expiry
  86 + * @return String
  87 + */
  88 + public static function encode($string, $key, $expiry = 0)
  89 + {
  90 + return self::auth($string, $key, $expiry, __FUNCTION__);
  91 + }
  92 +
  93 + /**
  94 + * 获取编码
  95 + *
  96 + * @param String $plaintext
  97 + * @param String $salt
  98 + * @param String $encryption
  99 + * @param bool $show_encrypt
  100 + * @return String
  101 + */
  102 + public static function getCrypted($plaintext, $salt = '', $encryption = 'md5-hex', $show_encrypt = false)
  103 + {
  104 + $salt = self::getSalt($encryption, $salt, $plaintext);
  105 + switch ($encryption) {
  106 + case 'plain' :
  107 + return $plaintext;
  108 + case 'sha' :
  109 + $encrypted = base64_encode(mhash(MHASH_SHA1, $plaintext));
  110 + return ($show_encrypt) ? '{SHA}' . $encrypted : $encrypted;
  111 + case 'crypt' :
  112 + case 'crypt-des' :
  113 + case 'crypt-md5' :
  114 + case 'crypt-blowfish' :
  115 + return ($show_encrypt ? '{crypt}' : '') . crypt($plaintext, $salt);
  116 + case 'md5-base64' :
  117 + $encrypted = base64_encode(mhash(MHASH_MD5, $plaintext));
  118 + return ($show_encrypt) ? '{MD5}' . $encrypted : $encrypted;
  119 + case 'ssha' :
  120 + $encrypted = base64_encode(mhash(MHASH_SHA1, $plaintext . $salt) . $salt);
  121 + return ($show_encrypt) ? '{SSHA}' . $encrypted : $encrypted;
  122 + case 'smd5' :
  123 + $encrypted = base64_encode(mhash(MHASH_MD5, $plaintext . $salt) . $salt);
  124 + return ($show_encrypt) ? '{SMD5}' . $encrypted : $encrypted;
  125 + case 'aprmd5' :
  126 + $length = strlen($plaintext);
  127 + $context = $plaintext . '$apr1$' . $salt;
  128 + $binary = self::_bin(md5($plaintext . $salt . $plaintext));
  129 + for ($i = $length; $i > 0; $i -= 16) {
  130 + $context .= substr($binary, 0, ($i > 16 ? 16 : $i));
  131 + }
  132 + for ($i = $length; $i > 0; $i >>= 1) {
  133 + $context .= ($i & 1) ? chr(0) : $plaintext[0];
  134 + }
  135 + $binary = self::_bin(md5($context));
  136 +
  137 + for ($i = 0; $i < 1000; $i++) {
  138 + $new = ($i & 1) ? $plaintext : substr($binary, 0, 16);
  139 + if ($i % 3) {
  140 + $new .= $salt;
  141 + }
  142 + if ($i % 7) {
  143 + $new .= $plaintext;
  144 + }
  145 + $new .= ($i & 1) ? substr($binary, 0, 16) : $plaintext;
  146 + $binary = self::_bin(md5($new));
  147 + }
  148 +
  149 + $p = array();
  150 + for ($i = 0; $i < 5; $i++) {
  151 + $k = $i + 6;
  152 + $j = $i + 12;
  153 + if ($j == 16) {
  154 + $j = 5;
  155 + }
  156 + $p[] = self::_toAPRMD5((ord($binary[$i]) << 16) | (ord($binary[$k]) << 8) | (ord($binary[$j])), 5);
  157 + }
  158 +
  159 + return '$apr1$' . $salt . '$' . implode('', $p) . self::_toAPRMD5(ord($binary[11]), 3);
  160 +
  161 + case 'md5-hex' :
  162 +
  163 + default :
  164 + $encrypted = ($salt) ? md5($plaintext . $salt) : md5($plaintext);
  165 + return ($show_encrypt) ? '{MD5}' . $encrypted : $encrypted;
  166 + }
  167 + }
  168 +
  169 + /**
  170 + * Enter description here...
  171 + *
  172 + * @param unknown_type $encryption
  173 + * @param unknown_type $seed
  174 + * @param unknown_type $plaintext
  175 + * @return unknown
  176 + */
  177 + public static function getSalt($encryption = 'md5-hex', $seed = '', $plaintext = '')
  178 + {
  179 + switch ($encryption) {
  180 + case 'crypt' :
  181 + case 'crypt-des' :
  182 + if ($seed) {
  183 + return substr(preg_replace('|^{crypt}|i', '', $seed), 0, 2);
  184 + } else {
  185 + return substr(md5(mt_rand()), 0, 2);
  186 + }
  187 + break;
  188 +
  189 + case 'crypt-md5' :
  190 + if ($seed) {
  191 + return substr(preg_replace('|^{crypt}|i', '', $seed), 0, 12);
  192 + } else {
  193 + return '$1$' . substr(md5(mt_rand()), 0, 8) . '$';
  194 + }
  195 + break;
  196 +
  197 + case 'crypt-blowfish' :
  198 + if ($seed) {
  199 + return substr(preg_replace('|^{crypt}|i', '', $seed), 0, 16);
  200 + } else {
  201 + return '$2$' . substr(md5(mt_rand()), 0, 12) . '$';
  202 + }
  203 + break;
  204 +
  205 + case 'ssha' :
  206 + if ($seed) {
  207 + return substr(preg_replace('|^{SSHA}|', '', $seed), -20);
  208 + } else {
  209 + return mhash_keygen_s2k(MHASH_SHA1, $plaintext, substr(pack('h*', md5(mt_rand())), 0, 8), 4);
  210 + }
  211 + break;
  212 +
  213 + case 'smd5' :
  214 + if ($seed) {
  215 + return substr(preg_replace('|^{SMD5}|', '', $seed), -16);
  216 + } else {
  217 + return mhash_keygen_s2k(MHASH_MD5, $plaintext, substr(pack('h*', md5(mt_rand())), 0, 8), 4);
  218 + }
  219 + break;
  220 +
  221 + case 'aprmd5' :
  222 + /* 64 characters that are valid for APRMD5 passwords. */
  223 + $APRMD5 = './0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz';
  224 +
  225 + if ($seed) {
  226 + return substr(preg_replace('/^\$apr1\$(.{8}).*/', '\\1', $seed), 0, 8);
  227 + } else {
  228 + $salt = '';
  229 + for ($i = 0; $i < 8; $i++) {
  230 + $salt .= $APRMD5{rand(0, 63)};
  231 + }
  232 + return $salt;
  233 + }
  234 + break;
  235 +
  236 + default :
  237 + $salt = '';
  238 + if ($seed) {
  239 + $salt = $seed;
  240 + }
  241 + return $salt;
  242 + break;
  243 + }
  244 + }
  245 +
  246 + public static function genRandom($length = 8)
  247 + {
  248 + $salt = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
  249 + $len = strlen($salt);
  250 + $makepass = '';
  251 +
  252 + $stat = @stat(__FILE__);
  253 + if (empty($stat) || !is_array($stat))
  254 + $stat = array(
  255 + php_uname()
  256 + );
  257 +
  258 + mt_srand(crc32(microtime() . implode('|', $stat)));
  259 +
  260 + for ($i = 0; $i < $length; $i++) {
  261 + $makepass .= $salt[mt_rand(0, $len - 1)];
  262 + }
  263 +
  264 + return $makepass;
  265 + }
  266 +
  267 + public static function _toAPRMD5($value, $count)
  268 + {
  269 + /* 64 characters that are valid for APRMD5 passwords. */
  270 + $APRMD5 = './0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz';
  271 + $aprmd5 = '';
  272 + $count = abs($count);
  273 + while (--$count) {
  274 + $aprmd5 .= $APRMD5[$value & 0x3f];
  275 + $value >>= 6;
  276 + }
  277 + return $aprmd5;
  278 + }
  279 +
  280 + public static function _bin($hex)
  281 + {
  282 + $bin = '';
  283 + $length = strlen($hex);
  284 + for ($i = 0; $i < $length; $i += 2) {
  285 + $tmp = sscanf(substr($hex, $i, 2), '%x');
  286 + $bin .= chr(array_shift($tmp));
  287 + }
  288 + return $bin;
  289 + }
  290 +
  291 + /**
  292 + * 组合一个安全的密码
  293 + * @param $code
  294 + * @return String
  295 + */
  296 + public static function makePass($code)
  297 + {
  298 + $salt = self::genRandom(32);
  299 + $crypt = self::getCrypted($code . $salt, $salt);
  300 + return $crypt . ':' . $salt;
  301 + }
  302 +
  303 + /**
  304 + * 验证密码
  305 + *
  306 + * @param String $inputPassword
  307 + * @param String $password
  308 + * @return bool
  309 + */
  310 + public static function authPassword($inputPassword, $password)
  311 + {
  312 + if (empty($password) || empty($inputPassword)) {
  313 + return false;
  314 + }
  315 + $passwordList = explode(':', trim($password));
  316 + if (count($passwordList) != 2) {
  317 + return false;
  318 + }
  319 + list($crypt, $salt) = $passwordList;
  320 + $decode = self::getCrypted($inputPassword . $salt, $salt);
  321 + if ($crypt != $decode) {
  322 + return false;
  323 + }
  324 + return true;
  325 + }
  326 +
  327 + ############################ 加密规则 ########################
  328 + /**
  329 + * 排序参数
  330 + * @param array $package
  331 + * @return array
  332 + */
  333 + static function packageSort(array $package)
  334 + {
  335 + ksort($package);
  336 + reset($package);
  337 + return $package;
  338 + }
  339 +
  340 + /**
  341 + * 组合签名
  342 + * @param array $package
  343 + * @return string
  344 + */
  345 + static function makeSign(array $package)
  346 + {
  347 + $packageList = array();
  348 + foreach ($package as $key => $val) {
  349 + $packageList[] = trim($key . '=' . $val);
  350 + }
  351 + return strtolower(md5(implode('&', $packageList)));
  352 + }
  353 +
  354 + /**
  355 + * 获取签名
  356 + *
  357 + * @param array $package
  358 + * @return string
  359 + */
  360 + static function getSign(array $package)
  361 + {
  362 + $package = self::packageSort($package);
  363 + return self::makeSign($package);
  364 + }
  365 +
  366 + /**
  367 + * 校验签名
  368 + * @param $submitSign
  369 + * @param $makeSign
  370 + * @return bool
  371 + */
  372 + static function verifySign($submitSign, $makeSign)
  373 + {
  374 + return strtolower($submitSign) == strtolower($makeSign);
  375 + }
  376 +}
  1 +<?php
  2 +/**
  3 + * Created by PhpStorm.
  4 + * User: Zip
  5 + * Date: 14/12/7
  6 + * Time: 上午12:11
  7 + */
  8 +
  9 +namespace Hood\Core;
  10 +
  11 +use Hood\Debug\DebugException;
  12 +
  13 +class Server extends Root
  14 +{
  15 + /**
  16 + * 服务器随机选择模式
  17 + * @var Integer
  18 + */
  19 + const SERVER_SELECT_MODEL_RAND = 1;
  20 +
  21 + /**
  22 + * 服务器选择静态
  23 + * @var Integer
  24 + */
  25 + const SERVER_SELECT_MODEL_STATIC = 2;
  26 +
  27 + /**
  28 + * @var string
  29 + */
  30 + protected $_sectionSeparator = ':';
  31 +
  32 + /**
  33 + * 字符分割
  34 + * @var string
  35 + */
  36 + protected $_nestSeparator = '.';
  37 +
  38 + /**
  39 + * 服务器选择模式
  40 + * @var int
  41 + */
  42 + private $serverSelectModel = 1;
  43 +
  44 + /**
  45 + * ini 数组
  46 + * @var array
  47 + */
  48 + private $iniArray = array();
  49 +
  50 + /**
  51 + * 检查服务状态
  52 + * @var bool
  53 + */
  54 + private $checkServerStatus = true;
  55 +
  56 +
  57 + public function __construct($filename)
  58 + {
  59 + $this->iniArray = $this->_loadIniFile($filename);
  60 + }
  61 +
  62 + /**
  63 + * 设置服务器选择模式
  64 + * @param $model
  65 + * @return $this
  66 + */
  67 + public function setSelectModel($model)
  68 + {
  69 + $this->serverSelectModel = $model;
  70 + return $this;
  71 + }
  72 +
  73 + /**
  74 + * 获取服务器地址
  75 + * @param $section
  76 + * @param $node
  77 + * @param int $model
  78 + * @return array|mixed
  79 + * @throws DebugException
  80 + */
  81 + public function getServerConfig($section, $node = null)
  82 + {
  83 + $sectionArray = $this->_processSection($section);
  84 + if ($node == null) {
  85 + return $sectionArray;
  86 + } elseif (isset($sectionArray[$node])) {
  87 + return $sectionArray[$node];
  88 + }
  89 + return array();
  90 +
  91 + }
  92 +
  93 + /**
  94 + * 选择服务器
  95 + * @param $servers
  96 + * @param $model
  97 + * @return array|mixed
  98 + * @throws DebugException
  99 + */
  100 + public function getServer($servers, $model = 1)
  101 + {
  102 + $serverArray = $this->_parseServer($servers);
  103 + switch ($model) {
  104 + case 1:
  105 + if (count($serverArray) <= 1) {
  106 + $servers = $serverArray;
  107 + } else {
  108 + $servers = $this->_randServer($serverArray);
  109 + }
  110 + break;
  111 + case 2:
  112 + $servers = $serverArray;
  113 + break;
  114 + default:
  115 + throw new DebugException('Server select model not ' . $model);
  116 + }
  117 + return $servers;
  118 + }
  119 +
  120 + /**
  121 + * 获取服务器Map
  122 + * @param $section
  123 + * @param $node
  124 + * @param int $model
  125 + * @return array
  126 + * @throws DebugException
  127 + */
  128 + public function getServerMap($servers, $model = 1)
  129 + {
  130 + $_servers = $this->getServer($servers, $model);
  131 + if (empty($_servers)) {
  132 + return array();
  133 + }
  134 + $_serversMap = array();
  135 + if ($model == 1 && count($_servers) == 1) {
  136 + $_serversMap = $this->_processHost($_servers[0]);
  137 + } elseif ($model == 2) {
  138 + foreach ($_servers as $key => $host) {
  139 + $_serversMap[] = $this->_processHost($host);
  140 + }
  141 + }
  142 + return $_serversMap;
  143 + }
  144 +
  145 + /**
  146 + * 获取所有配置Map
  147 + * @param $section
  148 + * @param $node
  149 + * @return array
  150 + */
  151 + public function getSectionConfig($section, $node)
  152 + {
  153 + $servers = $this->getServerConfig($section, $node);
  154 + $_serversMap = array();
  155 + foreach ($servers as $key => $host) {
  156 + $_serversMap[] = $this->_processHost($host);
  157 + }
  158 + return $_serversMap;
  159 + }
  160 +
  161 + /**
  162 + * 随机&权重随机
  163 + * @param array $server
  164 + * @return mixed
  165 + */
  166 + private function _randServer(array $server)
  167 + {
  168 + if (substr_count($server[0], ':') == 2) {
  169 + $_domain = array();
  170 + foreach ($server as $key => $domain) {
  171 + $_domain[] = $this->_processHost($domain);
  172 + }
  173 + $_server = $this->_countWeight($_domain);
  174 + $_server = $_server['host'] . ':' . $_server['port'] . ':' . $_server['weight'];
  175 + } else {
  176 + $_server = $server[array_rand($server)];
  177 + }
  178 + return $_server;
  179 + }
  180 +
  181 + /**
  182 + * 权重计算
  183 + * @param array $data
  184 + * @return mixed
  185 + */
  186 + private function _countWeight(array $data)
  187 + {
  188 + $weight = 0;
  189 + $tempArray = array();
  190 + foreach ($data as $v) {
  191 + $weight += (int)$v['weight'];
  192 + for ($i = 0; $i < $v['weight']; $i++) {
  193 + $tempArray[] = $v;//放大数组
  194 + }
  195 + }
  196 + $int = mt_rand(0, $weight - 1);//获取一个随机数
  197 + return $tempArray[$int];
  198 + }
  199 +
  200 + /**
  201 + * 解析host
  202 + * @param $domain
  203 + * @return array
  204 + */
  205 + private function _processHost($domain)
  206 + {
  207 + $_hostMap = array();
  208 + $domainArray = explode(':', $domain);
  209 + switch (count($domainArray)) {
  210 + case 2 :
  211 + list($host, $port) = $domainArray;
  212 + $_hostMap = array(
  213 + 'host' => (string)$host,
  214 + 'port' => (int)intval($port)
  215 + );
  216 + break;
  217 + case 3 :
  218 + list($host, $port, $weight) = $domainArray;
  219 + $_hostMap = array(
  220 + 'host' => (string)$host,
  221 + 'port' => (int)intval($port),
  222 + 'weight' => (int)intval($weight)
  223 + );
  224 + break;
  225 + }
  226 + return $_hostMap;
  227 + }
  228 +
  229 + /**
  230 + * 设置检测服务状态
  231 + * @param $check
  232 + * @return $this
  233 + */
  234 + public function setCheckServer($check)
  235 + {
  236 + $this->checkServerStatus = $check;
  237 + return $this;
  238 + }
  239 +
  240 + /**
  241 + * 检查服务
  242 + * @param array $servers
  243 + * @return array
  244 + */
  245 + public function checkServer(array $servers)
  246 + {
  247 + $_servers = array();
  248 + foreach ($servers as $key => $val) {
  249 + $status = $this->ping($val['host'], $val['port']);
  250 + if ($status > 0) {
  251 + $_servers[] = $val;
  252 + }
  253 + }
  254 + return $_servers;
  255 + }
  256 +
  257 + /**
  258 + * 解析Server
  259 + * @param $ips
  260 + * @return array|mixed
  261 + */
  262 + protected function _parseServer($serverString)
  263 + {
  264 + return explode(',', str_replace(array(
  265 + ' ',
  266 + "\n"
  267 + ), '', $serverString));
  268 + }
  269 +
  270 + public function getSection($section)
  271 + {
  272 + return $this->_processSection($section);
  273 + }
  274 +
  275 + public function get($name, $section = null)
  276 + {
  277 + return $this->_processSection($section);
  278 + }
  279 +
  280 + /**
  281 + * 加载ini
  282 + * @param $filename
  283 + * @return array
  284 + * @throws DebugException
  285 + */
  286 + private function _loadIniFile($filename)
  287 + {
  288 + $loaded = $this->_parseIniFile($filename);
  289 + $iniArray = array();
  290 + foreach ($loaded as $key => $data) {
  291 + $pieces = explode($this->_sectionSeparator, $key);
  292 + $thisSection = trim($pieces[0]);
  293 + switch (count($pieces)) {
  294 + case 1:
  295 + $iniArray[$thisSection] = $data;
  296 + break;
  297 + case 2:
  298 + $extendedSection = trim($pieces[1]);
  299 + $iniArray[$thisSection] = array_merge(array(';extends' => $extendedSection), $data);
  300 + break;
  301 + default:
  302 + throw new DebugException("Section '$thisSection' may not extend multiple sections in $filename");
  303 + }
  304 + }
  305 + return $iniArray;
  306 + }
  307 +
  308 + /**
  309 + * 解析ini
  310 + * @param $filename
  311 + * @return array
  312 + */
  313 + private function _parseIniFile($filename)
  314 + {
  315 + if (!file_exists($filename)) {
  316 + throw new DebugException($filename . ' Not Find,');
  317 + }
  318 + $iniArray = parse_ini_file($filename, true);
  319 + if ($iniArray == false) {
  320 + throw new DebugException($filename . ' Not Array.');
  321 + }
  322 + return $iniArray;
  323 + }
  324 +
  325 + /**
  326 + * 解析节点
  327 + * @param $section
  328 + * @return array
  329 + * @throws DebugException
  330 + */
  331 + protected function _processSection($section)
  332 + {
  333 + $config = array();
  334 + $thisSection = array();
  335 + if (isset($this->iniArray[$section])) {
  336 + $thisSection = $this->iniArray[$section];
  337 + }
  338 + foreach ($thisSection as $key => $value) {
  339 + if (strtolower($key) == ';extends') {
  340 + if (isset($this->iniArray[$value])) {
  341 + $config = $this->iniArray[$value] + $config;
  342 + } else {
  343 + throw new DebugException("Parent section '$section' cannot be found");
  344 + }
  345 + } else {
  346 + $config = $this->_processKey($config, $key, $value);
  347 + }
  348 + }
  349 + return $config;
  350 + }
  351 +
  352 + /**
  353 + * 解析键值
  354 + * @param array $config
  355 + * @param $key
  356 + * @param string $val
  357 + * @return array
  358 + */
  359 + protected function _processKey(array $config, $key, $val = '')
  360 + {
  361 + if (strpos($key, $this->_nestSeparator) !== false) {
  362 + $pieces = explode($this->_nestSeparator, $key, 2);
  363 + if (strlen($pieces[0]) && strlen($pieces[1])) {
  364 + if (!isset($config[$pieces[0]])) {
  365 + if ($pieces[0] === '0' && !empty($config)) {
  366 + $config = array($pieces[0] => $config);
  367 + } else {
  368 + $config[$pieces[0]] = array();
  369 + }
  370 + }
  371 + $config[$pieces[0]] = $this->_processKey($config[$pieces[0]], $pieces[1], $val);
  372 + }
  373 + } else {
  374 + $config[$key] = $val;
  375 + }
  376 + return $config;
  377 + }
  378 +
  379 + /**
  380 + * ping
  381 + * @param $domain
  382 + * @param $port
  383 + * @param int $timeout
  384 + * @return float|int|mixed
  385 + */
  386 + public function ping($domain, $port, $timeout = 3)
  387 + {
  388 + $starttime = microtime(true);
  389 + $file = @fsockopen($domain, $port, $errno, $errstr, $timeout);
  390 + $stoptime = microtime(true);
  391 + $status = -1;
  392 + if ($file) {
  393 + stream_set_blocking($file, false);//非堵塞
  394 + stream_set_timeout($file, 3);
  395 + fclose($file);
  396 + $status = ($stoptime - $starttime) * 1000;
  397 + $status = floor($status);
  398 + }
  399 + return $status;
  400 + }
  401 +}