[ Index ] |
|
Code source de LifeType 1.2.4 |
1 <?php 2 // 3 // +---------------------------------------------------------------------------+ 4 // | memcached client, PHP | 5 // +---------------------------------------------------------------------------+ 6 // | Copyright (c) 2003 Ryan T. Dean <rtdean@cytherianage.net> | 7 // | All rights reserved. | 8 // | | 9 // | Redistribution and use in source and binary forms, with or without | 10 // | modification, are permitted provided that the following conditions | 11 // | are met: | 12 // | | 13 // | 1. Redistributions of source code must retain the above copyright | 14 // | notice, this list of conditions and the following disclaimer. | 15 // | 2. Redistributions in binary form must reproduce the above copyright | 16 // | notice, this list of conditions and the following disclaimer in the | 17 // | documentation and/or other materials provided with the distribution. | 18 // | | 19 // | THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR | 20 // | IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES | 21 // | OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. | 22 // | IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, | 23 // | INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT | 24 // | NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | 25 // | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | 26 // | THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | 27 // | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF | 28 // | THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | 29 // +---------------------------------------------------------------------------+ 30 // | Author: Ryan T. Dean <rtdean@cytherianage.net> | 31 // | Heavily influenced by the Perl memcached client by Brad Fitzpatrick. | 32 // | Permission granted by Brad Fitzpatrick for relicense of ported Perl | 33 // | client logic under 2-clause BSD license. | 34 // +---------------------------------------------------------------------------+ 35 // 36 // $TCAnet$ 37 // 38 39 /** 40 * This is the PHP client for memcached - a distributed memory cache daemon. 41 * More information is available at http://www.danga.com/memcached/ 42 * 43 * Usage example: 44 * 45 * require_once 'memcached.php'; 46 * 47 * $mc = new memcached(array( 48 * 'servers' => array('127.0.0.1:10000', 49 * array('192.0.0.1:10010', 2), 50 * '127.0.0.1:10020'), 51 * 'debug' => false, 52 * 'compress_threshold' => 10240, 53 * 'persistant' => true)); 54 * 55 * $mc->add('key', array('some', 'array')); 56 * $mc->replace('key', 'some random string'); 57 * $val = $mc->get('key'); 58 * 59 * @author Ryan T. Dean <rtdean@cytherianage.net> 60 * @package memcached-client 61 * @version 0.1.2 62 */ 63 64 // {{{ requirements 65 // }}} 66 67 // {{{ constants 68 // {{{ flags 69 70 /** 71 * Flag: indicates data is serialized 72 */ 73 define("MEMCACHE_SERIALIZED", 1<<0); 74 75 /** 76 * Flag: indicates data is compressed 77 */ 78 define("MEMCACHE_COMPRESSED", 1<<1); 79 80 // }}} 81 82 /** 83 * Minimum savings to store data compressed 84 */ 85 define("COMPRESSION_SAVINGS", 0.20); 86 87 // }}} 88 89 // {{{ class memcached 90 /** 91 * memcached client class implemented using (p)fsockopen() 92 * 93 * @author Ryan T. Dean <rtdean@cytherianage.net> 94 * @package memcached-client 95 */ 96 class memcached 97 { 98 // {{{ properties 99 // {{{ public 100 101 /** 102 * Command statistics 103 * 104 * @var array 105 * @access public 106 */ 107 var $stats; 108 109 // }}} 110 // {{{ private 111 112 /** 113 * Cached Sockets that are connected 114 * 115 * @var array 116 * @access private 117 */ 118 var $_cache_sock; 119 120 /** 121 * Current debug status; 0 - none to 9 - profiling 122 * 123 * @var boolean 124 * @access private 125 */ 126 var $_debug; 127 128 /** 129 * Dead hosts, assoc array, 'host'=>'unixtime when ok to check again' 130 * 131 * @var array 132 * @access private 133 */ 134 var $_host_dead; 135 136 /** 137 * Is compression available? 138 * 139 * @var boolean 140 * @access private 141 */ 142 var $_have_zlib; 143 144 /** 145 * Do we want to use compression? 146 * 147 * @var boolean 148 * @access private 149 */ 150 var $_compress_enable; 151 152 /** 153 * At how many bytes should we compress? 154 * 155 * @var interger 156 * @access private 157 */ 158 var $_compress_threshold; 159 160 /** 161 * Are we using persistant links? 162 * 163 * @var boolean 164 * @access private 165 */ 166 var $_persistant; 167 168 /** 169 * If only using one server; contains ip:port to connect to 170 * 171 * @var string 172 * @access private 173 */ 174 var $_single_sock; 175 176 /** 177 * Array containing ip:port or array(ip:port, weight) 178 * 179 * @var array 180 * @access private 181 */ 182 var $_servers; 183 184 /** 185 * Our bit buckets 186 * 187 * @var array 188 * @access private 189 */ 190 var $_buckets; 191 192 /** 193 * Total # of bit buckets we have 194 * 195 * @var interger 196 * @access private 197 */ 198 var $_bucketcount; 199 200 /** 201 * # of total servers we have 202 * 203 * @var interger 204 * @access private 205 */ 206 var $_active; 207 208 /** 209 * Stream timeout in seconds. Applies for example to fread() 210 * 211 * @var integer 212 * @access private 213 */ 214 var $_timeout_seconds; 215 216 /** 217 * Stream timeout in microseconds 218 * 219 * @var integer 220 * @access private 221 */ 222 var $_timeout_microseconds; 223 224 // }}} 225 // }}} 226 // {{{ methods 227 // {{{ public functions 228 // {{{ memcached() 229 230 /** 231 * Memcache initializer 232 * 233 * @param array $args Associative array of settings 234 * 235 * @return mixed 236 * @access public 237 */ 238 function memcached ($args) 239 { 240 $this->set_servers(@$args['servers']); 241 $this->_debug = @$args['debug']; 242 $this->stats = array(); 243 $this->_compress_threshold = @$args['compress_threshold']; 244 $this->_persistant = array_key_exists('persistant', $args) ? (@$args['persistant']) : false; 245 $this->_compress_enable = true; 246 $this->_have_zlib = function_exists("gzcompress"); 247 248 $this->_cache_sock = array(); 249 $this->_host_dead = array(); 250 251 $this->_timeout_seconds = 1; 252 $this->_timeout_microseconds = 0; 253 } 254 255 // }}} 256 // {{{ add() 257 258 /** 259 * Adds a key/value to the memcache server if one isn't already set with 260 * that key 261 * 262 * @param string $key Key to set with data 263 * @param mixed $val Value to store 264 * @param interger $exp (optional) Time to expire data at 265 * 266 * @return boolean 267 * @access public 268 */ 269 function add ($key, $val, $exp = 0) 270 { 271 return $this->_set('add', $key, $val, $exp); 272 } 273 274 // }}} 275 // {{{ decr() 276 277 /** 278 * Decriment a value stored on the memcache server 279 * 280 * @param string $key Key to decriment 281 * @param interger $amt (optional) Amount to decriment 282 * 283 * @return mixed FALSE on failure, value on success 284 * @access public 285 */ 286 function decr ($key, $amt=1) 287 { 288 return $this->_incrdecr('decr', $key, $amt); 289 } 290 291 // }}} 292 // {{{ delete() 293 294 /** 295 * Deletes a key from the server, optionally after $time 296 * 297 * @param string $key Key to delete 298 * @param interger $time (optional) How long to wait before deleting 299 * 300 * @return boolean TRUE on success, FALSE on failure 301 * @access public 302 */ 303 function delete ($key, $time = 0) 304 { 305 if (!$this->_active) 306 return false; 307 308 $sock = $this->get_sock($key); 309 if (!is_resource($sock)) 310 return false; 311 312 $key = is_array($key) ? $key[1] : $key; 313 314 @$this->stats['delete']++; 315 $cmd = "delete $key $time\r\n"; 316 if(!$this->_safe_fwrite($sock, $cmd, strlen($cmd))) 317 { 318 $this->_dead_sock($sock); 319 return false; 320 } 321 $res = trim(fgets($sock)); 322 323 if ($this->_debug) 324 $this->_debugprint(sprintf("MemCache: delete %s (%s)\n", $key, $res)); 325 326 if ($res == "DELETED") 327 return true; 328 return false; 329 } 330 331 // }}} 332 // {{{ flush_all() 333 334 /** 335 * Flush all keys from the server 336 * 337 * @return boolean Always TRUE 338 * @access public 339 */ 340 function flush_all () 341 { 342 if (!$this->_active) 343 return false; 344 345 foreach ($this->_servers as $server) 346 { 347 if (is_array($server)) 348 { 349 for ($i=0; $i<$server[1]; $i++) 350 $hosts[] = $server[0]; 351 } else 352 { 353 $hosts[] = $server; 354 } 355 } 356 357 foreach ($hosts as $host) 358 { 359 $sock = $this->sock_to_host($host); 360 if (is_resource($sock)) { 361 $this->_flush_read_buffer($sock); 362 363 @$this->stats['flush_all']++; 364 $cmd = "flush_all\r\n"; 365 if(!$this->_safe_fwrite($sock, $cmd, strlen($cmd))) 366 { 367 $this->_dead_sock($sock); 368 continue; 369 } 370 $res = trim(fgets($sock)); 371 372 if ($this->_debug) 373 $this->_debugprint(sprintf("MemCache: flush_all %s (%s)\n", $host, $res)); 374 } 375 } 376 return true; 377 } 378 379 // }}} 380 // {{{ disconnect_all() 381 382 /** 383 * Disconnects all connected sockets 384 * 385 * @access public 386 */ 387 function disconnect_all () 388 { 389 foreach ($this->_cache_sock as $sock) 390 fclose($sock); 391 392 $this->_cache_sock = array(); 393 } 394 395 // }}} 396 // {{{ enable_compress() 397 398 /** 399 * Enable / Disable compression 400 * 401 * @param boolean $enable TRUE to enable, FALSE to disable 402 * 403 * @access public 404 */ 405 function enable_compress ($enable) 406 { 407 $this->_compress_enable = $enable; 408 } 409 410 // }}} 411 // {{{ forget_dead_hosts() 412 413 /** 414 * Forget about all of the dead hosts 415 * 416 * @access public 417 */ 418 function forget_dead_hosts () 419 { 420 $this->_host_dead = array(); 421 } 422 423 // }}} 424 // {{{ get() 425 426 /** 427 * Retrieves the value associated with the key from the memcache server 428 * 429 * @param string $key Key to retrieve 430 * 431 * @return mixed 432 * @access public 433 */ 434 function get ($key) 435 { 436 if (!$this->_active) { 437 return false; 438 } 439 440 $sock = $this->get_sock($key); 441 442 if (!is_resource($sock)) { 443 return false; 444 } 445 446 @$this->stats['get']++; 447 448 $cmd = "get $key\r\n"; 449 if (!$this->_safe_fwrite($sock, $cmd, strlen($cmd))) 450 { 451 $this->_dead_sock($sock); 452 return false; 453 } 454 455 $val = array(); 456 $this->_load_items($sock, $val); 457 458 if ($this->_debug) 459 foreach ($val as $k => $v) 460 $this->_debugprint(@sprintf("MemCache: sock %s got %s => %s\r\n", serialize($sock), $k, $v)); 461 462 return @$val[$key]; 463 } 464 465 // }}} 466 // {{{ get_multi() 467 468 /** 469 * Get multiple keys from the server(s) 470 * 471 * @param array $keys Keys to retrieve 472 * 473 * @return array 474 * @access public 475 */ 476 function get_multi ($keys) 477 { 478 if (!$this->_active) 479 return false; 480 481 $this->stats['get_multi']++; 482 483 foreach ($keys as $key) 484 { 485 $sock = $this->get_sock($key); 486 if (!is_resource($sock)) continue; 487 $key = is_array($key) ? $key[1] : $key; 488 if (!isset($sock_keys[$sock])) 489 { 490 $sock_keys[$sock] = array(); 491 $socks[] = $sock; 492 } 493 $sock_keys[$sock][] = $key; 494 } 495 496 // Send out the requests 497 foreach ($socks as $sock) 498 { 499 $cmd = "get"; 500 foreach ($sock_keys[$sock] as $key) 501 { 502 $cmd .= " ". $key; 503 } 504 $cmd .= "\r\n"; 505 506 if ($this->_safe_fwrite($sock, $cmd, strlen($cmd))) 507 { 508 $gather[] = $sock; 509 } else 510 { 511 $this->_dead_sock($sock); 512 } 513 } 514 515 // Parse responses 516 $val = array(); 517 foreach ($gather as $sock) 518 { 519 $this->_load_items($sock, $val); 520 } 521 522 if ($this->_debug) 523 foreach ($val as $k => $v) 524 $this->_debugprint(sprintf("MemCache: got %s => %s\r\n", $k, $v)); 525 526 return $val; 527 } 528 529 // }}} 530 // {{{ incr() 531 532 /** 533 * Increments $key (optionally) by $amt 534 * 535 * @param string $key Key to increment 536 * @param interger $amt (optional) amount to increment 537 * 538 * @return interger New key value? 539 * @access public 540 */ 541 function incr ($key, $amt=1) 542 { 543 return $this->_incrdecr('incr', $key, $amt); 544 } 545 546 // }}} 547 // {{{ replace() 548 549 /** 550 * Overwrites an existing value for key; only works if key is already set 551 * 552 * @param string $key Key to set value as 553 * @param mixed $value Value to store 554 * @param interger $exp (optional) Experiation time 555 * 556 * @return boolean 557 * @access public 558 */ 559 function replace ($key, $value, $exp=0) 560 { 561 return $this->_set('replace', $key, $value, $exp); 562 } 563 564 // }}} 565 // {{{ run_command() 566 567 /** 568 * Passes through $cmd to the memcache server connected by $sock; returns 569 * output as an array (null array if no output) 570 * 571 * NOTE: due to a possible bug in how PHP reads while using fgets(), each 572 * line may not be terminated by a \r\n. More specifically, my testing 573 * has shown that, on FreeBSD at least, each line is terminated only 574 * with a \n. This is with the PHP flag auto_detect_line_endings set 575 * to falase (the default). 576 * 577 * @param resource $sock Socket to send command on 578 * @param string $cmd Command to run 579 * 580 * @return array Output array 581 * @access public 582 */ 583 function run_command ($sock, $cmd) 584 { 585 if (!is_resource($sock)) 586 return array(); 587 588 if (!$this->_safe_fwrite($sock, $cmd, strlen($cmd))) 589 return array(); 590 591 while (true) 592 { 593 $res = fgets($sock); 594 $ret[] = $res; 595 if (preg_match('/^END/', $res)) 596 break; 597 if (strlen($res) == 0) 598 break; 599 } 600 return $ret; 601 } 602 603 // }}} 604 // {{{ set() 605 606 /** 607 * Unconditionally sets a key to a given value in the memcache. Returns true 608 * if set successfully. 609 * 610 * @param string $key Key to set value as 611 * @param mixed $value Value to set 612 * @param interger $exp (optional) Experiation time 613 * 614 * @return boolean TRUE on success 615 * @access public 616 */ 617 function set ($key, $value, $exp=0) 618 { 619 return $this->_set('set', $key, $value, $exp); 620 } 621 622 // }}} 623 // {{{ set_compress_threshold() 624 625 /** 626 * Sets the compression threshold 627 * 628 * @param interger $thresh Threshold to compress if larger than 629 * 630 * @access public 631 */ 632 function set_compress_threshold ($thresh) 633 { 634 $this->_compress_threshold = $thresh; 635 } 636 637 // }}} 638 // {{{ set_debug() 639 640 /** 641 * Sets the debug flag 642 * 643 * @param boolean $dbg TRUE for debugging, FALSE otherwise 644 * 645 * @access public 646 * 647 * @see memcahced::memcached 648 */ 649 function set_debug ($dbg) 650 { 651 $this->_debug = $dbg; 652 } 653 654 // }}} 655 // {{{ set_servers() 656 657 /** 658 * Sets the server list to distribute key gets and puts between 659 * 660 * @param array $list Array of servers to connect to 661 * 662 * @access public 663 * 664 * @see memcached::memcached() 665 */ 666 function set_servers ($list) 667 { 668 $this->_servers = $list; 669 $this->_active = count($list); 670 $this->_buckets = null; 671 $this->_bucketcount = 0; 672 673 $this->_single_sock = null; 674 if ($this->_active == 1) 675 $this->_single_sock = $this->_servers[0]; 676 } 677 678 /** 679 * Sets the timeout for new connections 680 * 681 * @param integer $seconds Number of seconds 682 * @param integer $microseconds Number of microseconds 683 * 684 * @access public 685 */ 686 function set_timeout ($seconds, $microseconds) 687 { 688 $this->_timeout_seconds = $seconds; 689 $this->_timeout_microseconds = $microseconds; 690 } 691 692 // }}} 693 // }}} 694 // {{{ private methods 695 // {{{ _close_sock() 696 697 /** 698 * Close the specified socket 699 * 700 * @param string $sock Socket to close 701 * 702 * @access private 703 */ 704 function _close_sock ($sock) 705 { 706 $host = array_search($sock, $this->_cache_sock); 707 fclose($this->_cache_sock[$host]); 708 unset($this->_cache_sock[$host]); 709 } 710 711 // }}} 712 // {{{ _connect_sock() 713 714 /** 715 * Connects $sock to $host, timing out after $timeout 716 * 717 * @param interger $sock Socket to connect 718 * @param string $host Host:IP to connect to 719 * @param float $timeout (optional) Timeout value, defaults to 0.25s 720 * 721 * @return boolean 722 * @access private 723 */ 724 function _connect_sock (&$sock, $host, $timeout = 0.25) 725 { 726 list ($ip, $port) = explode(":", $host); 727 if ($this->_persistant == 1) 728 { 729 $sock = @pfsockopen($ip, $port, $errno, $errstr, $timeout); 730 } else 731 { 732 $sock = @fsockopen($ip, $port, $errno, $errstr, $timeout); 733 } 734 735 if (!$sock) { 736 if ($this->_debug) 737 $this->_debugprint( "Error connecting to $host: $errstr\n" ); 738 return false; 739 } 740 741 // Initialise timeout 742 stream_set_timeout($sock, $this->_timeout_seconds, $this->_timeout_microseconds); 743 744 return true; 745 } 746 747 // }}} 748 // {{{ _dead_sock() 749 750 /** 751 * Marks a host as dead until 30-40 seconds in the future 752 * 753 * @param string $sock Socket to mark as dead 754 * 755 * @access private 756 */ 757 function _dead_sock ($sock) 758 { 759 $host = array_search($sock, $this->_cache_sock); 760 @list ($ip, $port) = explode(":", $host); 761 $this->_host_dead[$ip] = time() + 30 + intval(rand(0, 10)); 762 $this->_host_dead[$host] = $this->_host_dead[$ip]; 763 unset($this->_cache_sock[$host]); 764 } 765 766 // }}} 767 // {{{ get_sock() 768 769 /** 770 * get_sock 771 * 772 * @param string $key Key to retrieve value for; 773 * 774 * @return mixed resource on success, false on failure 775 * @access private 776 */ 777 function get_sock ($key) 778 { 779 if (!$this->_active) 780 return false; 781 782 if ($this->_single_sock !== null) { 783 $this->_flush_read_buffer($this->_single_sock); 784 return $this->sock_to_host($this->_single_sock); 785 } 786 787 $hv = is_array($key) ? intval($key[0]) : $this->_hashfunc($key); 788 789 if ($this->_buckets === null) 790 { 791 foreach ($this->_servers as $v) 792 { 793 if (is_array($v)) 794 { 795 for ($i=0; $i<$v[1]; $i++) 796 $bu[] = $v[0]; 797 } else 798 { 799 $bu[] = $v; 800 } 801 } 802 $this->_buckets = $bu; 803 $this->_bucketcount = count($bu); 804 } 805 806 $realkey = is_array($key) ? $key[1] : $key; 807 for ($tries = 0; $tries<20; $tries++) 808 { 809 $host = $this->_buckets[$hv % $this->_bucketcount]; 810 $sock = $this->sock_to_host($host); 811 if (is_resource($sock)) { 812 $this->_flush_read_buffer($sock); 813 return $sock; 814 } 815 $hv += $this->_hashfunc($tries . $realkey); 816 } 817 818 return false; 819 } 820 821 // }}} 822 // {{{ _hashfunc() 823 824 /** 825 * Creates a hash interger based on the $key 826 * 827 * @param string $key Key to hash 828 * 829 * @return interger Hash value 830 * @access private 831 */ 832 function _hashfunc ($key) 833 { 834 # Hash function must on [0,0x7ffffff] 835 # We take the first 31 bits of the MD5 hash, which unlike the hash 836 # function used in a previous version of this client, works 837 return hexdec(substr(md5($key),0,8)) & 0x7fffffff; 838 } 839 840 // }}} 841 // {{{ _incrdecr() 842 843 /** 844 * Perform increment/decriment on $key 845 * 846 * @param string $cmd Command to perform 847 * @param string $key Key to perform it on 848 * @param interger $amt Amount to adjust 849 * 850 * @return interger New value of $key 851 * @access private 852 */ 853 function _incrdecr ($cmd, $key, $amt=1) 854 { 855 if (!$this->_active) 856 return null; 857 858 $sock = $this->get_sock($key); 859 if (!is_resource($sock)) 860 return null; 861 862 $key = is_array($key) ? $key[1] : $key; 863 @$this->stats[$cmd]++; 864 if (!$this->_safe_fwrite($sock, "$cmd $key $amt\r\n")) 865 return $this->_dead_sock($sock); 866 867 stream_set_timeout($sock, 1, 0); 868 $line = fgets($sock); 869 if (!preg_match('/^(\d+)/', $line, $match)) 870 return null; 871 return $match[1]; 872 } 873 874 // }}} 875 // {{{ _load_items() 876 877 /** 878 * Load items into $ret from $sock 879 * 880 * @param resource $sock Socket to read from 881 * @param array $ret Returned values 882 * 883 * @access private 884 */ 885 function _load_items ($sock, &$ret) 886 { 887 while (1) 888 { 889 $decl = fgets($sock); 890 if ($decl == "END\r\n") 891 { 892 return true; 893 } elseif (preg_match('/^VALUE (\S+) (\d+) (\d+)\r\n$/', $decl, $match)) 894 { 895 list($rkey, $flags, $len) = array($match[1], $match[2], $match[3]); 896 $bneed = $len+2; 897 $offset = 0; 898 899 while ($bneed > 0) 900 { 901 $data = fread($sock, $bneed); 902 $n = strlen($data); 903 if ($n == 0) 904 break; 905 $offset += $n; 906 $bneed -= $n; 907 @$ret[$rkey] .= $data; 908 } 909 910 if ($offset != $len+2) 911 { 912 // Something is borked! 913 if ($this->_debug) 914 $this->_debugprint(sprintf("Something is borked! key %s expecting %d got %d length\n", $rkey, $len+2, $offset)); 915 916 unset($ret[$rkey]); 917 $this->_close_sock($sock); 918 return false; 919 } 920 921 if ($this->_have_zlib && $flags & MEMCACHE_COMPRESSED) 922 $ret[$rkey] = gzuncompress($ret[$rkey]); 923 924 $ret[$rkey] = rtrim($ret[$rkey]); 925 926 if ($flags & MEMCACHE_SERIALIZED) 927 $ret[$rkey] = unserialize($ret[$rkey]); 928 929 } else 930 { 931 $this->_debugprint("Error parsing memcached response\n"); 932 return 0; 933 } 934 } 935 } 936 937 // }}} 938 // {{{ _set() 939 940 /** 941 * Performs the requested storage operation to the memcache server 942 * 943 * @param string $cmd Command to perform 944 * @param string $key Key to act on 945 * @param mixed $val What we need to store 946 * @param interger $exp When it should expire 947 * 948 * @return boolean 949 * @access private 950 */ 951 function _set ($cmd, $key, $val, $exp) 952 { 953 if (!$this->_active) 954 return false; 955 956 $sock = $this->get_sock($key); 957 if (!is_resource($sock)) 958 return false; 959 960 @$this->stats[$cmd]++; 961 962 $flags = 0; 963 964 if (!is_scalar($val)) 965 { 966 $val = serialize($val); 967 $flags |= MEMCACHE_SERIALIZED; 968 if ($this->_debug) 969 $this->_debugprint(sprintf("client: serializing data as it is not scalar\n")); 970 } 971 972 $len = strlen($val); 973 974 if ($this->_have_zlib && $this->_compress_enable && 975 $this->_compress_threshold && $len >= $this->_compress_threshold) 976 { 977 $c_val = gzcompress($val, 9); 978 $c_len = strlen($c_val); 979 980 if ($c_len < $len*(1 - COMPRESSION_SAVINGS)) 981 { 982 if ($this->_debug) 983 $this->_debugprint(sprintf("client: compressing data; was %d bytes is now %d bytes\n", $len, $c_len)); 984 $val = $c_val; 985 $len = $c_len; 986 $flags |= MEMCACHE_COMPRESSED; 987 } 988 } 989 if (!$this->_safe_fwrite($sock, "$cmd $key $flags $exp $len\r\n$val\r\n")) 990 return $this->_dead_sock($sock); 991 992 $line = trim(fgets($sock)); 993 994 if ($this->_debug) 995 { 996 if ($flags & MEMCACHE_COMPRESSED) 997 $val = 'compressed data'; 998 $this->_debugprint(sprintf("MemCache: %s %s => %s (%s)\n", $cmd, $key, $val, $line)); 999 } 1000 if ($line == "STORED") 1001 return true; 1002 return false; 1003 } 1004 1005 // }}} 1006 // {{{ sock_to_host() 1007 1008 /** 1009 * Returns the socket for the host 1010 * 1011 * @param string $host Host:IP to get socket for 1012 * 1013 * @return mixed IO Stream or false 1014 * @access private 1015 */ 1016 function sock_to_host ($host) 1017 { 1018 if (isset($this->_cache_sock[$host])) 1019 return $this->_cache_sock[$host]; 1020 1021 $now = time(); 1022 list ($ip, $port) = explode (":", $host); 1023 if (isset($this->_host_dead[$host]) && $this->_host_dead[$host] > $now || 1024 isset($this->_host_dead[$ip]) && $this->_host_dead[$ip] > $now) 1025 return null; 1026 1027 if (!$this->_connect_sock($sock, $host)) 1028 return $this->_dead_sock($host); 1029 1030 // Do not buffer writes 1031 stream_set_write_buffer($sock, 0); 1032 1033 $this->_cache_sock[$host] = $sock; 1034 1035 return $this->_cache_sock[$host]; 1036 } 1037 1038 function _debugprint($str){ 1039 print($str); 1040 } 1041 1042 /** 1043 * Write to a stream, timing out after the correct amount of time 1044 * 1045 * @return bool false on failure, true on success 1046 */ 1047 function _safe_fwrite($f, $buf, $len = false) { 1048 if ($len === false) { 1049 $bytesWritten = @fwrite($f, $buf); 1050 } else { 1051 $bytesWritten = @fwrite($f, $buf, $len); 1052 } 1053 return $bytesWritten; 1054 } 1055 1056 /** 1057 * Flush the read buffer of a stream 1058 */ 1059 function _flush_read_buffer($f) { 1060 if (!is_resource($f)) { 1061 return; 1062 } 1063 $n = stream_select($r=array($f), $w = NULL, $e = NULL, 0, 0); 1064 while ($n == 1 && !feof($f)) { 1065 fread($f, 1024); 1066 $n = stream_select($r=array($f), $w = NULL, $e = NULL, 0, 0); 1067 } 1068 } 1069 1070 // }}} 1071 // }}} 1072 // }}} 1073 } 1074 1075 // vim: sts=3 sw=3 et 1076 1077 // }}} 1078 ?>
titre
Description
Corps
titre
Description
Corps
titre
Description
Corps
titre
Corps
Généré le : Mon Nov 26 21:04:15 2007 | par Balluche grâce à PHPXref 0.7 |
![]() |