PHP  
 PHP: Test and Code Coverage Analysis
downloads | QA | documentation | faq | getting help | mailing lists | reporting bugs | php.net sites | links | my php.net 
 

LTP GCOV extension - code coverage report
Current view: directory - zlib - zlib_filter.c
Test: PHP Code Coverage
Date: 2009-11-23 Instrumented lines: 213
Code covered: 78.9 % Executed lines: 168
Legend: not executed executed

       1                 : /*
       2                 :    +----------------------------------------------------------------------+
       3                 :    | PHP Version 6                                                        |
       4                 :    +----------------------------------------------------------------------+
       5                 :    | Copyright (c) 1997-2009 The PHP Group                                |
       6                 :    +----------------------------------------------------------------------+
       7                 :    | This source file is subject to version 3.01 of the PHP license,      |
       8                 :    | that is bundled with this package in the file LICENSE, and is        |
       9                 :    | available through the world-wide-web at the following url:           |
      10                 :    | http://www.php.net/license/3_01.txt                                  |
      11                 :    | If you did not receive a copy of the PHP license and are unable to   |
      12                 :    | obtain it through the world-wide-web, please send a note to          |
      13                 :    | license@php.net so we can mail you a copy immediately.               |
      14                 :    +----------------------------------------------------------------------+
      15                 :    | Authors: Sara Golemon (pollita@php.net)                              |
      16                 :    +----------------------------------------------------------------------+
      17                 : */
      18                 : 
      19                 : /* $Id: zlib_filter.c 287926 2009-08-31 21:18:55Z jani $ */
      20                 : 
      21                 : #include "php.h"
      22                 : #include "php_zlib.h"
      23                 : 
      24                 : /* {{{ data structure */
      25                 : 
      26                 : /* Passed as opaque in malloc callbacks */
      27                 : typedef struct _php_zlib_filter_data {
      28                 :         int persistent;
      29                 :         z_stream strm;
      30                 :         char *inbuf;
      31                 :         size_t inbuf_len;
      32                 :         char *outbuf;
      33                 :         size_t outbuf_len;
      34                 :         zend_bool finished;
      35                 : } php_zlib_filter_data;
      36                 : 
      37                 : /* }}} */
      38                 : 
      39                 : /* {{{ Memory management wrappers */
      40                 : 
      41                 : static voidpf php_zlib_alloc(voidpf opaque, uInt items, uInt size)
      42             279 : {
      43             279 :         return (voidpf)safe_pemalloc(items, size, 0, ((php_zlib_filter_data*)opaque)->persistent);
      44                 : }
      45                 : 
      46                 : static void php_zlib_free(voidpf opaque, voidpf address)
      47             279 : {
      48             279 :         pefree((void*)address, ((php_zlib_filter_data*)opaque)->persistent);
      49             279 : }
      50                 : /* }}} */
      51                 : 
      52                 : /* {{{ zlib.inflate filter implementation */
      53                 : 
      54                 : static php_stream_filter_status_t php_zlib_inflate_filter(
      55                 :         php_stream *stream,
      56                 :         php_stream_filter *thisfilter,
      57                 :         php_stream_bucket_brigade *buckets_in,
      58                 :         php_stream_bucket_brigade *buckets_out,
      59                 :         size_t *bytes_consumed,
      60                 :         int flags
      61                 :         TSRMLS_DC)
      62             122 : {
      63                 :         php_zlib_filter_data *data;
      64                 :         php_stream_bucket *bucket;
      65             122 :         size_t consumed = 0, original_out, original_in;
      66                 :         int status;
      67             122 :         php_stream_filter_status_t exit_status = PSFS_FEED_ME;
      68                 :         z_stream *streamp;
      69                 : 
      70             122 :         if (!thisfilter || !thisfilter->abstract) {
      71                 :                 /* Should never happen */
      72               0 :                 return PSFS_ERR_FATAL;
      73                 :         }
      74                 : 
      75             122 :         data = (php_zlib_filter_data *)(thisfilter->abstract);
      76             122 :         streamp = &(data->strm);
      77             122 :         original_in = data->strm.total_in;
      78             122 :         original_out = data->strm.total_out;
      79                 : 
      80             289 :         while (buckets_in->head) {
      81              51 :                 size_t bin = 0, desired;
      82                 : 
      83              51 :                 bucket = buckets_in->head;
      84                 : 
      85              51 :                 if (bucket->buf_type == IS_UNICODE) {
      86                 :                         /* inflation not allowed for unicode data */
      87               0 :                         return PSFS_ERR_FATAL;
      88                 :                 }
      89                 : 
      90              51 :                 bucket = php_stream_bucket_make_writeable(buckets_in->head TSRMLS_CC);
      91             295 :                 while (bin < (unsigned int) bucket->buflen) {
      92                 : 
      93             205 :                         if (data->finished) {
      94               6 :                                 consumed += bucket->buflen;
      95               6 :                                 break;
      96                 :                         }
      97                 : 
      98             199 :                         desired = bucket->buflen - bin;
      99             199 :                         if (desired > data->inbuf_len) {
     100             112 :                                 desired = data->inbuf_len;
     101                 :                         }
     102             199 :                         memcpy(data->strm.next_in, bucket->buf.s + bin, desired);
     103             199 :                         data->strm.avail_in = desired;
     104                 : 
     105             199 :                         status = inflate(&(data->strm), flags & PSFS_FLAG_FLUSH_CLOSE ? Z_FINISH : Z_SYNC_FLUSH);
     106             199 :                         if (status == Z_STREAM_END) {
     107              45 :                                 inflateEnd(&(data->strm));
     108              45 :                                 data->finished = '\1';
     109             154 :                         } else if (status != Z_OK) {
     110                 :                                 /* Something bad happened */
     111               5 :                                 php_stream_bucket_delref(bucket TSRMLS_CC);
     112               5 :                                 return PSFS_ERR_FATAL;
     113                 :                         }
     114             194 :                         desired -= data->strm.avail_in; /* desired becomes what we consumed this round through */
     115             194 :                         data->strm.next_in = data->inbuf;
     116             194 :                         data->strm.avail_in = 0;
     117             194 :                         bin += desired;
     118                 : 
     119             194 :                         if (data->strm.avail_out < data->outbuf_len) {
     120                 :                                 php_stream_bucket *out_bucket;
     121             192 :                                 size_t bucketlen = data->outbuf_len - data->strm.avail_out;
     122             192 :                                 out_bucket = php_stream_bucket_new(stream, estrndup(data->outbuf, bucketlen), bucketlen, 1, 0 TSRMLS_CC);
     123             192 :                                 php_stream_bucket_append(buckets_out, out_bucket TSRMLS_CC);
     124             192 :                                 data->strm.avail_out = data->outbuf_len;
     125             192 :                                 data->strm.next_out = data->outbuf;
     126             192 :                                 exit_status = PSFS_PASS_ON;
     127               2 :                         } else if (status == Z_STREAM_END && data->strm.avail_out >= data->outbuf_len) {
     128                 :                                 /* no more data to decompress, and nothing was spat out */
     129               1 :                                 php_stream_bucket_delref(bucket TSRMLS_CC);
     130               1 :                                 return PSFS_PASS_ON;
     131                 :                         }
     132                 : 
     133                 :                 }
     134              45 :                 consumed += bucket->buflen;
     135              45 :                 php_stream_bucket_delref(bucket TSRMLS_CC);
     136                 :         }
     137                 : 
     138             116 :         if (!data->finished && flags & PSFS_FLAG_FLUSH_CLOSE) {
     139                 :                 /* Spit it out! */
     140               2 :                 status = Z_OK;
     141               6 :                 while (status == Z_OK) {
     142               2 :                         status = inflate(&(data->strm), Z_FINISH);
     143               2 :                         if (data->strm.avail_out < data->outbuf_len) {
     144               0 :                                 size_t bucketlen = data->outbuf_len - data->strm.avail_out;
     145                 : 
     146               0 :                                 bucket = php_stream_bucket_new(stream, estrndup(data->outbuf, bucketlen), bucketlen, 1, 0 TSRMLS_CC);
     147               0 :                                 php_stream_bucket_append(buckets_out, bucket TSRMLS_CC);
     148               0 :                                 data->strm.avail_out = data->outbuf_len;
     149               0 :                                 data->strm.next_out = data->outbuf;
     150               0 :                                 exit_status = PSFS_PASS_ON;
     151                 :                         }
     152                 :                 }
     153                 :         }
     154                 : 
     155             116 :         if (bytes_consumed) {
     156              64 :                 *bytes_consumed = consumed;
     157                 :         }
     158                 : 
     159             116 :         return exit_status;
     160                 : }
     161                 : 
     162                 : static void php_zlib_inflate_dtor(php_stream_filter *thisfilter TSRMLS_DC)
     163              52 : {
     164              52 :         if (thisfilter && thisfilter->abstract) {
     165              52 :                 php_zlib_filter_data *data = thisfilter->abstract;
     166              52 :                 if (!data->finished) {
     167               7 :                         inflateEnd(&(data->strm));
     168                 :                 }
     169              52 :                 pefree(data->inbuf, data->persistent);
     170              52 :                 pefree(data->outbuf, data->persistent);
     171              52 :                 pefree(data, data->persistent);
     172                 :         }
     173              52 : }
     174                 : 
     175                 : static php_stream_filter_ops php_zlib_inflate_ops = {
     176                 :         php_zlib_inflate_filter,
     177                 :         php_zlib_inflate_dtor,
     178                 :         "zlib.inflate",
     179                 :         PSFO_FLAG_ACCEPTS_STRING | PSFO_FLAG_OUTPUTS_STRING
     180                 : };
     181                 : /* }}} */
     182                 : 
     183                 : /* {{{ zlib.inflate filter implementation */
     184                 : 
     185                 : static php_stream_filter_status_t php_zlib_deflate_filter(
     186                 :         php_stream *stream,
     187                 :         php_stream_filter *thisfilter,
     188                 :         php_stream_bucket_brigade *buckets_in,
     189                 :         php_stream_bucket_brigade *buckets_out,
     190                 :         size_t *bytes_consumed,
     191                 :         int flags
     192                 :         TSRMLS_DC)
     193             115 : {
     194                 :         php_zlib_filter_data *data;
     195                 :         php_stream_bucket *bucket;
     196             115 :         size_t consumed = 0, original_out, original_in;
     197                 :         int status;
     198             115 :         php_stream_filter_status_t exit_status = PSFS_FEED_ME;
     199                 :         z_stream *streamp;
     200                 : 
     201             115 :         if (!thisfilter || !thisfilter->abstract) {
     202                 :                 /* Should never happen */
     203               0 :                 return PSFS_ERR_FATAL;
     204                 :         }
     205                 : 
     206             115 :         data = (php_zlib_filter_data *)(thisfilter->abstract);
     207             115 :         streamp = &(data->strm);
     208             115 :         original_in = data->strm.total_in;
     209             115 :         original_out = data->strm.total_out;
     210                 : 
     211             273 :         while (buckets_in->head) {
     212              43 :                 size_t bin = 0, desired;
     213                 : 
     214              43 :                 bucket = buckets_in->head;
     215                 : 
     216              43 :                 if (bucket->buf_type == IS_UNICODE) {
     217                 :                         /* inflation not allowed for unicode data */
     218               0 :                         return PSFS_ERR_FATAL;
     219                 :                 }
     220                 : 
     221              43 :                 bucket = php_stream_bucket_make_writeable(bucket TSRMLS_CC);
     222                 : 
     223             165 :                 while (bin < (unsigned int) bucket->buflen) {
     224              79 :                         desired = bucket->buflen - bin;
     225              79 :                         if (desired > data->inbuf_len) {
     226              36 :                                 desired = data->inbuf_len;
     227                 :                         }
     228              79 :                         memcpy(data->strm.next_in, bucket->buf.s + bin, desired);
     229              79 :                         data->strm.avail_in = desired;
     230                 : 
     231              79 :                         status = deflate(&(data->strm), flags & PSFS_FLAG_FLUSH_CLOSE ? Z_FULL_FLUSH : (flags & PSFS_FLAG_FLUSH_INC ? Z_SYNC_FLUSH : Z_NO_FLUSH));
     232              79 :                         if (status != Z_OK) {
     233                 :                                 /* Something bad happened */
     234               0 :                                 php_stream_bucket_delref(bucket TSRMLS_CC);
     235               0 :                                 return PSFS_ERR_FATAL;
     236                 :                         }
     237              79 :                         desired -= data->strm.avail_in; /* desired becomes what we consumed this round through */
     238              79 :                         data->strm.next_in = data->inbuf;
     239              79 :                         data->strm.avail_in = 0;
     240              79 :                         bin += desired;
     241                 : 
     242              79 :                         if (data->strm.avail_out < data->outbuf_len) {
     243                 :                                 php_stream_bucket *out_bucket;
     244              13 :                                 size_t bucketlen = data->outbuf_len - data->strm.avail_out;
     245                 : 
     246              13 :                                 out_bucket = php_stream_bucket_new(stream, estrndup(data->outbuf, bucketlen), bucketlen, 1, 0 TSRMLS_CC);
     247              13 :                                 php_stream_bucket_append(buckets_out, out_bucket TSRMLS_CC);
     248              13 :                                 data->strm.avail_out = data->outbuf_len;
     249              13 :                                 data->strm.next_out = data->outbuf;
     250              13 :                                 exit_status = PSFS_PASS_ON;
     251                 :                         }
     252                 :                 }
     253              43 :                 consumed += bucket->buflen;
     254              43 :                 php_stream_bucket_delref(bucket TSRMLS_CC);
     255                 :         }
     256                 : 
     257             115 :         if (flags & PSFS_FLAG_FLUSH_CLOSE) {
     258                 :                 /* Spit it out! */
     259              43 :                 status = Z_OK;
     260             132 :                 while (status == Z_OK) {
     261              46 :                         status = deflate(&(data->strm), Z_FINISH);
     262              46 :                         if (data->strm.avail_out < data->outbuf_len) {
     263              46 :                                 size_t bucketlen = data->outbuf_len - data->strm.avail_out;
     264                 : 
     265              46 :                                 bucket = php_stream_bucket_new(stream, estrndup(data->outbuf, bucketlen), bucketlen, 1, 0 TSRMLS_CC);
     266              46 :                                 php_stream_bucket_append(buckets_out, bucket TSRMLS_CC);
     267              46 :                                 data->strm.avail_out = data->outbuf_len;
     268              46 :                                 data->strm.next_out = data->outbuf;
     269              46 :                                 exit_status = PSFS_PASS_ON;
     270                 :                         }
     271                 :                 }
     272                 :         }
     273                 : 
     274             115 :         if (bytes_consumed) {
     275              73 :                 *bytes_consumed = consumed;
     276                 :         }
     277                 : 
     278             115 :         return exit_status;
     279                 : }
     280                 : 
     281                 : static void php_zlib_deflate_dtor(php_stream_filter *thisfilter TSRMLS_DC)
     282              43 : {
     283              43 :         if (thisfilter && thisfilter->abstract) {
     284              43 :                 php_zlib_filter_data *data = thisfilter->abstract;
     285              43 :                 deflateEnd(&(data->strm));
     286              43 :                 pefree(data->inbuf, data->persistent);
     287              43 :                 pefree(data->outbuf, data->persistent);
     288              43 :                 pefree(data, data->persistent);
     289                 :         }
     290              43 : }
     291                 : 
     292                 : static php_stream_filter_ops php_zlib_deflate_ops = {
     293                 :         php_zlib_deflate_filter,
     294                 :         php_zlib_deflate_dtor,
     295                 :         "zlib.deflate",
     296                 :         PSFO_FLAG_ACCEPTS_STRING | PSFO_FLAG_OUTPUTS_STRING
     297                 : };
     298                 : 
     299                 : /* }}} */
     300                 : 
     301                 : /* {{{ zlib.* common factory */
     302                 : 
     303                 : static php_stream_filter *php_zlib_filter_create(const char *filtername, zval *filterparams, int persistent TSRMLS_DC)
     304              95 : {
     305              95 :         php_stream_filter_ops *fops = NULL;
     306                 :         php_zlib_filter_data *data;
     307                 :         int status;
     308                 : 
     309                 :         /* Create this filter */
     310              95 :         data = pecalloc(1, sizeof(php_zlib_filter_data), persistent);
     311              95 :         if (!data) {
     312               0 :                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Failed allocating %zd bytes", sizeof(php_zlib_filter_data));
     313               0 :                 return NULL;
     314                 :         }
     315                 : 
     316                 :         /* Circular reference */
     317              95 :         data->strm.opaque = (voidpf) data;
     318                 : 
     319              95 :         data->strm.zalloc = (alloc_func) php_zlib_alloc;
     320              95 :         data->strm.zfree = (free_func) php_zlib_free;
     321              95 :         data->strm.avail_out = data->outbuf_len = data->inbuf_len = 2048;
     322              95 :         data->strm.next_in = data->inbuf = (Bytef *) pemalloc(data->inbuf_len, persistent);
     323              95 :         if (!data->inbuf) {
     324               0 :                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Failed allocating %zd bytes", data->inbuf_len);
     325               0 :                 pefree(data, persistent);
     326               0 :                 return NULL;
     327                 :         }
     328              95 :         data->strm.avail_in = 0;
     329              95 :         data->strm.next_out = data->outbuf = (Bytef *) pemalloc(data->outbuf_len, persistent);
     330              95 :         if (!data->outbuf) {
     331               0 :                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Failed allocating %zd bytes", data->outbuf_len);
     332               0 :                 pefree(data->inbuf, persistent);
     333               0 :                 pefree(data, persistent);
     334               0 :                 return NULL;
     335                 :         }
     336                 :                 
     337              95 :         data->strm.data_type = Z_ASCII;
     338                 : 
     339              95 :         if (strcasecmp(filtername, "zlib.inflate") == 0) {
     340              52 :                 int windowBits = -MAX_WBITS;
     341                 : 
     342              52 :                 if (filterparams) {
     343                 :                         zval **tmpzval;
     344                 : 
     345              15 :                         if ((Z_TYPE_P(filterparams) == IS_ARRAY || Z_TYPE_P(filterparams) == IS_OBJECT) &&
     346                 :                                 zend_hash_find(HASH_OF(filterparams), "window", sizeof("window"), (void **) &tmpzval) == SUCCESS) {
     347                 :                                 zval tmp;
     348                 : 
     349                 :                                 /* log-2 base of history window (9 - 15) */
     350              13 :                                 tmp = **tmpzval;
     351              13 :                                 zval_copy_ctor(&tmp);
     352              13 :                                 convert_to_long(&tmp);
     353              13 :                                 if (Z_LVAL(tmp) < -MAX_WBITS || Z_LVAL(tmp) > MAX_WBITS + 32) {
     354               0 :                                         php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid parameter give for window size. (%ld)", Z_LVAL(tmp));
     355                 :                                 } else {
     356              13 :                                         windowBits = Z_LVAL(tmp);
     357                 :                                 }
     358                 :                         }
     359                 :                 }
     360                 : 
     361                 :                 /* RFC 1951 Inflate */
     362              52 :                 data->finished = '\0';
     363              52 :                 status = inflateInit2(&(data->strm), windowBits);
     364              52 :                 fops = &php_zlib_inflate_ops;
     365              43 :         } else if (strcasecmp(filtername, "zlib.deflate") == 0) {
     366                 :                 /* RFC 1951 Deflate */
     367              43 :                 int level = Z_DEFAULT_COMPRESSION;
     368              43 :                 int windowBits = -MAX_WBITS;
     369              43 :                 int memLevel = MAX_MEM_LEVEL;
     370                 : 
     371                 : 
     372              43 :                 if (filterparams) {
     373                 :                         zval **tmpzval, tmp;
     374                 : 
     375                 :                         /* filterparams can either be a scalar value to indicate compression level (shortcut method)
     376                 :                Or can be a hash containing one or more of 'window', 'memory', and/or 'level' members. */
     377                 : 
     378              13 :                         switch (Z_TYPE_P(filterparams)) {
     379                 :                                 case IS_ARRAY:
     380                 :                                 case IS_OBJECT:
     381              13 :                                         if (zend_hash_find(HASH_OF(filterparams), "memory", sizeof("memory"), (void**) &tmpzval) == SUCCESS) {
     382               0 :                                                 tmp = **tmpzval;
     383               0 :                                                 zval_copy_ctor(&tmp);
     384               0 :                                                 convert_to_long(&tmp);
     385                 : 
     386                 :                                                 /* Memory Level (1 - 9) */
     387               0 :                                                 if (Z_LVAL(tmp) < 1 || Z_LVAL(tmp) > MAX_MEM_LEVEL) {
     388               0 :                                                         php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid parameter give for memory level. (%ld)", Z_LVAL(tmp));
     389                 :                                                 } else {
     390               0 :                                                         memLevel = Z_LVAL(tmp);
     391                 :                                                 }
     392                 :                                         }
     393                 : 
     394              13 :                                         if (zend_hash_find(HASH_OF(filterparams), "window", sizeof("window"), (void**) &tmpzval) == SUCCESS) {
     395              13 :                                                 tmp = **tmpzval;
     396              13 :                                                 zval_copy_ctor(&tmp);
     397              13 :                                                 convert_to_long(&tmp);
     398                 : 
     399                 :                                                 /* log-2 base of history window (9 - 15) */
     400              13 :                                                 if (Z_LVAL(tmp) < -MAX_WBITS || Z_LVAL(tmp) > MAX_WBITS + 16) {
     401               0 :                                                         php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid parameter give for window size. (%ld)", Z_LVAL(tmp));
     402                 :                                                 } else {
     403              13 :                                                         windowBits = Z_LVAL(tmp);
     404                 :                                                 }
     405                 :                                         }
     406                 : 
     407              13 :                                         if (zend_hash_find(HASH_OF(filterparams), "level", sizeof("level"), (void**) &tmpzval) == SUCCESS) {
     408               0 :                                                 tmp = **tmpzval;
     409                 : 
     410                 :                                                 /* Psuedo pass through to catch level validating code */
     411               0 :                                                 goto factory_setlevel;
     412                 :                                         }
     413              13 :                                         break;
     414                 :                                 case IS_STRING:
     415                 :                                 case IS_DOUBLE:
     416                 :                                 case IS_LONG:
     417               0 :                                         tmp = *filterparams;
     418               0 : factory_setlevel:
     419               0 :                                         zval_copy_ctor(&tmp);
     420               0 :                                         convert_to_long(&tmp);
     421                 : 
     422                 :                                         /* Set compression level within reason (-1 == default, 0 == none, 1-9 == least to most compression */
     423               0 :                                         if (Z_LVAL(tmp) < -1 || Z_LVAL(tmp) > 9) {
     424               0 :                                                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid compression level specified. (%ld)", Z_LVAL(tmp));
     425                 :                                         } else {
     426               0 :                                                 level = Z_LVAL(tmp);
     427                 :                                         }
     428               0 :                                         break;
     429                 :                                 default:
     430               0 :                                         php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid filter parameter, ignored");
     431                 :                         }
     432                 :                 }
     433              43 :                 status = deflateInit2(&(data->strm), level, Z_DEFLATED, windowBits, memLevel, 0);
     434              43 :                 fops = &php_zlib_deflate_ops;
     435                 :         } else {
     436               0 :                 status = Z_DATA_ERROR;
     437                 :         }
     438                 : 
     439              95 :         if (status != Z_OK) {
     440                 :                 /* Unspecified (probably strm) error, let stream-filter error do its own whining */
     441               0 :                 pefree(data->strm.next_in, persistent);
     442               0 :                 pefree(data->strm.next_out, persistent);
     443               0 :                 pefree(data, persistent);
     444               0 :                 return NULL;
     445                 :         }
     446                 : 
     447              95 :         return php_stream_filter_alloc(fops, data, persistent);
     448                 : }
     449                 : 
     450                 : php_stream_filter_factory php_zlib_filter_factory = {
     451                 :         php_zlib_filter_create
     452                 : };
     453                 : /* }}} */
     454                 : 
     455                 : /*
     456                 :  * Local variables:
     457                 :  * tab-width: 4
     458                 :  * c-basic-offset: 4
     459                 :  * End:
     460                 :  * vim600: sw=4 ts=4 fdm=marker
     461                 :  * vim<600: sw=4 ts=4
     462                 :  */

Generated by: LTP GCOV extension version 1.5

Generated at Mon, 23 Nov 2009 17:39:44 +0000 (36 hours ago)

Copyright © 2005-2009 The PHP Group
All rights reserved.