Back to index

php5  5.3.10
streams.c
Go to the documentation of this file.
00001 /*
00002    +----------------------------------------------------------------------+
00003    | PHP Version 5                                                        |
00004    +----------------------------------------------------------------------+
00005    | Copyright (c) 1997-2012 The PHP Group                                |
00006    +----------------------------------------------------------------------+
00007    | This source file is subject to version 3.01 of the PHP license,      |
00008    | that is bundled with this package in the file LICENSE, and is        |
00009    | available through the world-wide-web at the following url:           |
00010    | http://www.php.net/license/3_01.txt                                  |
00011    | If you did not receive a copy of the PHP license and are unable to   |
00012    | obtain it through the world-wide-web, please send a note to          |
00013    | license@php.net so we can mail you a copy immediately.               |
00014    +----------------------------------------------------------------------+
00015    | Author: Wez Furlong <wez@thebrainroom.com>                           |
00016    +----------------------------------------------------------------------+
00017 */
00018 
00019 /* $Id: streams.c 321634 2012-01-01 13:15:04Z felipe $ */
00020 
00021 /* This file implements cURL based wrappers.
00022  * NOTE: If you are implementing your own streams that are intended to
00023  * work independently of wrappers, this is not a good example to follow!
00024  **/
00025 
00026 #ifdef HAVE_CONFIG_H
00027 #include "config.h"
00028 #endif
00029 
00030 #include "php.h"
00031 #include "php_memory_streams.h"
00032 
00033 #if HAVE_CURL
00034 
00035 #include <stdio.h>
00036 #include <string.h>
00037 
00038 #ifdef PHP_WIN32
00039 #include <winsock2.h>
00040 #include <sys/types.h>
00041 #endif
00042 
00043 #include <curl/curl.h>
00044 #include <curl/easy.h>
00045 
00046 #define SMART_STR_PREALLOC 4096
00047 
00048 #include "ext/standard/php_smart_str.h"
00049 #include "ext/standard/info.h"
00050 #include "ext/standard/file.h"
00051 #include "ext/standard/php_string.h"
00052 #include "php_curl.h"
00053 
00054 static size_t on_data_available(char *data, size_t size, size_t nmemb, void *ctx)
00055 {
00056        php_stream *stream = (php_stream *) ctx;
00057        php_curl_stream *curlstream = (php_curl_stream *) stream->abstract;
00058        size_t wrote;
00059        TSRMLS_FETCH();
00060 
00061        /* TODO: I'd like to deprecate this.
00062         * This code is here because until we start getting real data, we don't know
00063         * if we have had all of the headers 
00064         * */
00065        if (curlstream->readbuffer.writepos == 0) {
00066               zval *sym;
00067 
00068               if (!EG(active_symbol_table)) {
00069                      zend_rebuild_symbol_table(TSRMLS_C);
00070               }
00071               MAKE_STD_ZVAL(sym);
00072               *sym = *curlstream->headers;
00073               zval_copy_ctor(sym);
00074               ZEND_SET_SYMBOL(EG(active_symbol_table), "http_response_header", sym);
00075        }
00076        
00077        php_stream_seek(curlstream->readbuffer.buf, curlstream->readbuffer.writepos, SEEK_SET);
00078        wrote = php_stream_write(curlstream->readbuffer.buf, data, size * nmemb);
00079        curlstream->readbuffer.writepos = php_stream_tell(curlstream->readbuffer.buf);
00080 
00081        return wrote;
00082 }
00083 
00084 /* cURL guarantees that headers are written as complete lines, with this function
00085  * called once for each header */
00086 static size_t on_header_available(char *data, size_t size, size_t nmemb, void *ctx)
00087 {
00088        size_t length = size * nmemb;
00089        zval *header;
00090        php_stream *stream = (php_stream *) ctx;
00091        php_curl_stream *curlstream = (php_curl_stream *) stream->abstract;
00092        TSRMLS_FETCH();
00093 
00094        if (length < 2) {
00095               /* invalid header ? */
00096               return length;
00097        }
00098 
00099        if (!(length == 2 && data[0] == '\r' && data[1] == '\n')) {
00100               MAKE_STD_ZVAL(header);
00101               Z_STRLEN_P(header) = length;
00102               Z_STRVAL_P(header) = estrndup(data, length);
00103               if (Z_STRVAL_P(header)[length-1] == '\n') {
00104                      Z_STRVAL_P(header)[length-1] = '\0';
00105                      Z_STRLEN_P(header)--;
00106                      
00107                      if (Z_STRVAL_P(header)[length-2] == '\r') {
00108                             Z_STRVAL_P(header)[length-2] = '\0';
00109                             Z_STRLEN_P(header)--;
00110                      }
00111               }
00112               Z_TYPE_P(header) = IS_STRING;
00113               zend_hash_next_index_insert(Z_ARRVAL_P(curlstream->headers), &header, sizeof(zval *), NULL);
00114               
00115               /* based on the header, we might need to trigger a notification */
00116               if (!strncasecmp(data, "Location: ", 10)) {
00117                      php_stream_notify_info(stream->context, PHP_STREAM_NOTIFY_REDIRECTED, data + 10, 0);
00118               } else if (!strncasecmp(data, "Content-Type: ", 14)) {
00119                      php_stream_notify_info(stream->context, PHP_STREAM_NOTIFY_MIME_TYPE_IS, data + 14, 0);
00120               } else if (!strncasecmp(data, "Context-Length: ", 16)) {
00121                      php_stream_notify_file_size(stream->context, atoi(data + 16), data, 0);
00122                      php_stream_notify_progress_init(stream->context, 0, 0);
00123               }
00124        }
00125        return length;
00126        
00127 }
00128 
00129 static int on_progress_avail(php_stream *stream, double dltotal, double dlnow, double ultotal, double ulnow)
00130 {
00131        TSRMLS_FETCH();
00132 
00133        /* our notification system only works in a single direction; we should detect which
00134         * direction is important and use the correct values in this call */
00135        php_stream_notify_progress(stream->context, (size_t) dlnow, (size_t) dltotal);
00136        return 0;
00137 }
00138 
00139 static size_t php_curl_stream_write(php_stream *stream, const char *buf, size_t count TSRMLS_DC)
00140 {
00141        php_curl_stream *curlstream = (php_curl_stream *) stream->abstract;
00142 
00143        if (curlstream->writebuffer.buf) {
00144               return php_stream_write(curlstream->writebuffer.buf, buf, count);
00145        }
00146        
00147        return 0;
00148 }
00149 
00150 static size_t php_curl_stream_read(php_stream *stream, char *buf, size_t count TSRMLS_DC)
00151 {
00152        php_curl_stream *curlstream = (php_curl_stream *) stream->abstract;
00153        size_t didread = 0;
00154        
00155        if (curlstream->readbuffer.readpos >= curlstream->readbuffer.writepos && curlstream->pending) {
00156               /* we need to read some more data */
00157               struct timeval tv;
00158 
00159               /* fire up the connection */
00160               if (curlstream->readbuffer.writepos == 0) {
00161                      while (CURLM_CALL_MULTI_PERFORM == curl_multi_perform(curlstream->multi, &curlstream->pending));
00162               }
00163               
00164               do {
00165                      /* get the descriptors from curl */
00166                      curl_multi_fdset(curlstream->multi, &curlstream->readfds, &curlstream->writefds, &curlstream->excfds, &curlstream->maxfd);
00167 
00168                      /* if we are in blocking mode, set a timeout */
00169                      tv.tv_usec = 0;
00170                      tv.tv_sec = 15; /* TODO: allow this to be configured from the script */
00171 
00172                      /* wait for data */
00173                      switch ((curlstream->maxfd < 0) ? 1 : 
00174                                    select(curlstream->maxfd + 1, &curlstream->readfds, &curlstream->writefds, &curlstream->excfds, &tv)) {
00175                             case -1:
00176                                    /* error */
00177                                    return 0;
00178                             case 0:
00179                                    /* no data yet: timed-out */
00180                                    return 0;
00181                             default:
00182                                    /* fetch the data */
00183                                    do {
00184                                           curlstream->mcode = curl_multi_perform(curlstream->multi, &curlstream->pending);
00185                                    } while (curlstream->mcode == CURLM_CALL_MULTI_PERFORM);
00186                      }
00187               } while (curlstream->maxfd >= 0 &&
00188                             curlstream->readbuffer.readpos >= curlstream->readbuffer.writepos && curlstream->pending > 0);
00189 
00190        }
00191 
00192        /* if there is data in the buffer, try and read it */
00193        if (curlstream->readbuffer.writepos > 0 && curlstream->readbuffer.readpos < curlstream->readbuffer.writepos) {
00194               php_stream_seek(curlstream->readbuffer.buf, curlstream->readbuffer.readpos, SEEK_SET);
00195               didread = php_stream_read(curlstream->readbuffer.buf, buf, count);
00196               curlstream->readbuffer.readpos = php_stream_tell(curlstream->readbuffer.buf);
00197        }
00198 
00199        if (didread == 0) {
00200               stream->eof = 1;
00201        }
00202        
00203        return didread;
00204 }
00205 
00206 static int php_curl_stream_close(php_stream *stream, int close_handle TSRMLS_DC)
00207 {
00208        php_curl_stream *curlstream = (php_curl_stream *) stream->abstract;
00209 
00210        /* TODO: respect the close_handle flag here, so that casting to a FILE* on
00211         * systems without fopencookie will work properly */
00212        
00213        curl_multi_remove_handle(curlstream->multi, curlstream->curl);
00214        curl_easy_cleanup(curlstream->curl);      
00215        curl_multi_cleanup(curlstream->multi);    
00216 
00217        /* we are not closing curlstream->readbuf here, because we export
00218         * it as a zval with the wrapperdata - the engine will garbage collect it */
00219 
00220        efree(curlstream->url);
00221        efree(curlstream);
00222        
00223        return 0;
00224 }
00225 
00226 static int php_curl_stream_flush(php_stream *stream TSRMLS_DC)
00227 {
00228 #ifdef ilia_0
00229        php_curl_stream *curlstream = (php_curl_stream *) stream->abstract;
00230 #endif
00231        return 0;
00232 }
00233 
00234 static int php_curl_stream_stat(php_stream *stream, php_stream_statbuf *ssb TSRMLS_DC)
00235 {
00236        /* TODO: fill in details based on Data: and Content-Length: headers, and/or data
00237         * from curl_easy_getinfo().
00238         * For now, return -1 to indicate that it doesn't make sense to stat this stream */
00239        return -1;
00240 }
00241 
00242 static int php_curl_stream_cast(php_stream *stream, int castas, void **ret TSRMLS_DC)
00243 {
00244        php_curl_stream *curlstream = (php_curl_stream *) stream->abstract;
00245        /* delegate to the readbuffer stream */
00246        return php_stream_cast(curlstream->readbuffer.buf, castas, ret, 0);
00247 }
00248 
00249 php_stream_ops php_curl_stream_ops = {
00250        php_curl_stream_write,
00251        php_curl_stream_read,
00252        php_curl_stream_close,
00253        php_curl_stream_flush,
00254        "cURL",
00255        NULL, /* seek */
00256        php_curl_stream_cast, /* cast */
00257        php_curl_stream_stat  /* stat */
00258 };
00259 
00260 
00261 php_stream *php_curl_stream_opener(php_stream_wrapper *wrapper, char *filename, char *mode,
00262               int options, char **opened_path, php_stream_context *context STREAMS_DC TSRMLS_DC)
00263 {
00264        php_stream *stream;
00265        php_curl_stream *curlstream;
00266        zval *tmp, **ctx_opt = NULL;
00267        struct curl_slist *slist = NULL;
00268 
00269        curlstream = emalloc(sizeof(php_curl_stream));
00270        memset(curlstream, 0, sizeof(php_curl_stream));
00271 
00272        stream = php_stream_alloc(&php_curl_stream_ops, curlstream, 0, mode);
00273        php_stream_context_set(stream, context);
00274 
00275        curlstream->curl = curl_easy_init();
00276        curlstream->multi = curl_multi_init();
00277        curlstream->pending = 1;
00278 
00279        /* if opening for an include statement, ensure that the local storage will
00280         * have a FILE* associated with it.
00281         * Otherwise, use the "smart" memory stream that will turn itself into a file
00282         * when it gets large */
00283 #ifndef HAVE_FOPENCOOKIE
00284        if (options & STREAM_WILL_CAST) {
00285               curlstream->readbuffer.buf = php_stream_fopen_tmpfile();
00286        } else
00287 #endif
00288        {
00289               curlstream->readbuffer.buf = php_stream_temp_new();
00290        }
00291        
00292        /* curl requires the URL to be valid throughout it's operation, so dup it */
00293        curlstream->url = estrdup(filename);
00294        curl_easy_setopt(curlstream->curl, CURLOPT_URL, curlstream->url);
00295 
00296        /* feed curl data into our read buffer */ 
00297        curl_easy_setopt(curlstream->curl, CURLOPT_WRITEFUNCTION, on_data_available);
00298        curl_easy_setopt(curlstream->curl, CURLOPT_FILE, stream);
00299        
00300        /* feed headers */
00301        curl_easy_setopt(curlstream->curl, CURLOPT_HEADERFUNCTION, on_header_available);
00302        curl_easy_setopt(curlstream->curl, CURLOPT_WRITEHEADER, stream);
00303 
00304        curl_easy_setopt(curlstream->curl, CURLOPT_ERRORBUFFER, curlstream->errstr);
00305        curl_easy_setopt(curlstream->curl, CURLOPT_VERBOSE, 0);
00306 
00307        /* enable progress notification */
00308        curl_easy_setopt(curlstream->curl, CURLOPT_PROGRESSFUNCTION, on_progress_avail);
00309        curl_easy_setopt(curlstream->curl, CURLOPT_PROGRESSDATA, stream);
00310        curl_easy_setopt(curlstream->curl, CURLOPT_NOPROGRESS, 0);
00311 
00312        curl_easy_setopt(curlstream->curl, CURLOPT_USERAGENT, FG(user_agent) ? FG(user_agent) : "PHP/" PHP_VERSION);
00313        
00314        /* TODO: read cookies and options from context */
00315        if (context && !strncasecmp(filename, "http", sizeof("http")-1)) {
00316               /* Protocol version */
00317               if (SUCCESS == php_stream_context_get_option(context, "http", "protocol_version", &ctx_opt) && Z_TYPE_PP(ctx_opt) == IS_DOUBLE) {
00318                      if (Z_DVAL_PP(ctx_opt) == 1.1) {
00319                             curl_easy_setopt(curlstream->curl, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1);
00320                      } else {
00321                             curl_easy_setopt(curlstream->curl, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0);
00322                      }
00323               }
00324 
00325               if (SUCCESS == php_stream_context_get_option(context, "http", "curl_verify_ssl_host", &ctx_opt) && Z_TYPE_PP(ctx_opt) == IS_BOOL && Z_LVAL_PP(ctx_opt) == 1) {
00326                      curl_easy_setopt(curlstream->curl, CURLOPT_SSL_VERIFYHOST, 1);
00327               } else {
00328                      curl_easy_setopt(curlstream->curl, CURLOPT_SSL_VERIFYHOST, 0);
00329               }
00330               if (SUCCESS == php_stream_context_get_option(context, "http", "curl_verify_ssl_peer", &ctx_opt) && Z_TYPE_PP(ctx_opt) == IS_BOOL && Z_LVAL_PP(ctx_opt) == 1) {
00331                      curl_easy_setopt(curlstream->curl, CURLOPT_SSL_VERIFYPEER, 1);
00332               } else {
00333                      curl_easy_setopt(curlstream->curl, CURLOPT_SSL_VERIFYPEER, 0);
00334               }
00335 
00336               /* HTTP(S) */
00337               if (SUCCESS == php_stream_context_get_option(context, "http", "user_agent", &ctx_opt) && Z_TYPE_PP(ctx_opt) == IS_STRING) {
00338                      curl_easy_setopt(curlstream->curl, CURLOPT_USERAGENT, Z_STRVAL_PP(ctx_opt));
00339               }
00340               if (SUCCESS == php_stream_context_get_option(context, "http", "header", &ctx_opt)) {
00341                      if (Z_TYPE_PP(ctx_opt) == IS_ARRAY) {
00342                             HashPosition pos;
00343                             zval **header = NULL;
00344                      
00345                             for (zend_hash_internal_pointer_reset_ex(Z_ARRVAL_PP(ctx_opt), &pos);
00346                                    SUCCESS == zend_hash_get_current_data_ex(Z_ARRVAL_PP(ctx_opt), (void *)&header, &pos);
00347                                    zend_hash_move_forward_ex(Z_ARRVAL_PP(ctx_opt), &pos)
00348                             ) {
00349                                    if (Z_TYPE_PP(header) == IS_STRING) {
00350                                           slist = curl_slist_append(slist, Z_STRVAL_PP(header));
00351                                    }
00352                             }
00353                      } else if (Z_TYPE_PP(ctx_opt) == IS_STRING && Z_STRLEN_PP(ctx_opt)) {
00354                             char *p, *token, *trimmed, *copy_ctx_opt;
00355 
00356                             copy_ctx_opt = php_trim(Z_STRVAL_PP(ctx_opt), Z_STRLEN_PP(ctx_opt), NULL, 0, NULL, 3 TSRMLS_CC);
00357                             p = php_strtok_r(copy_ctx_opt, "\r\n", &token);
00358                             while (p) {
00359                                    trimmed = php_trim(p, strlen(p), NULL, 0, NULL, 3 TSRMLS_CC);
00360                                    slist = curl_slist_append(slist, trimmed);
00361                                    efree(trimmed);
00362                                    p = php_strtok_r(NULL, "\r\n", &token);
00363                             }
00364                             efree(copy_ctx_opt);
00365                      }
00366                      if (slist) {
00367                             curl_easy_setopt(curlstream->curl, CURLOPT_HTTPHEADER, slist);
00368                      }
00369               }
00370               if (SUCCESS == php_stream_context_get_option(context, "http", "method", &ctx_opt) && Z_TYPE_PP(ctx_opt) == IS_STRING) {
00371                      if (strcasecmp(Z_STRVAL_PP(ctx_opt), "get")) {
00372                             if (!strcasecmp(Z_STRVAL_PP(ctx_opt), "head")) {
00373                                    curl_easy_setopt(curlstream->curl, CURLOPT_NOBODY, 1);
00374                             } else {
00375                                    if (!strcasecmp(Z_STRVAL_PP(ctx_opt), "post")) {
00376                                           curl_easy_setopt(curlstream->curl, CURLOPT_POST, 1);
00377                                    } else {
00378                                           curl_easy_setopt(curlstream->curl, CURLOPT_CUSTOMREQUEST, Z_STRVAL_PP(ctx_opt));
00379                                    }
00380                                    if (SUCCESS == php_stream_context_get_option(context, "http", "content", &ctx_opt) && Z_TYPE_PP(ctx_opt) == IS_STRING) {
00381                                           curl_easy_setopt(curlstream->curl, CURLOPT_POSTFIELDS, Z_STRVAL_PP(ctx_opt));
00382                                           curl_easy_setopt(curlstream->curl, CURLOPT_POSTFIELDSIZE, (long)Z_STRLEN_PP(ctx_opt));
00383                                    }
00384                             }
00385                      }
00386               }
00387               if (SUCCESS == php_stream_context_get_option(context, "http", "proxy", &ctx_opt) && Z_TYPE_PP(ctx_opt) == IS_STRING) {
00388                      curl_easy_setopt(curlstream->curl, CURLOPT_PROXY, Z_STRVAL_PP(ctx_opt));
00389               }
00390               if (SUCCESS == php_stream_context_get_option(context, "http", "max_redirects", &ctx_opt)) {
00391                      long mr = 20;
00392                      if (Z_TYPE_PP(ctx_opt) != IS_STRING || !is_numeric_string(Z_STRVAL_PP(ctx_opt), Z_STRLEN_PP(ctx_opt), &mr, NULL, 1)) {
00393                             if (Z_TYPE_PP(ctx_opt) == IS_LONG) {
00394                                    mr = Z_LVAL_PP(ctx_opt);
00395                             }
00396                      }
00397                      if (mr > 1) {
00398                             if ((PG(open_basedir) && *PG(open_basedir)) || PG(safe_mode)) {
00399                                    curl_easy_setopt(curlstream->curl, CURLOPT_FOLLOWLOCATION, 0);
00400                             } else {
00401                                    curl_easy_setopt(curlstream->curl, CURLOPT_FOLLOWLOCATION, 1);
00402                             }
00403                             curl_easy_setopt(curlstream->curl, CURLOPT_MAXREDIRS, mr);
00404                      }
00405               } else {
00406                      if ((PG(open_basedir) && *PG(open_basedir)) || PG(safe_mode)) {
00407                             curl_easy_setopt(curlstream->curl, CURLOPT_FOLLOWLOCATION, 0);
00408                      } else {
00409                             curl_easy_setopt(curlstream->curl, CURLOPT_FOLLOWLOCATION, 1);
00410                      }
00411                      curl_easy_setopt(curlstream->curl, CURLOPT_MAXREDIRS, 20L);
00412               }
00413        } else if (context && !strncasecmp(filename, "ftps", sizeof("ftps")-1)) {
00414               if (SUCCESS == php_stream_context_get_option(context, "ftp", "curl_verify_ssl_host", &ctx_opt) && Z_TYPE_PP(ctx_opt) == IS_BOOL && Z_LVAL_PP(ctx_opt) == 1) {
00415                      curl_easy_setopt(curlstream->curl, CURLOPT_SSL_VERIFYHOST, 1);
00416               } else {
00417                      curl_easy_setopt(curlstream->curl, CURLOPT_SSL_VERIFYHOST, 0);
00418               }
00419               if (SUCCESS == php_stream_context_get_option(context, "ftp", "curl_verify_ssl_peer", &ctx_opt) && Z_TYPE_PP(ctx_opt) == IS_BOOL && Z_LVAL_PP(ctx_opt) == 1) {
00420                      curl_easy_setopt(curlstream->curl, CURLOPT_SSL_VERIFYPEER, 1);
00421               } else {
00422                      curl_easy_setopt(curlstream->curl, CURLOPT_SSL_VERIFYPEER, 0);
00423               }
00424        }
00425 
00426        /* prepare for "pull" mode */
00427        curl_multi_add_handle(curlstream->multi, curlstream->curl);
00428 
00429        /* Prepare stuff for file_get_wrapper_data: the data is an array:
00430         *
00431         * data = array(
00432         *   "headers" => array("Content-Type: text/html", "Xxx: Yyy"),
00433         *   "readbuf" => resource (equivalent to curlstream->readbuffer)
00434         * );
00435         * */
00436        MAKE_STD_ZVAL(stream->wrapperdata);
00437        array_init(stream->wrapperdata);
00438        
00439        MAKE_STD_ZVAL(curlstream->headers);
00440        array_init(curlstream->headers);
00441        
00442        add_assoc_zval(stream->wrapperdata, "headers", curlstream->headers);
00443        
00444        MAKE_STD_ZVAL(tmp);
00445        php_stream_to_zval(curlstream->readbuffer.buf, tmp);
00446        add_assoc_zval(stream->wrapperdata, "readbuf", tmp);
00447 
00448 #ifndef HAVE_FOPENCOOKIE
00449        if (options & STREAM_WILL_CAST) {
00450               /* we will need to download the whole resource now,
00451                * since we cannot get the actual FD for the download,
00452                * so we won't be able to drive curl via stdio. */
00453 
00454 /* TODO: this needs finishing */
00455               
00456               curl_easy_perform(curlstream->curl);
00457        }
00458        else
00459 #endif
00460        {
00461               /* fire up the connection; we need to detect a connection error here,
00462                * otherwise the curlstream we return ends up doing nothing useful. */
00463               CURLMcode m;
00464               CURLMsg *msg;
00465               int msgs_left, msg_found = 0;
00466 
00467               while (CURLM_CALL_MULTI_PERFORM == (m = curl_multi_perform(curlstream->multi, &curlstream->pending))) {
00468                      ; /* spin */
00469               }
00470 
00471               if (m != CURLM_OK) {
00472 #if HAVE_CURL_MULTI_STRERROR
00473                      php_error_docref(NULL TSRMLS_CC, E_WARNING, "%s", curl_multi_strerror(m));
00474 #else 
00475                      php_error_docref(NULL TSRMLS_CC, E_WARNING, "There was an error mcode=%d", m);
00476 #endif
00477                      goto exit_fail;
00478               }
00479               
00480               /* we have only one curl handle here, even though we use multi syntax, 
00481                * so it's ok to fail on any error */
00482               while ((msg = curl_multi_info_read(curlstream->multi, &msgs_left))) {
00483                      if (msg->data.result == CURLE_OK) {
00484                             continue;
00485                      } else {
00486 #if HAVE_CURL_EASY_STRERROR
00487                             php_error_docref(NULL TSRMLS_CC, E_WARNING, "%s", curl_easy_strerror(msg->data.result));
00488 #else
00489                             php_error_docref(NULL TSRMLS_CC, E_WARNING, "There was an error mcode=%d", msg->data.result);
00490 #endif
00491                             msg_found++;
00492                      }
00493               }
00494               if (msg_found) {
00495                      goto exit_fail;
00496               }
00497        }
00498 
00499        /* context headers are not needed anymore */
00500        if (slist) {
00501               curl_easy_setopt(curlstream->curl, CURLOPT_HTTPHEADER, NULL);
00502               curl_slist_free_all(slist);
00503        }
00504        return stream;
00505 
00506 exit_fail:
00507        php_stream_close(stream);
00508        if (slist) {
00509               curl_slist_free_all(slist);
00510        }
00511        return NULL;
00512 }
00513 
00514 static php_stream_wrapper_ops php_curl_wrapper_ops = {
00515        php_curl_stream_opener,
00516        NULL, /* stream_close: curl streams know how to clean themselves up */
00517        NULL, /* stream_stat: curl streams know how to stat themselves */
00518        NULL, /* stat url */
00519        NULL, /* opendir */
00520        "cURL", /* label */
00521        NULL, /* unlink */
00522        NULL, /* rename */
00523        NULL, /* mkdir */
00524        NULL  /* rmdir */
00525 };
00526 
00527 php_stream_wrapper php_curl_wrapper = {
00528        &php_curl_wrapper_ops,
00529        NULL,
00530        1 /* is_url */
00531 };
00532 
00533 #endif
00534 
00535 /*
00536  * Local variables:
00537  * tab-width: 4
00538  * c-basic-offset: 4
00539  * End:
00540  * vim600: noet sw=4 ts=4 fdm=marker
00541  * vim<600: noet sw=4 ts=4
00542  */