CRedisUtil.php 39 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298
  1. <?php
  2. namespace loyalsoft;
  3. //define('Redis_Debug', true); // 调试redis操作
  4. //require __DIR__ . '/Predis/Autoloader.php';
  5. require __DIR__ . '/predis-2.0.0/src/Autoloader.php'; # 2022.8.16 更新Predis代码到2.0
  6. \Predis\Autoloader::register();
  7. /**
  8. * redis操作封装,
  9. * 关于阿里云redis的支持命令和未开放命令见:
  10. * https://docs.aliyun.com/?spm=5176.7630237.9.3.WfKF0A#/pub/kvstore/quick-start/kvstore-redis-command
  11. * 腾讯云支持的命令:
  12. * https://www.qcloud.com/doc/product/239/%E4%BD%BF%E7%94%A8%E9%99%90%E5%88%B6
  13. * redis相关命令说明见:http://redisdoc.com/
  14. *
  15. * 支持命令集接口见: /phpRedisAdmin/predis/src/ClientInterface.php
  16. * @version <br/>
  17. * 1.0.4 取消公共基类CMemBase,后面可能不太会用到memcache(d)了. gwang 2020年11月23日
  18. * 1.0.3 扩展list相关api的操作方法, 针对values统一做json编解码处理.
  19. * 整理其他数据结构的操作方法, normal/hash/list api内部做json编解码处理,
  20. * set/zset value 默认不做json编解码处理, 针对set/zset的value,不推荐写入太大或复杂的数据.
  21. * gwang 2017年4月28日 <br/>
  22. * 1.0.2 扩充特有数据结构的操作方法, gwang 2016.4.21 <br/>
  23. * 1.0.1 扩充了事务的使用方法.开发竞争类业务,圣树争夺战, gwang 2016.3.21 <br/>
  24. * 1.0.0 pguan,基础功能, 方法与memcache看齐. <br/>
  25. */
  26. class CRedisUtil {
  27. // public $keyDic = null;
  28. /**
  29. *
  30. * @var ClientInterface
  31. */
  32. public $redis = null;
  33. /**
  34. * 自动回收
  35. */
  36. function __destruct() {
  37. $this->close();
  38. }
  39. private static function debug() {
  40. if (defined('Redis_Debug') && Redis_Debug) {
  41. DebugHelper::debug(DebugHelper::get_call_stack());
  42. }
  43. }
  44. // <editor-fold defaultstate="collapsed" desc=" 实现CMemBase操作接口">
  45. /**
  46. * 添加一个值
  47. * @param string $key
  48. * @param string $value
  49. * @param int $ts=0 此值无效
  50. * @return true 成功, false 失败,此key已经存在
  51. */
  52. public function add($key, $value, $ts = 0) {
  53. self::debug();
  54. return $this->setnx($key, JsonUtil::encode($value));
  55. }
  56. /**
  57. * 复制一个变量到另一个key
  58. * @param string $surKey 源数据的key
  59. * @param string $desKey 目的数据的key
  60. */
  61. public function copy($surKey, $desKey) {
  62. self::debug();
  63. return $this->set($desKey, $this->get($surKey));
  64. }
  65. /**
  66. * 一次取多个值
  67. * @param array(string) $keys
  68. * @return array
  69. */
  70. public function getMulti($keys) {
  71. self::debug();
  72. // var_dump($keys);
  73. return $this->mget($keys);
  74. }
  75. /**
  76. * 设置多个值
  77. * @param dic $dict [{"key":value},{"key":value},....]
  78. * @return true 永远成功
  79. */
  80. public function setMutlti($dict) {
  81. self::debug();
  82. $params = array();
  83. foreach ($dict as $key => $val) {
  84. $params[$key] = is_string($val) ? $val : JsonUtil::encode($val);
  85. }
  86. if (count($params) <= 0) {
  87. return TRUE;
  88. }
  89. $this->mset($params);
  90. return true;
  91. }
  92. /**
  93. * 替换某个值
  94. * @param string $key
  95. * @param string $value
  96. * @param int $ts
  97. * @return boolean true 成功,false 失败
  98. */
  99. public function replace($key, $value, $ts = 0) {
  100. self::debug();
  101. $ret = $this->redis->setex($key, $value, $ts);
  102. if (strtolower($ret) == "ok") {
  103. return true;
  104. }
  105. $this->logErr("replace" . $ret);
  106. return false;
  107. }
  108. /**
  109. * 不经过jsonencode直接存储
  110. * @deprecated since version 20160413113950 经过自己考察json_encode对数据的影响并不存在
  111. * @param type $key
  112. * @return any
  113. */
  114. public function getWithoutJson($key) {
  115. self::debug();
  116. return $this->redis->get($key);
  117. }
  118. /**
  119. * 不经过jsondecode直接返回
  120. * @deprecated since version 20160413113950 经过自己考察json_encode对数据的影响并不存在
  121. * @param string $key
  122. * @param string $value
  123. * @param int $ts
  124. * @return boolean
  125. */
  126. public function setWithoutJson($key, $value, $ts = 0) {
  127. self::debug();
  128. $ret = $this->redis->set($key, $value, $ts);
  129. if (strtolower($ret) == "ok") {
  130. return true;
  131. }
  132. $this->logErr("set" . $ret);
  133. return false;
  134. }
  135. /**
  136. * 输出日志
  137. * @param mixed $msg
  138. */
  139. private function logErr($msg) {
  140. CLog::err($msg, "Redis Err:");
  141. }
  142. /**
  143. * 连接
  144. * @param string $host
  145. * @param string $port
  146. * @param string $pwd
  147. * @param string $db 数据库, 不建议输入参数, 如果是购买云实例只有一个db.
  148. * @return \CRedisUtil
  149. */
  150. public function conn($host, $port, $pwd = "", $db = 0) {
  151. // DebugHelper::print_stack_trace();
  152. // $this->redis = new \Predis\Client(array(
  153. // $this->redis = new \Redis();
  154. // $this->redis->connect('127.0.0.1', 6379);
  155. // $this->redis->auth($pwd);
  156. $this->redis = new \Predis\Client(array(
  157. 'scheme' => 'tcp',
  158. 'host' => $host,
  159. 'port' => $port,
  160. 'password' => $pwd,
  161. ));
  162. if ($db != 0) {
  163. $this->redis->select($db);
  164. }
  165. // $this->keyDic = new \stdClass();
  166. return $this;
  167. }
  168. /**
  169. * 关闭连接
  170. */
  171. public function close() {
  172. $this->redis->quit();
  173. }
  174. /**
  175. * 获取指定键值
  176. * @param string $key
  177. * @return any json_decode($result)
  178. */
  179. public function get($key) {
  180. self::debug();
  181. $result = $this->redis->get($key);
  182. if (!$result || $result == "" || $result == null) {
  183. return null;
  184. }
  185. // $this->keyDic->$key = $result;
  186. return JsonUtil::decode($result);
  187. }
  188. /**
  189. * 将字符串值 $val 关联到 key
  190. * @param string $key
  191. * @param any $value
  192. * @param int $ts default(0) 过期时间(单位秒)
  193. * @return boolean 成功true,失败false
  194. */
  195. public function set($key, $value, $ts = 0) {
  196. self::debug();
  197. if ($value === null || $value === "") { # 这里必须用全等符号
  198. return false;
  199. }
  200. if (is_string($value)) { # 使用json序列化后存储
  201. $val = $value;
  202. } else {
  203. $val = JsonUtil::encode($value);
  204. }
  205. if ($ts > 0) { # 将会设置TTL 到期删除 ps: replaced by gwang 增加过期时间
  206. $ret = $this->redis->setex($key, $ts, $val);
  207. } else { # 0:永不过期,如果原来有TTL将会清除TTL.
  208. $ret = $this->redis->set($key, $val);
  209. }
  210. if ("OK" != $ret) {
  211. $this->logErr("Set:" . $ret);
  212. return false;
  213. }
  214. return true;
  215. }
  216. /**
  217. * 安全的写入操作
  218. * @deprecated since version 1.0 云平台暂时不支持
  219. * @param string $key
  220. * @param any $value
  221. * @return boolean 成功true,失败false
  222. */
  223. public function cas($key, $value, $ts = 0) {
  224. if (false) { # ps. 各云平台皆不支持eval方法执行lua脚本.等开放支持的时候才是真正支持cas的时候
  225. $castoken = $this->keyDic->$key;
  226. # # 定义一段脚本
  227. $script = <<<casscript
  228. if redis.call("get",KEYS[1]) == "$castoken"
  229. then
  230. return redis.call("set",KEYS[1],ARGV[1])
  231. else
  232. return 0
  233. end
  234. casscript;
  235. $ret = $this->redis->eval($script, 1, $key, $value); # redis 执行lua脚本
  236. if (0 == $ret) {
  237. return false;
  238. }
  239. return true;
  240. }
  241. // 非线程安全,原因见下
  242. return $this->set($key, $value, $ts);
  243. }
  244. /**
  245. * 删除一个指定键值
  246. * @param string $key
  247. * @return int 删除键的个数
  248. */
  249. public function delete($key) {
  250. self::debug();
  251. my_Assert(is_string($key), "arg key should be a string!");
  252. $infos = array();
  253. array_push($infos, $key);
  254. return $this->redis->del($infos);
  255. }
  256. /**
  257. * 删除一个或多个指定键值
  258. * @param array $keys
  259. * @return int 删除键的个数
  260. */
  261. public function deleteMulti($keys) {
  262. self::debug();
  263. $infos = (array) $keys; # 强制转数据类型为数组
  264. return $this->redis->del($infos);
  265. }
  266. // </editor-fold>
  267. //
  268. // <editor-fold defaultstate="collapsed" desc=" normal 普通对象操作 mget/mset">
  269. /**
  270. * 返回所有(一个或多个)给定 key 的值
  271. * 如果给定的 key 里面,有某个 key 不存在,那么这个 key 返回特殊值 nil 。因此,该命令永不失败。
  272. * @param array $keys
  273. * @return array 一个包含所有给定 key 的值的列表
  274. */
  275. private function mget($keys) {
  276. // self::debug();
  277. $ret = array();
  278. if (count($keys)) {
  279. $ctx = $this->redis->mget($keys);
  280. $mval = count($ctx);
  281. for ($i = 0;
  282. $i < $mval;
  283. $i++) {
  284. $ret[] = JsonUtil::decode($ctx[$i]);
  285. }
  286. }
  287. return $ret;
  288. }
  289. /**
  290. * Add函数拥有相同效果 \n
  291. * 将 key 的值设为 value ,当且仅当 key 不存在。
  292. * 若给定的 key 已经存在,则不做任何动作。
  293. * @param type $key
  294. * @param type $val
  295. * @return boolean 成功true,失败false
  296. */
  297. private function setnx($key, $val) {
  298. self::debug();
  299. $ret = $this->redis->setnx($key, $val);
  300. // 成功返回1, 失败返回0
  301. if (1 == $ret) {
  302. return true;
  303. } else {
  304. $this->logErr("setnx:" . $ret . "(值已存在)");
  305. }
  306. return false;
  307. }
  308. /**
  309. * 同时设置一个或多个 key-value 对
  310. * 如果某个给定 key 已经存在,那么 MSET 会用新值覆盖原来的旧值
  311. * @param array $dict
  312. * @return mixed
  313. */
  314. private function mset($dict) {
  315. self::debug();
  316. return $this->redis->mset($dict);
  317. }
  318. /**
  319. * 同时设置一个或多个 key-value 对,当且仅当所有给定 key 都不存在
  320. * 即使只有一个给定 key 已存在, MSETNX 也会拒绝执行所有给定 key 的设置操作
  321. *
  322. * @param array $dict
  323. * @return int
  324. */
  325. public function msetnx($dict) {
  326. self::debug();
  327. $ret = $this->redis->msetnx($dict);
  328. return $ret == 1;
  329. }
  330. /**
  331. * 检测指定键值是否存在
  332. * @param type $key
  333. * @return boolean true 存在, false 不存在
  334. */
  335. public function exists($key) {
  336. self::debug();
  337. return $this->redis->exists($key) == 1;
  338. }
  339. /**
  340. * 将 key 中储存的数字值增一
  341. * 如果 key 不存在,那么 key 的值会先被初始化为 0
  342. * 如果值包含错误的类型,或字符串类型的值不能表示为数字,那么返回一个错误
  343. * 本操作的值限制在 64 位(bit)有符号数字表示之内
  344. * @param type $key
  345. * @return int 执行 INCR 命令之后 key 的值
  346. */
  347. public function increment($key) {
  348. self::debug();
  349. return $this->redis->incr($key);
  350. }
  351. /**
  352. * 将 key 中储存的数字值增加 一个int值
  353. * 如果 key 不存在,那么 key 的值会先被初始化为 0
  354. * 如果值包含错误的类型,或字符串类型的值不能表示为数字,那么返回一个错误
  355. * 本操作的值限制在 64 位(bit)有符号数字表示之内
  356. * @param string $key
  357. * @param int $i 增加的值
  358. * @return int 执行 INCR 命令之后 key 的值
  359. */
  360. public function incrby($key, $i) {
  361. self::debug();
  362. return $this->redis->incrby($key, $i);
  363. }
  364. // </editor-fold>
  365. //
  366. //======================== 以下部分 added by gwang at 2016-4-14 15:17:25 =================
  367. // <editor-fold defaultstate="collapsed" desc=" 辅助函数 ">
  368. /**
  369. * Server功能,看服务器是否连通
  370. * @return boolean true连通正常
  371. */
  372. public function ping() {
  373. $ret = $this->redis->ping();
  374. if ($ret == "PONG") {
  375. return true;
  376. }
  377. $this->logErr("ping:" . $ret);
  378. return false;
  379. }
  380. /**
  381. * 对数组进行json编码
  382. * @param array $values
  383. * @return array
  384. */
  385. static private function json_encode_arr($values) {
  386. $arr = array();
  387. if (is_array($values)) {
  388. $arr = array_map(function ($v) {
  389. return JsonUtil::encode($v);
  390. }, $values);
  391. } else {
  392. $arr[] = JsonUtil::encode($values);
  393. }
  394. return $arr;
  395. }
  396. /**
  397. * 对数组进行json解码
  398. * @param array $values
  399. * @return array
  400. */
  401. static private function json_decode_arr(array $values) {
  402. $arr = array();
  403. if (is_array($values)) {
  404. $arr = array_map(function ($v) {
  405. return JsonUtil::decode($v);
  406. }, $values);
  407. } else {
  408. $arr[] = JsonUtil::decode($values);
  409. }
  410. return $arr;
  411. }
  412. // </editor-fold>
  413. //
  414. // <editor-fold defaultstate="collapsed" desc=" 事务操作 ">
  415. /**
  416. * 监视一个(或多个) key ,如果在事务执行之前这个(或这些) key 被其他命令所改动,那么事务将被打断。
  417. * @param string $key
  418. */
  419. public function watch($key) {
  420. $this->redis->watch($key);
  421. }
  422. /**
  423. * 取消监视
  424. */
  425. public function unwatch() {
  426. $this->redis->unwatch();
  427. }
  428. /**
  429. * 开启事务
  430. */
  431. public function multi() {
  432. $this->redis->multi();
  433. }
  434. /**
  435. * 执行事务
  436. * @return type 事务块内所有命令的返回值,按命令执行的先后顺序排列。当操作被打断时,返回空值 nil 。
  437. */
  438. public function exec() {
  439. return $this->redis->exec();
  440. }
  441. // </editor-fold>
  442. //
  443. // == ↓ 下面是Redis独有的数据类型操作 ↓ ==
  444. //
  445. // <editor-fold defaultstate="collapsed" desc=" set 集合操作 ">
  446. /**
  447. * 集合(set) - 将一个或多个 member 元素加入到集合 key 当中,已经存在于集合的 member 元素将被忽略。
  448. * 集合不存在时将会创建集合
  449. * @param string $key
  450. * @param string[] $members (mixed is ok, i will transmit it.)
  451. * @return int
  452. * @expectedException type not set error
  453. */
  454. public function sadd($key, $members) {
  455. self::debug();
  456. if (!is_array($members)) { # 防御: 参数不为数组
  457. if (!is_string($members)) { # 防御: 参数不为字符串
  458. $members = JsonUtil::encode($members);
  459. }
  460. $members = array($members); # 转为字符串数组
  461. }
  462. return $this->redis->sadd($key, $members);
  463. }
  464. /**
  465. * 集合(set) - 将一个或多个 member 元素从集合 key 当中移除
  466. * 集合不存在时将会创建集合
  467. * @param string $key
  468. * @param string[] $members
  469. * @return int
  470. * @expectedException type not set error
  471. */
  472. public function sremove($key, $members) {
  473. self::debug();
  474. return $this->redis->srem($key, $members);
  475. }
  476. /**
  477. * 集合(set) - 返回集合 key 的基数(集合中元素的数量)。
  478. * @param strig $key
  479. * @return int
  480. */
  481. public function scard($key) {
  482. self::debug();
  483. return $this->redis->scard($key);
  484. }
  485. /**
  486. * 集合(set) - 等效于scard: 返回集合 key 的基数(集合中元素的数量)。
  487. * @param string $key
  488. * @return int
  489. *
  490. */
  491. public function slen($key) {
  492. self::debug();
  493. return $this->scard($key);
  494. }
  495. /**
  496. * 集合(set) - 判断某个元素是否属于集合
  497. * @param string $key
  498. * @param string $member
  499. * @return bool
  500. */
  501. public function sismember($key, $member) {
  502. self::debug();
  503. return $this->redis->sismember($key, $member) == 1;
  504. }
  505. /**
  506. * 集合(set) - 返回集合 key 中的所有成员。
  507. * @param type $key
  508. * @return array 不存在的key视为空集合
  509. */
  510. public function smembers($key) {
  511. self::debug();
  512. return $this->redis->smembers($key);
  513. }
  514. /**
  515. * 集合(set) - 如果命令执行时,只提供了 key 参数,那么返回集合中的10个随机元素。
  516. * 如果 count 为正数,且小于集合基数,那么命令返回一个包含 count 个元素的数组,数组中的元素各不相同。如果 count 大于等于集合基数,那么返回整个集合。
  517. * 如果 count 为负数,那么命令返回一个数组,数组中的元素可能会重复出现多次,而数组的长度为 count 的绝对值。
  518. * @param string $key
  519. * @param int $count =10
  520. * @return array
  521. */
  522. public function srandmember($key, $count = 10) {
  523. self::debug();
  524. return $this->redis->srandmember($key, $count);
  525. }
  526. // </editor-fold>
  527. //
  528. // <editor-fold defaultstate="collapsed" desc=" hash 哈希表操作 ">
  529. /**
  530. * 哈希表 - 删除 字段
  531. * @param string $key
  532. * @param array $fields
  533. * @return int 删除的字段的数量
  534. */
  535. public function hdel($key, $fields) {
  536. self::debug();
  537. return $this->redis->hdel($key, $fields);
  538. }
  539. /**
  540. * 哈希表 - 判断field是否存在
  541. * @param string $key
  542. * @param string $field
  543. * @return boolean true=存在,false 找不到
  544. */
  545. public function hexists($key, $field) {
  546. self::debug();
  547. return $this->redis->hexists($key, $field) == 1;
  548. }
  549. /**
  550. * 哈希表 - 获取字段
  551. * @param string $key
  552. * @param string $field 字段名
  553. * @return mixed json_decoded object
  554. */
  555. public function hget($key, $field) {
  556. self::debug();
  557. $ret = $this->redis->hget($key, $field);
  558. return JsonUtil::decode($ret);
  559. }
  560. /**
  561. * 哈希表 - 获取所有字段
  562. * @param string $key
  563. * @return stdclass/associate_array (适用箭头取变量写法)
  564. */
  565. public function hgetall($key) {
  566. self::debug();
  567. $ret = ArrayInit();
  568. $arr = $this->redis->hgetall($key);
  569. foreach ($arr as $k => $v) {
  570. $ret[$k] = JsonUtil::decode($v);
  571. }
  572. // 转为关联数组({})再返回, 方便代码中使用箭头写法
  573. return JsonUtil::decode(JsonUtil::encode($ret));
  574. }
  575. /**
  576. * 哈希表 - 获取表中字段数量
  577. * @param string $key
  578. * @return int
  579. */
  580. public function hlen($key) {
  581. self::debug();
  582. return $this->redis->hlen($key);
  583. }
  584. /**
  585. * 哈希表 - 同时获取多个字段
  586. * @param string $key
  587. * @param array $fields
  588. * @return Array
  589. */
  590. public function hmget($key, $fields) {
  591. self::debug();
  592. $ret = ArrayInit();
  593. if (is_array($fields) && count($fields) > 0) {
  594. $arr = $this->redis->hmget($key, $fields);
  595. foreach ($arr as $k => $v) {
  596. $ret[$k] = JsonUtil::decode($v);
  597. }
  598. }
  599. // 转为关联数组({})再返回, 方便代码中使用箭头写法
  600. return JsonUtil::decode(JsonUtil::encode($ret));
  601. }
  602. /**
  603. * 哈希表 - 同时设置多个字段的值
  604. * @param string $key
  605. * @param assoc_array $dictionary
  606. * @return boolean true成功
  607. */
  608. public function hmset($key, $dictionary) {
  609. self::debug();
  610. $newdic = ArrayInit();
  611. foreach ($dictionary as $k => $v) {
  612. $newdic[$k] = JsonUtil::encode($v);
  613. }
  614. $ret = $this->redis->hmset($key, $newdic);
  615. if (strtolower($ret) == 'ok') {
  616. return true;
  617. }
  618. return false;
  619. }
  620. /**
  621. * 哈希表 - 同时设置多个字段的值(带Not Changed校验)
  622. * @param string $key
  623. * @param HashSaver $dic (要包含$stVer字段用以校验)
  624. * @return boolean 写入是否成功
  625. */
  626. public function hmset_Cas(string $key, HashSaver $dic) {
  627. # # 定义一段脚本
  628. static $script = <<<Lua
  629. local key,casToken,casVer, dic = KEYS[1], KEYS[2], ARGV[1], ARGV[2]
  630. local cv = redis.call("hget", key, casToken)
  631. local t = cjson.decode( dic )
  632. if not cv or tonumber(cv) < tonumber(casVer) then
  633. for k, v in pairs(t) do
  634. if type(v) =="table" then -- 加戏,如果value是对象的话, 继续encode一下.
  635. v=cjson.encode(v)
  636. end
  637. redis.call("hset", key, k, v)
  638. end
  639. return 1
  640. else
  641. return 0
  642. end
  643. Lua;
  644. try {
  645. $castoken = "stVer";
  646. $casVer = $dic->stVer;
  647. $ret = $this->redis->eval($script, 2, $key, $castoken, $casVer, $dic->toString()); # redis 执行lua脚本
  648. // CLog::err($dic->toString());
  649. if (0 == $ret) {
  650. return false;
  651. }
  652. } catch (\Exception $e) {
  653. CLog::err($e->getMessage());
  654. return false;
  655. }
  656. return true;
  657. }
  658. /**
  659. * 哈希表 - 设置或新建一个字段的值
  660. * @param string $key
  661. * @param string $field
  662. * @param $mixed $value
  663. * @return int 0 覆盖旧值, 1 新建字段
  664. */
  665. public function hset($key, $field, $value) {
  666. self::debug();
  667. return $this->redis->hset($key, $field, JsonUtil::encode($value));
  668. }
  669. /**
  670. * 哈希表 - 增加一个新的field,已经存在则放弃操作返回false
  671. * @param string $key
  672. * @param string $field
  673. * @param string $value
  674. * @return boolean true成功
  675. */
  676. public function hsetnx($key, $field, $value) {
  677. self::debug();
  678. return $this->redis->hsetnx($key, $field, JsonUtil::encode($value)) == 1;
  679. }
  680. /**
  681. * 哈希表 - 按字段赠加 int值
  682. * @param string $key
  683. * @param string $field
  684. * @param int $increment
  685. * @return int
  686. */
  687. public function hincrby($key, $field, $increment) {
  688. self::debug();
  689. return $this->redis->hincrby($key, $field, $increment);
  690. }
  691. /**
  692. * 哈希表 - 按字段增加 float值
  693. * @param string $key
  694. * @param string $field
  695. * @param string $increment float值用string
  696. * @return string 用string存float值
  697. */
  698. public function hincrbyfloat($key, $field, $increment) {
  699. self::debug();
  700. return $this->redis->hincrbyfloat($key, $field, $increment);
  701. }
  702. /**
  703. * @param string $key
  704. * @return array
  705. */
  706. public function hkeys($key) {
  707. self::debug();
  708. return $this->redis->hkeys($key);
  709. }
  710. // * @method array hscan($key, $cursor, array $options = null)
  711. // * @method array hvals($key)
  712. // </editor-fold>
  713. //
  714. // <editor-fold defaultstate="collapsed" desc=" list 链表操作 ">
  715. //
  716. // <editor-fold defaultstate="collapsed" desc=" 阻塞的链表操作 ">
  717. /**
  718. * 链表 - 阻塞弹出, 当列表中没有元素的时候,命令会阻塞,直到等待超时或者有元素被添加到列表中.
  719. * @param array $keys 可以指定多个数组
  720. * @param int $timeout
  721. * @return array
  722. */
  723. public function blpop(array $keys, $timeout) {
  724. self::debug();
  725. $arr = $this->redis->blpop($keys, $timeout);
  726. $arr[1] = JsonUtil::decode($arr[1]); // 对value进行解包
  727. return $arr;
  728. }
  729. /**
  730. * 链表 - 阻塞队尾弹出, 当列表中没有元素的时候,命令会阻塞,直到等待超时或者有元素被添加到列表中.
  731. * @return array
  732. */
  733. public function brpop(array $keys, $timeout) {
  734. self::debug();
  735. $arr = $this->redis->brpop($keys, $timeout);
  736. $arr[1] = JsonUtil::decode($arr[1]);
  737. return $arr;
  738. }
  739. /**
  740. * 链表 - 阻塞版的 队尾弹出插入到队首. 本操作是原子的.
  741. *
  742. * @return array 假如在指定时间内没有任何元素被弹出,则返回一个 nil 和等待时长。
  743. * 反之,返回一个含有两个元素的列表,第一个元素是被弹出元素的值,第二个元素是等待时长。
  744. */
  745. public function brpoplpush($source, $destination, $timeout) {
  746. self::debug();
  747. $arr = $this->redis > brpoplpush($source, $destination, $timeout);
  748. $arr[0] = JsonUtil::decode($arr[0]);
  749. return $arr;
  750. }
  751. // </editor-fold>
  752. //
  753. /**
  754. * 链表 - 返回下标为index的元素
  755. * @return string
  756. */
  757. public function lindex($key, $index) {
  758. self::debug();
  759. $a = $this->redis->lindex($key, $index);
  760. return JsonUtil::decode($a);
  761. }
  762. /**
  763. * 链表 - 返回 链表key的长度
  764. * @return int
  765. * @param type $key
  766. */
  767. public function llen($key) {
  768. self::debug();
  769. return $this->redis->llen($key);
  770. }
  771. /**
  772. * 链表 - 移除并返回链表的队首元素.
  773. * @return string
  774. * @param type $key
  775. */
  776. public function lpop($key) {
  777. self::debug();
  778. $a = $this->redis->lpop($key);
  779. return JsonUtil::decode($a);
  780. }
  781. /**
  782. * 链表 - 向链表插入一个或多个值,链表不存在时创建链表并插入元素
  783. * @return int key存在却不是链表类型时返回一个错误.
  784. * @param type $key
  785. * @param array $values
  786. */
  787. public function lpush($key, $values) {
  788. self::debug();
  789. $arr = self::json_encode_arr($values);
  790. return $this->redis->lpush($key, $arr);
  791. }
  792. /**
  793. * 链表 - 取链表中指定下标区间的元素
  794. * @return array
  795. * @param string $key
  796. * @param int $start
  797. * @param int $stop
  798. */
  799. public function lrange($key, $start, $stop) {
  800. self::debug();
  801. $values = $this->redis->lrange($key, $start, $stop);
  802. return self::json_decode_arr($values);
  803. }
  804. /**
  805. * 链表 - 移除链表中 count 个值为 value的元素.
  806. * @return int
  807. * @param string $key
  808. * @param int $count
  809. * @param string $value
  810. */
  811. public function lrem($key, $count, $value) {
  812. self::debug();
  813. return $this->redis->lrem($key, $count, JsonUtil::encode($value));
  814. }
  815. /**
  816. * 链表 - 将链表中下标为index的 元素设置为value
  817. * @return mixed
  818. *
  819. * @param type $key
  820. * @param type $index
  821. * @param type $value
  822. */
  823. public function lset($key, $index, $value) {
  824. self::debug();
  825. return $this->redis->lset($key, $index, JsonUtil::encode($value));
  826. }
  827. /**
  828. * 链表 - 对链表进行修剪, 让链表只保留指定下标区间的元素,其余元素删除
  829. * @return bool true 成功, false 失败
  830. * @param string $key
  831. * @param int $start
  832. * @param int $stop
  833. */
  834. public function ltrim($key, $start, $stop) {
  835. self::debug();
  836. // return mixed: ok or fails
  837. $ret = $this->redis->ltrim($key, $start, $stop);
  838. if (strtolower($ret) == 'ok') {
  839. return true;
  840. }
  841. return false;
  842. }
  843. /**
  844. * 链表 - 从链表右侧(尾部)弹出一个元素,并返回该元素
  845. * @param string $key
  846. * @return string 列表的尾元素。当 key 不存在时,返回 nil
  847. */
  848. public function rpop($key) {
  849. self::debug();
  850. return JsonUtil::decode($this->redis->rpop($key));
  851. }
  852. /**
  853. * 将一个或多个值 value 插入到列表 key 的表尾(最右边)。
  854. * @param string $key
  855. * @param array $values
  856. * @return int
  857. */
  858. public function rpush($key, array $values) {
  859. self::debug();
  860. $arr = self::json_encode_arr($values);
  861. return $this->redis->rpush($key, $arr);
  862. }
  863. //
  864. // /**
  865. // * 链表 - 向链表中插入一个或多个值,链表不存在时,什么也不做.
  866. // * @return int
  867. // * @param type $key
  868. // * @param type $value
  869. // */
  870. // public function lpushx($key, $value)
  871. // {
  872. // return $this->redis->lpushx($key, $value);
  873. // }
  874. // /**
  875. // * 链表 - 将值 value 插入到链表 key 中 , 位于pivot之前或之后
  876. // * @return int -1:未找到pivot, 0:链表为空或者不存在.
  877. // *
  878. // * @param string $key 链表名称
  879. // * @param string $whence after/before pivot之前或之后
  880. // * @param string $pivot 插入pivot之前或之后
  881. // * @param string $value 要插入的value
  882. // */
  883. // public function linsert($key, $whence, $pivot, $value)
  884. // {
  885. // $this->redis->linsert($key, $whence, $pivot, $value);
  886. // }
  887. // /**
  888. // * 在一个原子时间内,执行以下两个动作
  889. // * 将列表 source 中的最后一个元素(尾元素)弹出,并返回给客户端。
  890. // * 将 source 弹出的元素插入到列表 destination ,作为 destination 列表的的头元素.
  891. // * @return string
  892. // */
  893. // public function rpoplpush($source, $destination)
  894. // {
  895. // throw new Exception("un implemented now!");
  896. // }
  897. // /**
  898. // * 将值 value 插入到列表 key 的表尾,当且仅当 key 存在并且是一个列表。
  899. // * 和 RPUSH 命令相反,当 key 不存在时, RPUSHX 命令什么也不做。
  900. // * @param type $key
  901. // * @param type $value
  902. // * @return int
  903. // */
  904. // public function rpushx($key, $value)
  905. // {
  906. // throw new Exception("un implemented now!");
  907. // }
  908. // </editor-fold>
  909. //
  910. // <editor-fold defaultstate="collapsed" desc=" zset 有序集合 ">
  911. /**
  912. * 有序集合 - 添加或更新元素 对于zset类型不建议写入太长, 太复杂的value
  913. * @param string $key
  914. * @param array $membersAndScoresDictionary array( 'value'=>score,'value'=>score,...), score可以是int或float
  915. * @return int 新增元素数量,不包含更新的元素
  916. */
  917. public function zadd($key, $membersAndScoresDictionary) {
  918. self::debug();
  919. return $this->redis->zadd($key, $membersAndScoresDictionary);
  920. }
  921. /**
  922. * 有序集合 - 给某个元素增加积分
  923. * @param string $key
  924. * @param string $member
  925. * @param int $increment
  926. * @return string
  927. */
  928. public function zincrby($key, $member, $increment = 1) {
  929. self::debug();
  930. return $this->redis->zincrby($key, $increment, $member);
  931. }
  932. /**
  933. * 有序集合 - 元素数量
  934. * @param string $key
  935. * @return int
  936. */
  937. public function zlen($key) {
  938. self::debug();
  939. return $this->redis->zcard($key);
  940. }
  941. /**
  942. * 有序集合 - 统计某区间元素数量
  943. * @param string $key
  944. * @param int/float $min 最低分
  945. * @param int/float $max 最高分
  946. * @return int
  947. */
  948. public function zcount($key, $min, $max) {
  949. self::debug();
  950. return $this->redis->zcount($key, $min, $max);
  951. }
  952. /**
  953. * 有序集合 - 获取集合指定区间内的成员, 第一个成员从0开始
  954. * @param string $key
  955. * @param int $start
  956. * @param int $stop Ps.以 -1 表示最后一个成员, -2 表示倒数第二个成员
  957. * @param boolean $withScore 返回值中是否带score字段
  958. * @return array (index=>member) or assoc_array (member=>score)
  959. */
  960. public function zrange($key, $start, $stop, $withScore = false) {
  961. self::debug();
  962. if ($withScore) {
  963. return $this->redis->zrange($key, $start, $stop, 'WITHSCORES');
  964. } else {
  965. return $this->redis->zrange($key, $start, $stop);
  966. }
  967. if ($withScore) {
  968. $ret = $this->redis->zrange($key, $start, $stop, 'WITHSCORES');
  969. DebugHelper::var_dump($ret);
  970. $ma = count($ret);
  971. $arr = array();
  972. for ($i = 0; $i < $ma; $i += 2) {
  973. $arr[$ret[$i]] = $ret[$i + 1];
  974. }
  975. return $arr;
  976. } else {
  977. $ret = $this->redis->zrange($key, $start, $stop);
  978. DebugHelper::var_dump($ret);
  979. return $ret;
  980. }
  981. }
  982. /**
  983. *
  984. * 有序集合 - 获取集合倒序之后,指定区间内的成员, 第一个成员从0开始
  985. * @param string $key
  986. * @param int $start
  987. * @param int $stop Ps.以 -1 表示最后一个成员, -2 表示倒数第二个成员
  988. * @param boolean $withScore 返回值中是否带score字段 default(false)
  989. * @return array (index=>member) or assoc_array (member=>score) 用foreach(=>)取
  990. */
  991. public function zrevrange($key, $start, $stop, $withScore = false) {
  992. self::debug();
  993. if ($withScore) {
  994. $r = $this->redis->zrevrange($key, $start, $stop, 'WITHSCORES');
  995. return $r;
  996. } else {
  997. return $this->redis->zrevrange($key, $start, $stop);
  998. }
  999. }
  1000. /**
  1001. *
  1002. * 有序列表 - 获取指定积分区间内的成员
  1003. * @param string $key
  1004. * @param int/float $min
  1005. * @param int/float $max
  1006. * @param boolean $withScore
  1007. * @param bool $limit 是否限制返回值大小
  1008. * @param int $offset 限制返回结果的起始位置
  1009. * @param type $count 返回结果的数量
  1010. * @return type
  1011. */
  1012. public function zrangebyscore($key, $min, $max, $withScore = false, $limit = false, $offset = 0, $count = 10) {
  1013. self::debug();
  1014. if ($limit) {
  1015. if ($withScore) {
  1016. return $this->redis->zrangebyscore($key, $min, $max, 'WITHSCORES', "LIMIT", $offset, $count);
  1017. } else {
  1018. return $this->redis->zrangebyscore($key, $min, $max, 'LIMIT', $offset, $count);
  1019. }
  1020. } else {
  1021. if ($withScore) {
  1022. return $this->redis->zrangebyscore($key, $min, $max, 'WITHSCORES');
  1023. } else {
  1024. return $this->redis->zrangebyscore($key, $min, $max);
  1025. }
  1026. }
  1027. }
  1028. /**
  1029. *
  1030. * 有序列表 - 获取按照倒序排序后指定积分区间内的成员
  1031. * @param string $key
  1032. * @param int/float $max
  1033. * @param int/float $min
  1034. * @param boolean $withScore
  1035. * @param bool $limit 是否限制返回值大小
  1036. * @param int $offset 限制返回结果的起始位置
  1037. * @param type $count 返回结果的数量
  1038. * @return type
  1039. */
  1040. public function zrevrangebyscore($key, $max, $min, $withScore = false, $limit = false, $offset = 0, $count = 10) {
  1041. self::debug();
  1042. if ($limit) {
  1043. if ($withScore) {
  1044. return $this->redis->zrevrangebyscore($key, $max, $min, 'WITHSCORES', "LIMIT", $offset, $count);
  1045. } else {
  1046. return $this->redis->zrevrangebyscore($key, $max, $min, 'LIMIT', $offset, $count);
  1047. }
  1048. } else {
  1049. if ($withScore) {
  1050. return $this->redis->zrevrangebyscore($key, $max, $min, 'WITHSCORES');
  1051. } else {
  1052. return $this->redis->zrevrangebyscore($key, $max, $min);
  1053. }
  1054. }
  1055. }
  1056. /**
  1057. * 有序列表 - 根据元素反查排名
  1058. * @param string $key
  1059. * @param string $member
  1060. * @return int
  1061. */
  1062. public function zrank($key, $member) {
  1063. self::debug();
  1064. return $this->redis->zrank($key, $member);
  1065. }
  1066. /**
  1067. * 有序列表 - 查询某个成员的倒序排名
  1068. * @param string $key
  1069. * @param string $member
  1070. * @return int
  1071. */
  1072. public function zrevrank($key, $member) {
  1073. self::debug();
  1074. return $this->redis->zrevrank($key, $member);
  1075. }
  1076. /**
  1077. * 有序列表 - 根据元素反查积分
  1078. * @param string $key
  1079. * @param string $member
  1080. * @return int/float
  1081. */
  1082. public function zscore($key, $member) {
  1083. self::debug();
  1084. return $this->redis->zscore($key, $member);
  1085. }
  1086. /**
  1087. * 有序列表 - 移除元素
  1088. * @param string $key
  1089. * @param string $member
  1090. */
  1091. public function zrem($key, $member) {
  1092. self::debug();
  1093. $this->redis->zrem($key, $member);
  1094. }
  1095. /**
  1096. * 有序列表 - 移除指定区间的元素
  1097. * @param string $key
  1098. * @param int $start
  1099. * @param int $stop
  1100. */
  1101. public function zremrangebyrank($key, $start, $stop) {
  1102. self::debug();
  1103. $this->redis->zremrangebyrank($key, $start, $stop);
  1104. }
  1105. /**
  1106. * 有序列表 - 移除指定积分区间的元素.
  1107. * @param string $key
  1108. * @param int/float $min
  1109. * @param int/float $max
  1110. */
  1111. public function zremrangebyscore($key, $min, $max) {
  1112. self::debug();
  1113. $this->redis->zremrangebyscore($key, $min, $max);
  1114. }
  1115. /**
  1116. * 有序列表 - 复制有序类表到一个新的key
  1117. * @param string $key_source 源集合
  1118. * @param string $key_new 目标集合
  1119. */
  1120. public function zcopy($key_source, $key_new) {
  1121. self::debug();
  1122. $this->redis->zunionstore($key_new, 1, $key_source);
  1123. }
  1124. // </editor-fold>
  1125. //
  1126. // <editor-fold defaultstate="collapsed" desc=" 其他api ">
  1127. //
  1128. /**
  1129. * 重命名一个key(注意: 与move的区别, move是将数据迁移到其他db,rename相当于在当前db内move)
  1130. * @param type $key
  1131. * @param type $newkey
  1132. * @return boolean
  1133. */
  1134. public function rename($key, $newkey) {
  1135. self::debug();
  1136. return $this->redis->rename($key, $newkey) == "ok";
  1137. }
  1138. /**
  1139. * 给指定的key设置/更新生存时间
  1140. * @param string $key
  1141. * @param number $seconds
  1142. * @return bool
  1143. */
  1144. public function expire($key, $seconds) {
  1145. self::debug();
  1146. return $this->redis->expire($key, $seconds) == "ok";
  1147. }
  1148. // == end of zSet ===
  1149. // * @method string zincrby($key, $increment, $member)
  1150. // * @method int zinterstore($destination, array $keys, array $options = null)
  1151. // * @method array zrevrangebyscore($key, $min, $max, array $options = null)
  1152. // * @method int zunionstore($destination, array $keys, array $options = null)
  1153. // * @method array zscan($key, $cursor, array $options = null)
  1154. // * @method array zrangebylex($key, $start, $stop, array $options = null)
  1155. // * @method int zremrangebylex($key, $min, $max)
  1156. // === end of zSet 操作 =====
  1157. // ======= hash 操作 ======
  1158. //
  1159. // // ======== set 操作 ======
  1160. // * @method array sdiff(array $keys)
  1161. // * @method int sdiffstore($destination, array $keys)
  1162. // * @method array sinter(array $keys)
  1163. // * @method int sinterstore($destination, array $keys)
  1164. //
  1165. // * @method int smove($source, $destination, $member)
  1166. // * @method string spop($key)
  1167. // * @method array sscan($key, $cursor, array $options = null)
  1168. // * @method array sunion(array $keys)
  1169. // * @method int sunionstore($destination, array $keys)
  1170. // ======= 订阅相关api =======s
  1171. // * @method int pfadd($key, array $elements)
  1172. // * @method mixed pfmerge($destinationKey, array $sourceKeys)
  1173. // * @method int pfcount(array $keys)
  1174. // * @method mixed pubsub($subcommand, $argument)
  1175. // * @method int publish($channel, $message)
  1176. // *
  1177. // ======= 事务相关api =======
  1178. // * @method mixed discard()
  1179. public function discard() {
  1180. return $this->redis->discard();
  1181. }
  1182. // * @method array exec()
  1183. // * @method mixed multi()
  1184. // * @method mixed unwatch()
  1185. // * @method mixed watch($key)
  1186. // ======= 执行lua脚本 =======
  1187. // * @method mixed eval($script, $numkeys, $keyOrArg1 = null, $keyOrArgN = null)
  1188. // * @method mixed evalsha($script, $numkeys, $keyOrArg1 = null, $keyOrArgN = null)
  1189. // * @method mixed script($subcommand, $argument = null)
  1190. // ======= 服务器操作api ======
  1191. // * @method mixed auth($password)
  1192. // * @method string echo($message)
  1193. // * @method mixed ping($message = null)
  1194. // * @method mixed select($database)
  1195. // * @method mixed bgrewriteaof()
  1196. // * @method mixed bgsave()
  1197. // </editor-fold>
  1198. }