Skip to content

Instantly share code, notes, and snippets.

@qti3e
Created March 2, 2018 19:39
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save qti3e/25dd71610e91bc1cc15dea1b1a8757d0 to your computer and use it in GitHub Desktop.
Save qti3e/25dd71610e91bc1cc15dea1b1a8757d0 to your computer and use it in GitHub Desktop.
Simple Redis Client to understand it's protocol
<?php
/**
* Class myRedisException
*/
class myRedisException extends Exception{
/**
* @var null|string
*/
private $command = '';
/**
* myRedisException constructor.
* @param string $message
* @param null $command
*/
public function __construct($message, $command = null){
$this->message = trim($message);
$this->command = $command;
}
/**
* @return null|string
*/
public function getCommand(){
return $this->command;
}
}
/**
* Class redis
*/
class myRedis{
/**
* @var
*/
private $connection;
/**
* @param $host
* @param int $port
* @return bool
* @throws myRedisException
*/
public function connect($host,$port = 6379){
$connection = @fsockopen($host,$port,$errorN,$errorStr);
if($connection){
$this->connection = $connection;
return true;
}else{
throw new myRedisException("Error when trying to make connection to server(#$errorN):\n\t$errorStr\n");
}
}
public function COMMAND($command,$ar = []){
return $this->runCommand($this->mkCommand($command,$ar));
}
/**
* @param $command
* @param array $ar
* @return string
*/
private function mkCommand($command,$ar = []){
$count = count($ar);
for($i = 0;$i < $count;$i++){
$command .= ' "'.str_replace(["\n","\r"],['\n','\r'],$ar[$i]).'"';
}
return $command;
}
/**
* @param $command
* @return array|bool|int|string
* @throws myRedisException
*/
private function runCommand($command){
$handle = $this->connection;
fwrite($handle,$command."\r\n");
$fl = fgets($handle);//fl:First Line
$re = false;
/**
* http://redis.io/topics/protocol
* In RESP, the type of some data depends on the first byte:
* -For Simple Strings the first byte of the reply is "+"
* -For Errors the first byte of the reply is "-"
* -For Integers the first byte of the reply is ":"
* -For Bulk Strings the first byte of the reply is "$"
* -For Arrays the first byte of the reply is "*"
*/
switch($fl[0]){
case '+'://bool true +OK\r\n
$re = true;
break;
case '-'://bool false -[Error Str]\r\n
throw new myRedisException($fl,$command);
break;
case ':'://Int :[number]\r\n
$re = (int)(substr($fl,1,-2));
break;
case '$'://String $[len]\r\n(...Get more)\r\n
$len = (int)(substr($fl,1,-2))+2;
$size = 0;
while($size < $len){
$size = strlen($re .= fgets($handle));
}
$re = substr($re,0,$len-2);
break;
case '*'://Array $[count]\r\n(..Get more)\r\n
$re = [];
$count = (int)(substr($fl,1,-2));
for($i = 0;$i < $count;$i++){
$l = fgets($handle);
$len = (int)(substr($l,1,-2));
$size= 0;
$str = '';
while($size < $len){
$size = strlen($str .= fgets($handle));
}
$str = substr($str,0,$len);
$re[] = $str;
}
break;
}
return $re;
}
/**
* @param $key
* @param $value
* @return array|bool|int|string
* @throws myRedisException
*/
public function SET($key,$value){
return $this->runCommand($this->mkCommand('SET',[
$key,
$value
]));
}
/**
* @param $key
* @return array|bool|int|string
* @throws myRedisException
*/
public function GET($key){
return $this->runCommand($this->mkCommand('GET',[
$key
]));
}
/**
* @return array|bool|int|string
* @throws myRedisException
*/
public function FLUSHALL(){
return $this->runCommand('FLUSHALL');
}
/**
* @param $key
* @param $field
* @param $value
* @return array|bool|int|string
* @throws myRedisException
*/
public function HSET($key,$field,$value){
return $this->runCommand($this->mkCommand(
'HSET',[
$key,
$field,
$value
]
));
}
/**
* @param $key
* @return array
* @throws myRedisException
*/
public function HGETALL($key){
$re = $this->runCommand($this->mkCommand(
'HGETALL',[
$key
]
));
$return = [];
$count = count($re)/2;
for($i = 0;$i < $count;$i++){
$return[$re[$i*2]] = $re[$i*2+1];
}
return $return;
}
/**
* @param $key
* @param $field
* @return array|bool|int|string
* @throws myRedisException
*/
public function HGET($key,$field){
return $this->runCommand($this->mkCommand(
'HGET',[
$key,
$field
]
));
}
/**
* @param $key
* @return array|bool|int|string
* @throws myRedisException
*/
public function HVALS($key){
return $this->runCommand($this->mkCommand(
'HVALS',[
$key
]
));
}
/**
* @return array|bool|int|string
* @throws myRedisException
*/
public function INFO(){
return $this->runCommand('INFO');
}
/**
* @return mixed
*/
public function VER(){
$info = $this->INFO();
preg_match_all('/redis_version:([0-9\.]+)/',$info,$matches);
return $matches[1][0];
}
/**
* @param $key
* @param $field
* @return array|bool|int|string
* @throws myRedisException
*/
public function HSTRLEN($key,$field){
return $this->runCommand($this->mkCommand(
'HSTRLEN',[
$key,
$field
]
));
}
/**
* @param $key
* @return array|bool|int|string
* @throws myRedisException
*/
public function INCR($key){
return $this->runCommand($this->mkCommand(
'INCR',[
$key
]
));
}
/**
* @param $key
* @return array|bool|int|string
* @throws myRedisException
*/
public function STRLEN($key){
return $this->runCommand($this->mkCommand(
'STRLEN',[
$key
]
));
}
/**
* @param $key
* @param int $value
* @return array|bool|int|string
* @throws myRedisException
*/
public function INCRBY($key,$value){
return $this->runCommand($this->mkCommand(
'INCRBY',[
$key,
$value
]
));
}
/**
* Close socket handler
*/
public function __destruct(){
fclose($this->connection);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment