<?php defined('BASEPATH') OR
exit
('No direct script access allowed');
class
CI_Redis {
private
$_ci
;
private
$_connection
;
public
$debug
= FALSE;
const
CRLF =
"\r\n"
;
public
function
construct(
$params
=
array
())
{
log_message('debug', 'Redis Class Initialized');
$this
->_ci = get_instance();
$this
->_ci->load->config(
'redis'
);
if
(isset(
$params
[
'connection_group'
]))
{
$config
=
$this
->_ci->config->item(
'redis_'
.
$params
[
'connection_group'
]);
}
elseif
(
is_array
(
$this
->_ci->config->item(
'redis_default'
)))
{
$config
=
$this
->_ci->config->item(
'redis_default'
);
}
else
{
$config
=
array
(
'host'
=>
$this
->_ci->config->item(
'redis_host'
),
'port'
=>
$this
->_ci->config->item(
'redis_port'
),
'password'
=>
$this
->_ci->config->item(
'redis_password'
),
);
}
$this
->_connection = @
fsockopen
(
$config
[
'host'
],
$config
[
'port'
],
$errno
,
$errstr
, 3);
if
( !
$this
->_connection)
{
show_error(
'Could not connect to Redis at '
.
$config
[
'host'
] .
':'
.
$config
[
'port'
]);
}
$this
->_auth(
$config
[
'password'
]);
}
public
function
call(
$method
,
$arguments
)
{
$request
=
$this
->_encode_request(
$method
,
$arguments
);
return
$this
->_write_request(
$request
);
}
public
function
command(
$string
)
{
$slices
=
explode
(
' '
,
$string
);
$request
=
$this
->_encode_request(
$slices
[0],
array_slice
(
$slices
, 1));
return
$this
->_write_request(
$request
);
}
private
function
_auth(
$password
= NULL)
{
if
( !
empty
(
$password
))
{
if
(
$this
->command(
'AUTH '
.
$password
) !==
'OK'
)
{
show_error(
'Could not connect to Redis, invalid password'
);
}
}
}
public
function
_clear_socket()
{
fflush
(
$this
->_connection);
return
NULL;
}
private
function
_write_request(
$request
)
{
if
(
$this
->debug === TRUE)
{
log_message(
'debug'
,
'Redis unified request: '
.
$request
);
}
$value_length
=
strlen
(
$request
);
if
(
$value_length
<= 0)
return
NULL;
if
(
$value_length
<= 8192)
{
fwrite(
$this
->_connection,
$request
);
}
else
{
while
(
$value_length
> 0)
{
if
(
$value_length
> 8192) {
$send_size
= 8192;
}
fwrite(
$this
->_connection,
$request
,
$send_size
);
$value_length
=
$value_length
-
$send_size
;
$request
=
substr
(
$request
,
$send_size
,
$value_length
);
}
}
$return
=
$this
->_read_request();
$this
->_clear_socket();
return
$return
;
}
private
function
_read_request()
{
$type
=
fgetc
(
$this
->_connection);
$response_types
=
array
(
'+'
,
'-'
,
':'
,
'$'
,
'*'
);
$type_error_limit
= 50;
$try
= 0;
while
( ! in_array(
$type
,
$response_types
) &&
$try
<
$type_error_limit
)
{
$type
=
fgetc
(
$this
->_connection);
$try
++;
}
if
(
$this
->debug === TRUE)
{
log_message(
'debug'
,
'Redis response type: '
.
$type
);
}
switch
(
$type
)
{
case
'+'
:
return
$this
->_single_line_reply();
break
;
case
'-'
:
return
$this
->_error_reply();
break
;
case
':'
:
return
$this
->_integer_reply();
break
;
case
'$'
:
return
$this
->_bulk_reply();
break
;
case
'*'
:
return
$this
->_multi_bulk_reply();
break
;
default
:
return
FALSE;
}
}
private
function
_single_line_reply()
{
$value
= rtrim(
fgets
(
$this
->_connection));
$this
->_clear_socket();
return
$value
;
}
private
function
_error_reply()
{
$error
=
substr
(rtrim(
fgets
(
$this
->_connection)), 4);
log_message(
'error'
,
'Redis server returned an error: '
.
$error
);
$this
->_clear_socket();
return
FALSE;
}
private
function
_integer_reply()
{
return
(int) rtrim(
fgets
(
$this
->_connection));
}
private
function
_bulk_reply()
{
$value_length
= (int)
fgets
(
$this
->_connection);
if
(
$value_length
<= 0)
return
NULL;
$response
= '';
if
(
$value_length
<= 8192)
{
$response
=
fread
(
$this
->_connection,
$value_length
);
}
else
{
$data_left
=
$value_length
;
while
(
$data_left
> 0 ) {
if
(
$data_left
> 8192)
{
$read_size
= 8192;
}
else
{
$read_size
=
$data_left
;
}
$chunk
=
fread
(
$this
->_connection,
$read_size
);
$chunk_length
=
strlen
(
$chunk
);
while
(
$chunk_length
<
$read_size
)
{
$keep_reading
=
$read_size
-
$chunk_length
;
$chunk
.=
fread
(
$this
->_connection,
$keep_reading
);
$chunk_length
=
strlen
(
$chunk
);
}
$response
.=
$chunk
;
$data_left
=
$data_left
-
$read_size
;
}
}
$this
->_clear_socket();
return
isset(
$response
) ?
$response
: FALSE;
}
private
function
_multi_bulk_reply()
{
$response
=
array
();
$total_values
= (int)
fgets
(
$this
->_connection);
for
(
$i
= 0;
$i
<
$total_values
;
$i
++)
{
fgets
(
$this
->_connection, 2);
if
(
$i
> 0)
{
fgets
(
$this
->_connection);
fgets
(
$this
->_connection, 2);
}
$response
[] =
$this
->_bulk_reply();
}
$this
->_clear_socket();
return
isset(
$response
) ?
$response
: FALSE;
}
private
function
_encode_request(
$method
,
$arguments
=
array
())
{
$request
=
'$'
.
strlen
(
$method
) . self::CRLF .
$method
. self::CRLF;
$_args
= 1;
foreach
(
$arguments
as
$argument
)
{
if
(
is_array
(
$argument
))
{
foreach
(
$argument
as
$key
=>
$value
)
{
if
(!
is_int
(
$key
))
{
$request
.=
'$'
.
strlen
(
$key
) . self::CRLF .
$key
. self::CRLF;
$_args
++;
}
$request
.=
'$'
.
strlen
(
$value
) . self::CRLF .
$value
. self::CRLF;
$_args
++;
}
}
else
{
$request
.=
'$'
.
strlen
(
$argument
) . self::CRLF .
$argument
. self::CRLF;
$_args
++;
}
}
$request
=
'*'
.
$_args
. self::CRLF .
$request
;
return
$request
;
}
public
function
info(
$section
= FALSE)
{
if
(
$section
!== FALSE)
{
$response
=
$this
->command(
'INFO '
.
$section
);
}
else
{
$response
=
$this
->command(
'INFO'
);
}
$data
=
array
();
$lines
=
explode
(self::CRLF,
$response
);
foreach
(
$lines
as
$line
)
{
$parts
=
explode
(
':'
,
$line
);
if
(isset(
$parts
[1]))
$data
[
$parts
[0]] =
$parts
[1];
}
return
$data
;
}
public
function
debug(
$bool
)
{
$this
->debug = (bool)
$bool
;
}
function
destruct()
{
if
(
$this
->_connection) fclose(
$this
->_connection);
}
}
?>