Update of /cvsroot/phplib/php-lib/php
In directory usw-pr-cvs1:/tmp/cvs-serv2438/php
Added Files:
ct_cookie.inc ct_cookie_rc4.inc
Log Message:
Add ct_cookie.inc, a container class that stores data in cookies.
Also, a documentation page, sample pages using the class for both
sess and user and an ARC4 implementation for encryption.
The basis for this class was posted to the support mailing list by
Ing. Alejandro Vzquez C. <al...@in...> in August 2000.
--- NEW FILE: ct_cookie.inc ---
<?php
##
## Copyright (c) 2000 Alejandro Vázquez C. <al...@ya...>
## Copyright (c) 2001 Richard Archer <rh...@ju...>
## This file is distributed under the GNU Lesser General Public
## License version 2, as distributed by Free Software Foundation.
## Please contact FSF for a copy of the licence terms:
## Free Software Foundation Voice: +1-617-542-5942
## 59 Temple Place - Suite 330 Fax: +1-617-542-2652
## Boston, MA 02111-1307, USA gn...@gn...
##
## $Id: ct_cookie.inc,v 1.1 2001/09/04 00:21:19 richardarcher Exp $
##
## PHPLIB Data Storage Container using cookies
##
/*
This class saves session data in cookies. It does data compression
using gzcompress() and provides md5 validation so an evil user
cannot change the session data.
Another (optional) feature is data encryption. When enabled, the user
cannot see what is inside the cookie. Included is ct_cookie_rc4,
a sample class that implements RC4 compatible encryption.
For best performance it would be best to use one of the crypt
libraries with a native PHP interface.
This container is designed for small apps that do not need to store
large amounts of data. By default, 7396 bytes of cookie data can be
stored (this includes the md5 hash and base64-encoded gzipped data).
Apache rejects any request whose headers are larger than 8190 bytes.
You can hack your Apache to increase this storage limit!
It is useful also for those with limited control over their server
environment. Pages that use ct_cookie.inc do not need any special
sql/db/file configuration.
NOTE: If you use CT_Cookie your session mode must be "cookie".
If sessions fall back to get mode the session data will be lost.
Also note that many people reject cookies while surfing. This makes
CT_Cookie somewhat unreliable, but it can be useful if you offer the
user a choice of storing their profile on the server or in a cookie.
Session cookies ($this->lifetime = 0) may be accepted more often than
permanent cookies.
*/
class CT_Cookie {
var $magic = ""; # CHANGE THIS! It should be a random string.
var $gzlevel = 0; # This is the level of compression desired.
# Requires zlib support in PHP.
# 0 = no compression
# 1 = fast -> 9 = smaller
# -1 = default setting of gzcompress().
var $lifetime = 0; # Lifetime in minutes for cookies.
# 0 = session cookies.
var $cookie_max_length = 3968; # Maximum size for every single cookie.
# The spec says it can be up to 4kb.
var $max_cookies = 2; # Maximum allowed number of cookies.
# The spec says it can be up to 20.
# Maximum amount of data = 4kb*20 = 80kb!
# Note: Apache rejects any request
# whose headers are larger than 8190.
var $cookie_domain = ''; # Domain for cookies.
var $enable_buffering = true; # Set to false if you don't want to
# use ob_start()/ob_end_flush(), however
# you would need to call page_close()
# before any output is made otherwise
# PHP will not be able to send cookies.
# Requires PHP4 for output buffer support.
var $encrypt_class = false; # Name of the class implementing a
# (de)ciphering algorithm.
# false = no encryption (plaintext).
var $encrypt_key = ""; # Encryption key. Set to a random string.
var $last_md5 = false; # Internal variable (to avoid setting the
# same cookie twice).
var $debug = false; # Enables some debug output for troubleshooting
function ac_start() {
if (!isset($this->magic) || $this->magic == "") {
$this->ac_halt("CT_Cookie: you need to change the magic value!<br>".
"If it is known, a hacker can hijack your user's sessions!");
}
if ($this->enable_buffering) {
ob_start();
register_shutdown_function(create_function('', 'ob_end_flush();'));
}
}
function encode_val($val) {
if ($this->gzlevel == -1) {
$gzval = gzcompress($val);
}
else if ($this->gzlevel > 0) {
$gzval = gzcompress($val, $this->gzlevel);
}
else {
$gzval = $val;
}
$md5_val = md5($this->magic . ":{$val}");
if ($this->encrypt_class != false) {
if ($this->encrypt_key == "") {
$this->ac_halt('CT_Cookie: you have to setup the key before using encryption!');
}
$eclass = $this->encrypt_class;
$cipher = new $eclass;
$cipher->setupKey(md5($this->magic . ':' . $this->encrypt_key));
$gzval = $cipher->encrypt($gzval);
}
$encoded_val = $md5_val . base64_encode($gzval);
if (strlen($encoded_val) > ($this->cookie_max_length * $this->max_cookies)) {
if ($this->debug) {
echo ('CT_Cookie: Tried to store too much data in cookies!<br>');
}
return false;
}
$splitted = array();
while(strlen($encoded_val) > $this->cookie_max_length) {
$splitted[] = substr($encoded_val, 0, $this->cookie_max_length);
$encoded_val = substr($encoded_val, $this->cookie_max_length);
}
$splitted[] = $encoded_val;
return $splitted;
}
function decode_val($val) {
if (is_array($val)) {
$encoded_val = implode('', $val);
}
else {
$encoded_val = $val;
}
if (!ereg('^([0-9a-z]{32})([0-9A-Za-z/+=]+)$', $encoded_val, $splitted)) {
if ($this->debug) {
echo ('CT_Cookie debug: Failed to find our data in val!<br>');
}
return false;
}
$md5_val = $splitted[1];
$gzval = @base64_decode($splitted[2]);
if ($this->encrypt_class != false) {
if ($this->encrypt_key == "") {
$this->ac_halt('CT_Cookie: you have to setup the key before using encryption!');
}
$eclass = $this->encrypt_class;
$cipher = new $eclass;
$cipher->setupKey(md5($this->magic . ':' . $this->encrypt_key));
$gzval = $cipher->decrypt($gzval);
}
if ($this->gzlevel != 0) {
$val = @gzuncompress($gzval);
}
else {
$val = $gzval;
}
if (md5($this->magic . ":{$val}") != $md5_val) {
if ($this->debug) {
echo ('CT_Cookie debug: md5 value does not match data!<br>');
}
return false;
}
return $val;
}
function ac_store($id, $name, $str) {
global $HTTP_COOKIE_VARS;
$encoded_val = $this->encode_val($str);
if (!$encoded_val) {
return false;
}
$md5 = substr($encoded_val[0], 0, 32);
if (($this->lifetime == 0) && ($this->last_md5 == $md5)) {
return true;
}
reset($encoded_val);
if ($this->lifetime > 0) {
$then = time()+$this->lifetime*60;
}
else {
$then = 0;
}
$i = 0;
while(list(, $chunk) = each($encoded_val)) {
$cookie_ptr = "{$name}_" . chr($i + 97);
SetCookie($cookie_ptr, $chunk, $then, '/', $this->cookie_domain);
$HTTP_COOKIE_VARS[$cookie_ptr] = $chunk;
$i++;
}
for( ; $i < $this->max_cookies; $i++) {
$cookie_ptr = "{$name}_" . chr($i + 97);
if (isset($HTTP_COOKIE_VARS[$cookie_ptr])) {
SetCookie($cookie_ptr, '', 0, '/', $this->cookie_domain);
unset($HTTP_COOKIE_VARS[$cookie_ptr]);
}
}
return true;
}
function ac_get_value($id, $name) {
global $HTTP_COOKIE_VARS;
$encoded_val = '';
for($i = 0; $i < $this->max_cookies; $i++) {
$cookie_ptr = "{$name}_" . chr($i+97);
if (!isset($HTTP_COOKIE_VARS[$cookie_ptr])) {
break;
}
$encoded_val .= $HTTP_COOKIE_VARS[$cookie_ptr];
}
if (strlen($encoded_val) < 1) {
if ($this->debug) {
echo ("CT_Cookie debug: Cookie decoded to nothing!<br>");
}
return '';
}
$val = $this->decode_val($encoded_val);
if (!$val) {
return '';
}
$this->last_md5 = substr($encoded_val, 0, 32);
return $val;
}
function ac_delete($id, $name) {
global $HTTP_COOKIE_VARS;
if ($HTTP_COOKIE_VARS[$name] != $id) {
if ($this->debug) {
echo ("CT_Cookie debug: No cookies match name=$name and id=$id!<br>");
}
return;
}
for($i = 0; $i < $this->max_cookies; $i++) {
$cookie_ptr = "{$name}_" . chr($i+97);
if (isset($HTTP_COOKIE_VARS[$cookie_ptr])) {
SetCookie($cookie_ptr, '', 0, '/', $this->cookie_domain);
unset($HTTP_COOKIE_VARS[$cookie_ptr]);
}
}
}
function ac_newid($str, $name) {
return $str;
}
function ac_halt($s) {
echo "<b>{$s}</b>";
exit;
}
function ac_get_lock() {
# Nothing needed here.
}
function ac_release_lock() {
# Nothing needed here.
}
function ac_gc($gc_time, $name) {
# Nothing needed here.
}
}
?>
--- NEW FILE: ct_cookie_rc4.inc ---
<?php
##
## Copyright (c) 2000 Alejandro Vázquez C. <al...@ya...>
## This file is distributed under the GNU Lesser General Public
## License version 2, as distributed by Free Software Foundation.
## Please contact FSF for a copy of the licence terms:
## Free Software Foundation Voice: +1-617-542-5942
## 59 Temple Place - Suite 330 Fax: +1-617-542-2652
## Boston, MA 02111-1307, USA gn...@gn...
##
## $Id: ct_cookie_rc4.inc,v 1.1 2001/09/04 00:21:19 richardarcher Exp $
##
## PHPLIB Data Storage Container using cookies - RC4 encryption class
##
/*
This class provides an ciphering engine compatible with RC4.
To implement an alternative encoding you need to declare a class
with the following methods:
function setupKey($key);
It should do everything that is needed to start encoding/decoding
with the supplied key.
function encrypt($val);
It must encode the plaintext stored in $val, and return its ciphertext.
function decrypt($val);
It must decode the ciphertext stored in $val, and return its plaintext.
*/
class CT_Cookie_rc4 {
var $state, $state_save;
function setupKey($key) {
$this->state = array();
for($c = 0; $c < 256; $c++) {
$this->state[$c] = $c;
}
$i = 0;
$j = 0;
$key_len = strlen($key);
for($c = 0; $c < 256; $c++) {
$temp = $this->state[$c];
$j = (ord($key[$i]) + $temp + $j) % 256;
$this->state[$c] = $this->state[$j];
$this->state[$j] = $temp;
$i = ($i + 1) % $key_len;
}
$this->state_save = $this->state;
}
function do_rc4($val) {
$val_len = strlen($val);
$x = 0;
$y = 0;
$ret = '';
for($c = 0; $c < $val_len; $c++) {
$x = ($x + 1) % 256;
$temp = $this->state[$x];
$y = ($temp + $y) % 256;
$this->state[$x] = $this->state[$y];
$this->state[$y] = $temp;
$xorI = ($this->state[$x] + $temp) % 256;
$ret .= chr(ord($val[$c]) ^ $this->state[$xorI]);
}
return $ret;
}
function encrypt($val) {
$this->state = $this->state_save;
return $this->do_rc4($val);
}
function decrypt($val) {
$this->state = $this->state_save;
return $this->do_rc4($val);
}
}
?>
|