Exemplo n.º 1
0
bool HHVM_FUNCTION(mail,
                   const String& to,
                   const String& subject,
                   const String& message,
                   const String& additional_headers /* = null_string */,
                   const String& additional_parameters /* = null_string */) {

  // replace \0 with spaces
  String to2 = string_replace(to, s_zero, s_space);
  String subject2 = string_replace(subject, s_zero, s_space);
  String message2 = string_replace(message, s_zero, s_space);
  String headers2;
  if (!additional_headers.empty()) {
    headers2 = string_replace(additional_headers, s_zero, s_space);
  }
  String params2;
  if (!additional_parameters.empty()) {
    params2 = string_replace(additional_parameters, s_zero, s_space);
  }

  to2 = php_trim(to2);
  subject2 = php_trim(subject2);

  if (!RuntimeOption::MailForceExtraParameters.empty()) {
    params2 = string_escape_shell_cmd(
      RuntimeOption::MailForceExtraParameters.c_str());
  } else {
    params2 = string_escape_shell_cmd(params2.c_str());
  }

  return php_mail(to2, subject2, message2, headers2, params2);
}
Exemplo n.º 2
0
bool HHVM_FUNCTION(mail,
                   const String& to,
                   const String& subject,
                   const String& message,
                   const String& additional_headers /* = null_string */,
                   const String& additional_parameters /* = null_string */) {

  // replace \0 with spaces
  String to2 = string_replace(to, s_zero, s_space);
  String subject2 = string_replace(subject, s_zero, s_space);
  String message2 = string_replace(message, s_zero, s_space);
  String headers2;
  if (!additional_headers.empty()) {
    headers2 = string_replace(additional_headers, s_zero, s_space);
    headers2 = php_rtrim(headers2);

    if (php_mail_detect_multiple_crlf(headers2)) {
      raise_warning("Multiple or malformed newlines found in additional_headers");
      return false;
    }
  }
  String params2;
  if (!additional_parameters.empty()) {
    params2 = string_replace(additional_parameters, s_zero, s_space);
  }

  to2 = php_trim(to2);
  subject2 = php_trim(subject2);

  if (!RuntimeOption::MailForceExtraParameters.empty()) {
    params2 = string_escape_shell_cmd(
      RuntimeOption::MailForceExtraParameters.c_str());
  } else {
    params2 = string_escape_shell_cmd(params2.c_str());
  }

  return php_mail(to2, subject2, message2, headers2, params2);
}
Exemplo n.º 3
0
static void php_do_trim(lua_State *L, int mode)
{
    char *str, *what;
    size_t  str_len, what_len;   
    
    str  = (char *)lua_tolstring(L, 1, &str_len);
    if (lua_isstring(L, 2))
    {
        what = (char *)lua_tolstring(L, 2, &what_len);
    }
    else
    {
        what     = NULL;
        what_len = 0;
    }
    

    php_trim(L, str, str_len, what, what_len, mode);
}
Exemplo n.º 4
0
php_stream *php_stream_url_wrap_http_ex(php_stream_wrapper *wrapper, char *path, char *mode, int options, char **opened_path, php_stream_context *context, int redirect_max, int header_init STREAMS_DC TSRMLS_DC)
{
    php_stream *stream = NULL;
    php_url *resource = NULL;
    int use_ssl;
    char *scratch = NULL;
    char *tmp = NULL;
    char *ua_str = NULL;
    zval **ua_zval = NULL, **tmpzval = NULL;
    int scratch_len = 0;
    int body = 0;
    char location[HTTP_HEADER_BLOCK_SIZE];
    zval **response_header = NULL;
    int reqok = 0;
    char *http_header_line = NULL;
    char tmp_line[128];
    size_t chunk_size = 0, file_size = 0;
    int eol_detect, have_header = 0;

    if (redirect_max < 1) {
        php_error_docref(NULL TSRMLS_CC, E_WARNING, "Circular redirect, aborting.");
        return NULL;
    }

    if (strpbrk(mode, "aw+")) {
        php_stream_wrapper_log_error(wrapper, options TSRMLS_CC, "HTTP wrapper does not support writeable connections.");
        return NULL;
    }

    resource = php_url_parse(path);
    if (resource == NULL) {
        return NULL;
    }

    if (strncasecmp(resource->scheme, "http", sizeof("http")) && strncasecmp(resource->scheme, "https", sizeof("https"))) {
        php_url_free(resource);
        return php_stream_open_wrapper_ex(path, mode, ENFORCE_SAFE_MODE | REPORT_ERRORS, NULL, context);
    }

    use_ssl = resource->scheme && (strlen(resource->scheme) > 4) && resource->scheme[4] == 's';

    /* choose default ports */
    if (use_ssl && resource->port == 0)
        resource->port = 443;
    else if (resource->port == 0)
        resource->port = 80;

    stream = php_stream_sock_open_host(resource->host, resource->port, SOCK_STREAM, NULL, 0);
    if (stream == NULL) {
        eol_detect = 0;
        goto out;
    }

    /* avoid problems with auto-detecting when reading the headers -> the headers
     * are always in canonical \r\n format */
    eol_detect = stream->flags & (PHP_STREAM_FLAG_DETECT_EOL | PHP_STREAM_FLAG_EOL_MAC);
    stream->flags &= ~(PHP_STREAM_FLAG_DETECT_EOL | PHP_STREAM_FLAG_EOL_MAC);

    php_stream_context_set(stream, context);

    php_stream_notify_info(context, PHP_STREAM_NOTIFY_CONNECT, NULL, 0);

#ifdef HAVE_OPENSSL_EXT
    if (use_ssl)	{

        if (context) {
            /* set the CN we expect to be on the remote cert.
             * You still need to have enabled verification (verify_peer) in the context for
             * this to have an effect */
            zval *cn;

            ALLOC_INIT_ZVAL(cn);
            ZVAL_STRING(cn, resource->host, 1);
            php_stream_context_set_option(context, "ssl", "CN_match", cn);
        }

        if (php_stream_sock_ssl_activate(stream, 1) == FAILURE)	{
            php_stream_wrapper_log_error(wrapper, options TSRMLS_CC, "Unable to activate SSL mode");
            php_stream_close(stream);
            stream = NULL;
            goto out;
        }
    }
#endif

    if (context && php_stream_context_get_option(context, "http", "method", &tmpzval) == SUCCESS) {
        if (Z_TYPE_PP(tmpzval) == IS_STRING && Z_STRLEN_PP(tmpzval) > 0) {
            scratch_len = strlen(path) + 29 + Z_STRLEN_PP(tmpzval);
            scratch = (char *)emalloc(scratch_len);
            strlcpy(scratch, Z_STRVAL_PP(tmpzval), Z_STRLEN_PP(tmpzval) + 1);
            strcat(scratch, " ");
        }
    }

    if (!scratch) {
        scratch_len = strlen(path) + 32;
        scratch = (char *)emalloc(scratch_len);
        strcpy(scratch, "GET ");
    }

    /* file */
    if (resource->path && *resource->path)
        strlcat(scratch, resource->path, scratch_len);
    else
        strlcat(scratch, "/", scratch_len);

    /* query string */
    if (resource->query)	{
        strlcat(scratch, "?", scratch_len);
        strlcat(scratch, resource->query, scratch_len);
    }

    /* protocol version we are speaking */
    strlcat(scratch, " HTTP/1.0\r\n", scratch_len);

    /* send it */
    php_stream_write(stream, scratch, strlen(scratch));

    if (context && php_stream_context_get_option(context, "http", "header", &tmpzval) == SUCCESS && Z_STRLEN_PP(tmpzval)) {
        /* Remove newlines and spaces from start and end, php_trim will estrndup() */
        tmp = php_trim(Z_STRVAL_PP(tmpzval), Z_STRLEN_PP(tmpzval), NULL, 0, NULL, 3 TSRMLS_CC);
        if (strlen(tmp) > 0) {
            /* Output trimmed headers with \r\n at the end */
            php_stream_write(stream, tmp, strlen(tmp));
            php_stream_write(stream, "\r\n", sizeof("\r\n") - 1);

            /* Make lowercase for easy comparison against 'standard' headers */
            php_strtolower(tmp, strlen(tmp));
            if (strstr(tmp, "user-agent:")) {
                have_header |= HTTP_HEADER_USER_AGENT;
            }
            if (strstr(tmp, "host:")) {
                have_header |= HTTP_HEADER_HOST;
            }
            if (strstr(tmp, "from:")) {
                have_header |= HTTP_HEADER_FROM;
            }
            if (strstr(tmp, "authorization:")) {
                have_header |= HTTP_HEADER_AUTH;
            }
        }
        efree(tmp);
    }

    /* auth header if it was specified */
    if (((have_header & HTTP_HEADER_AUTH) == 0) && resource->user && resource->pass) {
        /* decode the strings first */
        php_url_decode(resource->user, strlen(resource->user));
        php_url_decode(resource->pass, strlen(resource->pass));

        /* scratch is large enough, since it was made large enough for the whole URL */
        strcpy(scratch, resource->user);
        strcat(scratch, ":");
        strcat(scratch, resource->pass);

        tmp = (char *)php_base64_encode((unsigned char*)scratch, strlen(scratch), NULL);

        if (snprintf(scratch, scratch_len, "Authorization: Basic %s\r\n", tmp) > 0) {
            php_stream_write(stream, scratch, strlen(scratch));
            php_stream_notify_info(context, PHP_STREAM_NOTIFY_AUTH_REQUIRED, NULL, 0);
        }

        efree(tmp);
        tmp = NULL;
    }

    /* if the user has configured who they are, send a From: line */
    if (((have_header & HTTP_HEADER_FROM) == 0) && cfg_get_string("from", &tmp) == SUCCESS)	{
        if (snprintf(scratch, scratch_len, "From: %s\r\n", tmp) > 0) {
            php_stream_write(stream, scratch, strlen(scratch));
        }
    }

    /* Send Host: header so name-based virtual hosts work */
    if ((have_header & HTTP_HEADER_HOST) == 0) {
        if ((use_ssl && resource->port != 443) || (!use_ssl && resource->port != 80))	{
            if (snprintf(scratch, scratch_len, "Host: %s:%i\r\n", resource->host, resource->port) > 0) {
                php_stream_write(stream, scratch, strlen(scratch));
            }
        } else {
            if (snprintf(scratch, scratch_len, "Host: %s\r\n", resource->host) > 0) {
                php_stream_write(stream, scratch, strlen(scratch));
            }
        }
    }

    if (context &&
            php_stream_context_get_option(context, "http", "user_agent", &ua_zval) == SUCCESS) {
        ua_str = Z_STRVAL_PP(ua_zval);
    } else if (FG(user_agent)) {
        ua_str = FG(user_agent);
    }

    if (ua_str) {
#define _UA_HEADER "User-Agent: %s\r\n"
        char *ua;
        size_t ua_len;

        ua_len = sizeof(_UA_HEADER) + strlen(ua_str);

        /* ensure the header is only sent if user_agent is not blank */
        if (ua_len > sizeof(_UA_HEADER)) {
            ua = (char *)emalloc(ua_len + 1);
            if ((ua_len = snprintf(ua, ua_len, _UA_HEADER, ua_str)) > 0) {
                ua[ua_len] = 0;
                php_stream_write(stream, ua, ua_len);
            } else {
                php_error_docref(NULL TSRMLS_CC, E_WARNING, "Cannot construct User-agent header");
            }

            if (ua) {
                efree(ua);
            }
        }
    }

    php_stream_write(stream, "\r\n", sizeof("\r\n")-1);

    /* Request content, such as for POST requests */
    if (context && php_stream_context_get_option(context, "http", "content", &tmpzval) == SUCCESS && Z_STRLEN_PP(tmpzval) > 0) {
        php_stream_write(stream, Z_STRVAL_PP(tmpzval), Z_STRLEN_PP(tmpzval));
        php_stream_write(stream, "\r\n\r\n", sizeof("\r\n\r\n")-1);
    }

    location[0] = '\0';

    /*
     * We need to read the HTTP response header one-by-one, because
     * the original author did not know about MSG_PEEK.
     * The chunk_size will be reset later, once we have read the
     * header completely.
     */
    if (options & STREAM_WILL_CAST)
        chunk_size = php_stream_set_chunk_size(stream, 1);

    if (!header_init && FAILURE == zend_hash_find(EG(active_symbol_table),
            "http_response_header", sizeof("http_response_header"), (void **) &response_header)) {
        header_init = 1;
    }

    if (header_init) {
        zval *tmp;
        MAKE_STD_ZVAL(tmp);
        array_init(tmp);
        ZEND_SET_SYMBOL(EG(active_symbol_table), "http_response_header", tmp);

        zend_hash_find(EG(active_symbol_table),
                       "http_response_header", sizeof("http_response_header"), (void **) &response_header);
    }


    if (!php_stream_eof(stream)) {
        size_t tmp_line_len;
        /* get response header */

        if (_php_stream_get_line(stream, tmp_line, sizeof(tmp_line) - 1, &tmp_line_len TSRMLS_CC) != NULL) {
            zval *http_response;
            int response_code;

            MAKE_STD_ZVAL(http_response);
            ZVAL_NULL(http_response);

            if (tmp_line_len > 9) {
                response_code = atoi(tmp_line + 9);
            } else {
                response_code = 0;
            }
            switch(response_code) {
            case 200:
            case 302:
            case 301:
                reqok = 1;
                break;
            case 403:
                php_stream_notify_error(context, PHP_STREAM_NOTIFY_AUTH_RESULT,
                                        tmp_line, response_code);
                break;
            default:
                /* safety net in the event tmp_line == NULL */
                if (!tmp_line_len) {
                    tmp_line[0] = '\0';
                }
                php_stream_notify_error(context, PHP_STREAM_NOTIFY_FAILURE,
                                        tmp_line, response_code);
            }

            Z_STRLEN_P(http_response) = tmp_line_len;
            Z_STRVAL_P(http_response) = estrndup(tmp_line, Z_STRLEN_P(http_response));
            if (Z_STRVAL_P(http_response)[Z_STRLEN_P(http_response)-1]=='\n') {
                Z_STRVAL_P(http_response)[Z_STRLEN_P(http_response)-1]=0;
                Z_STRLEN_P(http_response)--;
                if (Z_STRVAL_P(http_response)[Z_STRLEN_P(http_response)-1]=='\r') {
                    Z_STRVAL_P(http_response)[Z_STRLEN_P(http_response)-1]=0;
                    Z_STRLEN_P(http_response)--;
                }
            }
            Z_TYPE_P(http_response) = IS_STRING;
            zend_hash_next_index_insert(Z_ARRVAL_PP(response_header), &http_response, sizeof(zval *), NULL);
        }
    } else {
        php_stream_wrapper_log_error(wrapper, options TSRMLS_CC, "HTTP request failed, unexpected end of socket!");
        goto out;
    }

    /* read past HTTP headers */

    http_header_line = (char *)emalloc(HTTP_HEADER_BLOCK_SIZE);

    while (!body && !php_stream_eof(stream))	{

        if (php_stream_gets(stream, http_header_line, HTTP_HEADER_BLOCK_SIZE-1) != NULL)	{
            char *p;
            int found_eol = 0;
            int http_header_line_length;

            http_header_line[HTTP_HEADER_BLOCK_SIZE-1] = '\0';

            p = http_header_line;
            while(*p) {
                while(*p == '\n' || *p == '\r')	{
                    *p = '\0';
                    p--;
                    found_eol = 1;
                }
                if (found_eol)
                    break;
                p++;
            }
            http_header_line_length = p-http_header_line+1;

            if (!strncasecmp(http_header_line, "Location: ", 10)) {
                strlcpy(location, http_header_line + 10, sizeof(location));
            } else if (!strncasecmp(http_header_line, "Content-Type: ", 14)) {
                php_stream_notify_info(context, PHP_STREAM_NOTIFY_MIME_TYPE_IS, http_header_line + 14, 0);
            } else if (!strncasecmp(http_header_line, "Content-Length: ", 16)) {
                file_size = atoi(http_header_line + 16);
                php_stream_notify_file_size(context, file_size, http_header_line, 0);
            }

            if (http_header_line[0] == '\0') {
                body = 1;
            } else {
                zval *http_header;

                MAKE_STD_ZVAL(http_header);

                ZVAL_STRINGL(http_header, http_header_line, http_header_line_length, 1);

                zend_hash_next_index_insert(Z_ARRVAL_PP(response_header), &http_header, sizeof(zval *), NULL);
            }
        } else {
            break;
        }
    }

    if (!reqok || location[0] != '\0')	{
        if (location[0] != '\0')
            php_stream_notify_info(context, PHP_STREAM_NOTIFY_REDIRECTED, location, 0);

        php_stream_close(stream);
        stream = NULL;

        if (location[0] != '\0')	{

            zval *entry, **entryp;
            char new_path[HTTP_HEADER_BLOCK_SIZE];
            char loc_path[HTTP_HEADER_BLOCK_SIZE];

            *new_path='\0';
            if (strlen(location)<8 || (strncasecmp(location, "http://", sizeof("http://")-1) &&
                                       strncasecmp(location, "https://", sizeof("https://")-1) &&
                                       strncasecmp(location, "ftp://", sizeof("ftp://")-1) &&
                                       strncasecmp(location, "ftps://", sizeof("ftps://")-1)))
            {
                if (*location != '/') {
                    if (*(location+1) != '\0' && resource->path) {
                        char *s = strrchr(resource->path, '/');
                        if (!s) {
                            s = resource->path;
                            if (!s[0]) {
                                efree(s);
                                s = resource->path = estrdup("/");
                            } else {
                                *s = '/';
                            }
                        }
                        s[1] = '\0';
                        if (resource->path && *(resource->path) == '/' && *(resource->path + 1) == '\0') {
                            snprintf(loc_path, sizeof(loc_path) - 1, "%s%s", resource->path, location);
                        } else {
                            snprintf(loc_path, sizeof(loc_path) - 1, "%s/%s", resource->path, location);
                        }
                    } else {
                        snprintf(loc_path, sizeof(loc_path) - 1, "/%s", location);
                    }
                } else {
                    strlcpy(loc_path, location, sizeof(loc_path));
                }
                if ((use_ssl && resource->port != 443) || (!use_ssl && resource->port != 80)) {
                    snprintf(new_path, sizeof(new_path) - 1, "%s://%s:%d%s", resource->scheme, resource->host, resource->port, loc_path);
                } else {
                    snprintf(new_path, sizeof(new_path) - 1, "%s://%s%s", resource->scheme, resource->host, loc_path);
                }
            } else {
                strlcpy(new_path, location, sizeof(new_path));
            }
            stream = php_stream_url_wrap_http_ex(NULL, new_path, mode, options, opened_path, context, --redirect_max, 0 STREAMS_CC TSRMLS_CC);
            if (stream && stream->wrapperdata)	{
                entryp = &entry;
                MAKE_STD_ZVAL(entry);
                ZVAL_EMPTY_STRING(entry);
                zend_hash_next_index_insert(Z_ARRVAL_PP(response_header), entryp, sizeof(zval *), NULL);
                zend_hash_internal_pointer_reset(Z_ARRVAL_P(stream->wrapperdata));
                while (zend_hash_get_current_data(Z_ARRVAL_P(stream->wrapperdata), (void **)&entryp) == SUCCESS) {
                    zval_add_ref(entryp);
                    zend_hash_next_index_insert(Z_ARRVAL_PP(response_header), entryp, sizeof(zval *), NULL);
                    zend_hash_move_forward(Z_ARRVAL_P(stream->wrapperdata));
                }
                zval_dtor(stream->wrapperdata);
                FREE_ZVAL(stream->wrapperdata);
            }
        } else {
            php_stream_wrapper_log_error(wrapper, options TSRMLS_CC, "HTTP request failed! %s", tmp_line);
        }
    }
out:
    if (http_header_line)
        efree(http_header_line);
    if (scratch)
        efree(scratch);
    php_url_free(resource);

    if (stream) {
        if (header_init) {
            stream->wrapperdata = *response_header;
            zval_add_ref(response_header);
        }
        php_stream_notify_progress_init(context, 0, file_size);
        /* Restore original chunk size now that we're done with headers (if applicable) */
        if (options & STREAM_WILL_CAST)
            php_stream_set_chunk_size(stream, chunk_size);

        /* restore the users auto-detect-line-endings setting */
        stream->flags |= eol_detect;

        /* as far as streams are concerned, we are now at the start of
         * the stream */
        stream->position = 0;
    }

    return stream;
}
Exemplo n.º 5
0
bool ChooseAnImageFTP(int sx,int sy, char *ftp_dir, int slot, char **filename, bool *isdir, int *index_file)
{
/*	Parameters:
 sx, sy - window size,
 ftp_dir - what FTP directory to use,
 slot - in what slot should an image go (common: #6 for 5.25' 140Kb floppy disks, and #7 for hard-disks).
 	slot #5 - for 800Kb floppy disks, but we do not use them in Apple][?
	(They are as a rule with .2mg extension)
 index_file	- from which file we should start cursor (should be static and 0 when changing dir)

 Out:	filename	- chosen file name (or dir name)
	isdir		- if chosen name is a directory
*/
		double facx = double(g_ScreenWidth) / double(SCREEN_WIDTH);
		double facy = double(g_ScreenHeight) / double(SCREEN_HEIGHT);

	SDL_Surface *my_screen;	// for background
	struct ftpparse FTP_PARSE; // for parsing ftp directories
	
#ifndef _WIN32
	struct stat info;
#endif

	if(font_sfc == NULL)
		if(!fonts_initialization()) return false;	//if we don't have a fonts, we just can do none
	char tmpstr[512];
	char ftpdirpath [MAX_PATH];
	snprintf(ftpdirpath, MAX_PATH, "%s/%s%s", g_sFTPLocalDir, g_sFTPDirListing, md5str(ftp_dir));	// get path for FTP dir listing
//	printf("Dir: %s, MD5(dir)=%s\n",ftp_dir,ftpdirpath);

	List<char> files;		// our files
	List<char> sizes;		// and their sizes (or 'dir' for directories)

	int act_file;		// current file
	int first_file;		// from which we output files
	char ch = 0;
// prepare screen
	SDL_Surface *tempSurface;

	if(!g_WindowResized) {
		if(g_nAppMode == MODE_LOGO) tempSurface = g_hLogoBitmap;	// use logobitmap
			else tempSurface = g_hDeviceBitmap;
	}
	else tempSurface = g_origscreen;

	my_screen = SDL_CreateRGBSurface(SDL_SWSURFACE, tempSurface->w, tempSurface->h, tempSurface->format->BitsPerPixel, 0, 0, 0, 0);
	if(tempSurface->format->palette && my_screen->format->palette)
		SDL_SetColors(my_screen, tempSurface->format->palette->colors,
			      0, tempSurface->format->palette->ncolors);

	surface_fader(my_screen, 0.2F, 0.2F, 0.2F, -1, 0);	// fade it out to 20% of normal
	SDL_BlitSurface(tempSurface, NULL, my_screen, NULL);
	SDL_BlitSurface(my_screen, NULL, screen, NULL);		// show background
//	ch = 0;
	#define	NORMAL_LENGTH 60
	if(strlen(ftp_dir) > NORMAL_LENGTH) { ch = ftp_dir[NORMAL_LENGTH]; ftp_dir[NORMAL_LENGTH] = 0;} //cut-off too long string
	font_print_centered(sx/2 ,5 * facy , ftp_dir, screen, 1.5 * facx, 1.3 * facy);
	if(ch) ftp_dir[NORMAL_LENGTH] = ch; //restore cut-off char	

	font_print_centered(sx/2,20 * facy,"Connecting to FTP server... Please wait.", screen, 1 * facx, 1 * facy);
	SDL_Flip(screen);	// show the screen

	bool OKI;
#ifndef _WIN32
	if(stat(ftpdirpath,&info) == 0 && info.st_mtime > time(NULL) - RENEW_TIME) {
		OKI = false; // use this file
	}
	else {
		OKI = ftp_get(ftp_dir,ftpdirpath); // get ftp dir listing
	}
#else
// in WIN32 let's use constant caching? -- need to be redone using file.mtime
	if(GetFileAttributes(ftpdirpath) != DWORD(-1)) OKI = false;
		else OKI = ftp_get(ftp_dir,ftpdirpath); // get ftp dir listing
#endif

	if(OKI) {	// error
		printf("Failed getting FTP directory %s to %s\n",ftp_dir,ftpdirpath);	
		font_print_centered(sx/2,30 * facy, "Failure. Press any key!",screen, 1.4 * facx, 1.1 * facy);
		SDL_Flip(screen);	// show the screen
		SDL_Delay(KEY_DELAY);	// wait some time to be not too fast
		//////////////////////////////////
		// Wait for keypress
		//////////////////////////////////
		SDL_Event event;	// event
		Uint8 *keyboard;	// key state

		event.type = SDL_QUIT;
		while(event.type != SDL_KEYDOWN) {	// wait for key pressed
					SDL_Delay(100);
					SDL_PollEvent(&event);
		}
		SDL_FreeSurface(my_screen);		
		return false;	
	 }

		FILE *fdir = fopen(ftpdirpath,"r");
	
		char *tmp;
		int i,j, B, N;	// for cycles, beginning and end of list

// build prev dir
	if(strcmp(ftp_dir, "ftp://")) {
		tmp = new char[3];
		strcpy(tmp, "..");
		files.Add(tmp);
		tmp = new char[5];
		strcpy(tmp, "<UP>");
		sizes.Add(tmp);	// add sign of directory
		B = 1;
	}
	else	B = 0;	// for sorting dirs 

			while (tmp = fgets(tmpstr,512,fdir)) // first looking for directories
			{
				// clear and then try to fill in FTP_PARSE struct
				memset(&FTP_PARSE,0,sizeof(FTP_PARSE));
				ftpparse(&FTP_PARSE, tmp, strlen(tmp));
				
				int what = getstatFTP(&FTP_PARSE, NULL);
				
				if (strlen(FTP_PARSE.name) > 0 &&  what == 1) // is directory!
				{
					tmp = new char[strlen(FTP_PARSE.name)+1];	// add entity to list
					strcpy(tmp, FTP_PARSE.name);
					files.Add(tmp);
					tmp = new char[6];
					strcpy(tmp, "<DIR>");
					sizes.Add(tmp);	// add sign of directory
				} /* if */

			}
// sort directories. Please, don't laugh at my bubble sorting - it the simplest thing I've ever seen --bb
			if(files.Length() > 2)
			{
				N = files.Length() - 1;
//				B = 1; - defined above
				for(i = N; i > B; i--)
					for(j = B; j < i; j++)
						if(strcasecmp(files[j], files[j + 1]) > 0)
						{
							files.Swap(j,j + 1);
							sizes.Swap(j,j + 1);
						}

			}
			B = files.Length();	// start for files

			(void) rewind (fdir);	// to the start
				// now get all regular files
			while (tmp = fgets(tmpstr,512,fdir))
			{
				int fsize;
				// clear and then try to fill in FTP_PARSE struct
				memset(&FTP_PARSE,0,sizeof(FTP_PARSE));
				ftpparse(&FTP_PARSE, tmp, strlen(tmp));
				
				if ((getstatFTP(&FTP_PARSE, &fsize) == 2)) // is normal file!
				{
					tmp = new char[strlen(FTP_PARSE.name)+1];	// add this entity to list
					strcpy(tmp, FTP_PARSE.name);
					files.Add(tmp);
					tmp = new char[10];	// 1400000KB
					snprintf(tmp, 9, "%dKB", fsize);
					sizes.Add(tmp);	// add this size to list
				} /* if */
			}
			(void) fclose (fdir);
// do sorting for files
			if(files.Length() > 2 && B < files.Length())
			{
				N = files.Length() - 1;
//				B = 1;
				for(i = N; i > B; i--)
					for(j = B; j < i; j++)
						if(strcasecmp(files[j], files[j + 1]) > 0)
						{
							files.Swap(j,j + 1);
							sizes.Swap(j,j + 1);
						}
			}
//	Count out cursor position and file number output
	act_file = *index_file;
	if(act_file >= files.Length()) act_file = 0;		// cannot be more than files in list
	first_file = act_file - (FILES_IN_SCREEN / 2);
	if (first_file < 0) first_file = 0;	// cannot be negativ...

// Show all directories (first) and files then
//	char *tmp;
	char *siz;
//	int i;

	while(true)
	{
		SDL_BlitSurface(my_screen, NULL, screen, NULL);		// show background
		font_print_centered(sx/2 ,5 * facy , ftp_dir, screen, 1.5 * facx, 1.3 * facy);
		if (slot == 6) font_print_centered(sx/2,20 * facy,"Choose image for floppy 140KB drive", screen, 1 * facx, 1 * facy);
		else
			if (slot == 7) font_print_centered(sx/2,20 * facy,"Choose image for Hard Disk", screen, 1 * facx, 1 * facy);
		else
			if (slot == 5) font_print_centered(sx/2,20 * facy,"Choose image for floppy 800KB drive", screen, 1 * facx, 1 * facy);
		else
			if (slot == 1) font_print_centered(sx/2,20 * facy,"Select file name for saving snapshot", screen, 1 * facx, 1 * facy);
		else
			if (slot == 0) font_print_centered(sx/2,20 * facy,"Select snapshot file name for loading", screen, 1 * facx, 1 * facy);

		font_print_centered(sx/2,30 * facy, "Press ENTER to choose, or ESC to cancel",screen, 1.4 * facx, 1.1 * facy);

		files.Rewind();	// from start
		sizes.Rewind();
		i = 0;

//		printf("We've printed some messages, go to file list!\n");
// show all fetched dirs and files
// topX of first fiel visible
		int TOPX	= 45 * facy;

		while(files.Iterate(tmp)) {
			sizes.Iterate(siz);	// also fetch size string

			if (i >= first_file && i < first_file + FILES_IN_SCREEN)
			{ // FILES_IN_SCREEN items on screen
//				char tmp2[80],tmp3[256];

				if (i == act_file) { // show item under cursor (in inverse mode)
					SDL_Rect r;
					r.x= 2;
					r.y= TOPX + (i-first_file) * 15 * facy - 1;
					if(strlen(tmp) > 46) r.w = 46 * 6 * 1.7 * facx + 2;
					   else r.w= strlen(tmp) * 6 * 1.7 * facx + 2;	// 6- FONT_SIZE_X
					r.h= 9 * 1.5 * facy;
					SDL_FillRect(screen, &r, SDL_MapRGB(screen->format,255,0,0));// in RED
				} /* if */

				// print file name with enlarged font
				ch = 0;
				if(strlen(tmp) > 46) { ch = tmp[46]; tmp[46] = 0;} //cut-off too long string
				font_print(4, TOPX + (i - first_file) * 15 * facy, tmp, screen, 1.7 * facx, 1.5 * facy); // show name
				font_print(sx - 70*facx, TOPX + (i - first_file) * 15 * facy, siz, screen, 1.7 * facx, 1.5 * facy);// show info (dir or size)
				if(ch) tmp[46] = ch; //restore cut-off char
			} /* if */
			i++;		// next item
		} /* while */

/////////////////////////////////////////////////////////////////////////////////////////////
// draw rectangles
	rectangle(screen, 0, TOPX - 5, g_ScreenWidth, 320 * facy, SDL_MapRGB(screen->format, 255, 255, 255));
	rectangle(screen, 480 * facx, TOPX - 5, 0, 320 * facy, SDL_MapRGB(screen->format, 255, 255, 255));

	SDL_Flip(screen);	// show the screen
	SDL_Delay(KEY_DELAY);	// wait some time to be not too fast

	//////////////////////////////////
	// Wait for keypress
	//////////////////////////////////
	SDL_Event event;	// event
	Uint8 *keyboard;	// key state

	event.type = SDL_QUIT;
	while(event.type != SDL_KEYDOWN) {	// wait for key pressed
				SDL_Delay(10);
				SDL_PollEvent(&event);
	}

// control cursor
		keyboard = SDL_GetKeyState(NULL);	// get current state of pressed (and not pressed) keys
		if (keyboard[SDLK_UP] || keyboard[SDLK_LEFT]) {
			if (act_file>0) act_file--;	// up one position
			if (act_file<first_file) first_file=act_file;
		} /* if */

		if (keyboard[SDLK_DOWN] || keyboard[SDLK_RIGHT]) {
			if (act_file < (files.Length() - 1)) act_file++;
			if (act_file >= (first_file + FILES_IN_SCREEN)) first_file=act_file - FILES_IN_SCREEN + 1;
		} /* if */

		if (keyboard[SDLK_PAGEUP]) {
			act_file-=FILES_IN_SCREEN;
			if (act_file<0) act_file=0;
			if (act_file<first_file) first_file=act_file;
		} /* if */

		if (keyboard[SDLK_PAGEDOWN]) {
			act_file+=FILES_IN_SCREEN;
			if (act_file>=files.Length()) act_file=(files.Length()-1);
			if (act_file>=(first_file+FILES_IN_SCREEN)) first_file=act_file-FILES_IN_SCREEN + 1;
		} /* if */

		// choose an item?
		if (keyboard[SDLK_RETURN]) {
			// dup string from selected file name
			*filename = strdup(php_trim(files[act_file],strlen(files[act_file])));
//			printf("files[act_file]=%s, *filename=%s\n\n", files[act_file], *filename);
			if(!strcmp(sizes[act_file], "<DIR>") || !strcmp(sizes[act_file], "<UP>"))
			   		*isdir = true;
				else *isdir = false;	// this is directory (catalog in Apple][ terminology)
			*index_file = act_file;	// remember current index
			files.Delete();
			sizes.Delete();
			SDL_FreeSurface(my_screen);

			return true;
		} /* if */

		if (keyboard[SDLK_ESCAPE]) {
			files.Delete();
			sizes.Delete();
			SDL_FreeSurface(my_screen);
			return false;		// ESC has been pressed
		} /* if */

		if (keyboard[SDLK_HOME]) {	// HOME?
			act_file=0;
			first_file=0;
		} /* if */
		if (keyboard[SDLK_END]) {	// END?
			act_file=files.Length() - 1;	// go to the last possible file in list
			first_file=act_file - FILES_IN_SCREEN + 1;
			if(first_file < 0) first_file = 0;
		} /* if */

	}
} /* ChooseAnImageFTP */
Exemplo n.º 6
0
php_stream *php_stream_url_wrap_http_ex(php_stream_wrapper *wrapper, 
		const char *path, const char *mode, int options, char **opened_path, 
		php_stream_context *context, int redirect_max, int flags STREAMS_DC TSRMLS_DC) /* {{{ */
{
	php_stream *stream = NULL;
	php_url *resource = NULL;
	int use_ssl;
	int use_proxy = 0;
	char *scratch = NULL;
	char *tmp = NULL;
	char *ua_str = NULL;
	zval **ua_zval = NULL, **tmpzval = NULL, *ssl_proxy_peer_name = NULL;
	int scratch_len = 0;
	int body = 0;
	char location[HTTP_HEADER_BLOCK_SIZE];
	zval *response_header = NULL;
	int reqok = 0;
	char *http_header_line = NULL;
	char tmp_line[128];
	size_t chunk_size = 0, file_size = 0;
	int eol_detect = 0;
	char *transport_string, *errstr = NULL;
	int transport_len, have_header = 0, request_fulluri = 0, ignore_errors = 0;
	char *protocol_version = NULL;
	int protocol_version_len = 3; /* Default: "1.0" */
	struct timeval timeout;
	char *user_headers = NULL;
	int header_init = ((flags & HTTP_WRAPPER_HEADER_INIT) != 0);
	int redirected = ((flags & HTTP_WRAPPER_REDIRECTED) != 0);
	int follow_location = 1;
	php_stream_filter *transfer_encoding = NULL;
	int response_code;

	tmp_line[0] = '\0';

	if (redirect_max < 1) {
		php_stream_wrapper_log_error(wrapper, options TSRMLS_CC, "Redirection limit reached, aborting");
		return NULL;
	}

	resource = php_url_parse(path);
	if (resource == NULL) {
		return NULL;
	}

	if (strncasecmp(resource->scheme, "http", sizeof("http")) && strncasecmp(resource->scheme, "https", sizeof("https"))) {
		if (!context || 
			php_stream_context_get_option(context, wrapper->wops->label, "proxy", &tmpzval) == FAILURE ||
			Z_TYPE_PP(tmpzval) != IS_STRING ||
			Z_STRLEN_PP(tmpzval) <= 0) {
			php_url_free(resource);
			return php_stream_open_wrapper_ex(path, mode, REPORT_ERRORS, NULL, context);
		}
		/* Called from a non-http wrapper with http proxying requested (i.e. ftp) */
		request_fulluri = 1;
		use_ssl = 0;
		use_proxy = 1;

		transport_len = Z_STRLEN_PP(tmpzval);
		transport_string = estrndup(Z_STRVAL_PP(tmpzval), Z_STRLEN_PP(tmpzval));
	} else {
		/* Normal http request (possibly with proxy) */
	
		if (strpbrk(mode, "awx+")) {
			php_stream_wrapper_log_error(wrapper, options TSRMLS_CC, "HTTP wrapper does not support writeable connections");
			php_url_free(resource);
			return NULL;
		}

		use_ssl = resource->scheme && (strlen(resource->scheme) > 4) && resource->scheme[4] == 's';
		/* choose default ports */
		if (use_ssl && resource->port == 0)
			resource->port = 443;
		else if (resource->port == 0)
			resource->port = 80;

		if (context &&
			php_stream_context_get_option(context, wrapper->wops->label, "proxy", &tmpzval) == SUCCESS &&
			Z_TYPE_PP(tmpzval) == IS_STRING &&
			Z_STRLEN_PP(tmpzval) > 0) {
			use_proxy = 1;
			transport_len = Z_STRLEN_PP(tmpzval);
			transport_string = estrndup(Z_STRVAL_PP(tmpzval), Z_STRLEN_PP(tmpzval));
		} else {
			transport_len = spprintf(&transport_string, 0, "%s://%s:%d", use_ssl ? "ssl" : "tcp", resource->host, resource->port);
		}
	}

	if (context && php_stream_context_get_option(context, wrapper->wops->label, "timeout", &tmpzval) == SUCCESS) {
		SEPARATE_ZVAL(tmpzval);
		convert_to_double_ex(tmpzval);
		timeout.tv_sec = (time_t) Z_DVAL_PP(tmpzval);
		timeout.tv_usec = (size_t) ((Z_DVAL_PP(tmpzval) - timeout.tv_sec) * 1000000);
	} else {
		timeout.tv_sec = FG(default_socket_timeout);
		timeout.tv_usec = 0;
	}

	stream = php_stream_xport_create(transport_string, transport_len, options,
			STREAM_XPORT_CLIENT | STREAM_XPORT_CONNECT,
			NULL, &timeout, context, &errstr, NULL);
    
	if (stream) {
		php_stream_set_option(stream, PHP_STREAM_OPTION_READ_TIMEOUT, 0, &timeout);
	}
			
	if (errstr) {
		php_stream_wrapper_log_error(wrapper, options TSRMLS_CC, "%s", errstr);
		efree(errstr);
		errstr = NULL;
	}

	efree(transport_string);

	if (stream && use_proxy && use_ssl) {
		smart_str header = {0};

		/* Set peer_name or name verification will try to use the proxy server name */
		if (!context || php_stream_context_get_option(context, "ssl", "peer_name", &tmpzval) == FAILURE) {
			MAKE_STD_ZVAL(ssl_proxy_peer_name);
			ZVAL_STRING(ssl_proxy_peer_name, resource->host, 1);
			php_stream_context_set_option(stream->context, "ssl", "peer_name", ssl_proxy_peer_name);
		}

		smart_str_appendl(&header, "CONNECT ", sizeof("CONNECT ")-1);
		smart_str_appends(&header, resource->host);
		smart_str_appendc(&header, ':');
		smart_str_append_unsigned(&header, resource->port);
		smart_str_appendl(&header, " HTTP/1.0\r\n", sizeof(" HTTP/1.0\r\n")-1);

	    /* check if we have Proxy-Authorization header */
		if (context && php_stream_context_get_option(context, "http", "header", &tmpzval) == SUCCESS) {
			char *s, *p;

			if (Z_TYPE_PP(tmpzval) == IS_ARRAY) {
				HashPosition pos;
				zval **tmpheader = NULL;

				for (zend_hash_internal_pointer_reset_ex(Z_ARRVAL_PP(tmpzval), &pos);
					SUCCESS == zend_hash_get_current_data_ex(Z_ARRVAL_PP(tmpzval), (void *)&tmpheader, &pos);
					zend_hash_move_forward_ex(Z_ARRVAL_PP(tmpzval), &pos)) {
					if (Z_TYPE_PP(tmpheader) == IS_STRING) {
						s = Z_STRVAL_PP(tmpheader);
						do {
							while (*s == ' ' || *s == '\t') s++;
							p = s;
							while (*p != 0 && *p != ':' && *p != '\r' && *p !='\n') p++;
							if (*p == ':') {
								p++;
								if (p - s == sizeof("Proxy-Authorization:") - 1 &&
								    zend_binary_strcasecmp(s, sizeof("Proxy-Authorization:") - 1,
								        "Proxy-Authorization:", sizeof("Proxy-Authorization:") - 1) == 0) {
									while (*p != 0 && *p != '\r' && *p !='\n') p++;
									smart_str_appendl(&header, s, p - s);
									smart_str_appendl(&header, "\r\n", sizeof("\r\n")-1);
									goto finish;
								} else {
									while (*p != 0 && *p != '\r' && *p !='\n') p++;
								}
							}
							s = p;
							while (*s == '\r' || *s == '\n') s++;
						} while (*s != 0);
					}
				}
			} else if (Z_TYPE_PP(tmpzval) == IS_STRING && Z_STRLEN_PP(tmpzval)) {
				s = Z_STRVAL_PP(tmpzval);
				do {
					while (*s == ' ' || *s == '\t') s++;
					p = s;
					while (*p != 0 && *p != ':' && *p != '\r' && *p !='\n') p++;
					if (*p == ':') {
						p++;
						if (p - s == sizeof("Proxy-Authorization:") - 1 &&
						    zend_binary_strcasecmp(s, sizeof("Proxy-Authorization:") - 1,
						        "Proxy-Authorization:", sizeof("Proxy-Authorization:") - 1) == 0) {
							while (*p != 0 && *p != '\r' && *p !='\n') p++;
							smart_str_appendl(&header, s, p - s);
							smart_str_appendl(&header, "\r\n", sizeof("\r\n")-1);
							goto finish;
						} else {
							while (*p != 0 && *p != '\r' && *p !='\n') p++;
						}
					}
					s = p;
					while (*s == '\r' || *s == '\n') s++;
				} while (*s != 0);
			}
		}
finish:
		smart_str_appendl(&header, "\r\n", sizeof("\r\n")-1);

		if (php_stream_write(stream, header.c, header.len) != header.len) {
			php_stream_wrapper_log_error(wrapper, options TSRMLS_CC, "Cannot connect to HTTPS server through proxy");
			php_stream_close(stream);
			stream = NULL;
		}
 	 	smart_str_free(&header);

 	 	if (stream) {
 	 		char header_line[HTTP_HEADER_BLOCK_SIZE];

			/* get response header */
			while (php_stream_gets(stream, header_line, HTTP_HEADER_BLOCK_SIZE-1) != NULL) {
				if (header_line[0] == '\n' ||
				    header_line[0] == '\r' ||
				    header_line[0] == '\0') {
				  break;
				}
			}
		}

		/* enable SSL transport layer */
		if (stream) {
			if (php_stream_xport_crypto_setup(stream, STREAM_CRYPTO_METHOD_ANY_CLIENT, NULL TSRMLS_CC) < 0 ||
			    php_stream_xport_crypto_enable(stream, 1 TSRMLS_CC) < 0) {
				php_stream_wrapper_log_error(wrapper, options TSRMLS_CC, "Cannot connect to HTTPS server through proxy");
				php_stream_close(stream);
				stream = NULL;
			}
		}
	}

	if (stream == NULL)
		goto out;

	/* avoid buffering issues while reading header */
	if (options & STREAM_WILL_CAST)
		chunk_size = php_stream_set_chunk_size(stream, 1);
	
	/* avoid problems with auto-detecting when reading the headers -> the headers
	 * are always in canonical \r\n format */
	eol_detect = stream->flags & (PHP_STREAM_FLAG_DETECT_EOL | PHP_STREAM_FLAG_EOL_MAC);
	stream->flags &= ~(PHP_STREAM_FLAG_DETECT_EOL | PHP_STREAM_FLAG_EOL_MAC);

	php_stream_context_set(stream, context TSRMLS_CC);

	php_stream_notify_info(context, PHP_STREAM_NOTIFY_CONNECT, NULL, 0);

	if (header_init && context && php_stream_context_get_option(context, "http", "max_redirects", &tmpzval) == SUCCESS) {
		SEPARATE_ZVAL(tmpzval);
		convert_to_long_ex(tmpzval);
		redirect_max = Z_LVAL_PP(tmpzval);
	}

	if (context && php_stream_context_get_option(context, "http", "method", &tmpzval) == SUCCESS) {
		if (Z_TYPE_PP(tmpzval) == IS_STRING && Z_STRLEN_PP(tmpzval) > 0) {
			/* As per the RFC, automatically redirected requests MUST NOT use other methods than
			 * GET and HEAD unless it can be confirmed by the user */
			if (!redirected
				|| (Z_STRLEN_PP(tmpzval) == 3 && memcmp("GET", Z_STRVAL_PP(tmpzval), 3) == 0)
				|| (Z_STRLEN_PP(tmpzval) == 4 && memcmp("HEAD",Z_STRVAL_PP(tmpzval), 4) == 0)
			) {
				scratch_len = strlen(path) + 29 + Z_STRLEN_PP(tmpzval);
				scratch = emalloc(scratch_len);
				strlcpy(scratch, Z_STRVAL_PP(tmpzval), Z_STRLEN_PP(tmpzval) + 1);
				strncat(scratch, " ", 1);
			}
		}
	}
 
	if (context && php_stream_context_get_option(context, "http", "protocol_version", &tmpzval) == SUCCESS) {
		SEPARATE_ZVAL(tmpzval);
		convert_to_double_ex(tmpzval);
		protocol_version_len = spprintf(&protocol_version, 0, "%.1F", Z_DVAL_PP(tmpzval));
	}

	if (!scratch) {
		scratch_len = strlen(path) + 29 + protocol_version_len;
		scratch = emalloc(scratch_len);
		strncpy(scratch, "GET ", scratch_len);
	}

	/* Should we send the entire path in the request line, default to no. */
	if (!request_fulluri &&
		context &&
		php_stream_context_get_option(context, "http", "request_fulluri", &tmpzval) == SUCCESS) {
		zval ztmp = **tmpzval;

		zval_copy_ctor(&ztmp);
		convert_to_boolean(&ztmp);
		request_fulluri = Z_BVAL(ztmp) ? 1 : 0;
		zval_dtor(&ztmp);
	}

	if (request_fulluri) {
		/* Ask for everything */
		strcat(scratch, path);
	} else {
		/* Send the traditional /path/to/file?query_string */

		/* file */
		if (resource->path && *resource->path) {
			strlcat(scratch, resource->path, scratch_len);
		} else {
			strlcat(scratch, "/", scratch_len);
		}

		/* query string */
		if (resource->query) {
			strlcat(scratch, "?", scratch_len);
			strlcat(scratch, resource->query, scratch_len);
		}
	}

	/* protocol version we are speaking */
	if (protocol_version) {
		strlcat(scratch, " HTTP/", scratch_len);
		strlcat(scratch, protocol_version, scratch_len);
		strlcat(scratch, "\r\n", scratch_len);
	} else {
		strlcat(scratch, " HTTP/1.0\r\n", scratch_len);
	}

	/* send it */
	php_stream_write(stream, scratch, strlen(scratch));

	if (context && php_stream_context_get_option(context, "http", "header", &tmpzval) == SUCCESS) {
		tmp = NULL;
		
		if (Z_TYPE_PP(tmpzval) == IS_ARRAY) {
			HashPosition pos;
			zval **tmpheader = NULL;
			smart_str tmpstr = {0};

			for (zend_hash_internal_pointer_reset_ex(Z_ARRVAL_PP(tmpzval), &pos);
				SUCCESS == zend_hash_get_current_data_ex(Z_ARRVAL_PP(tmpzval), (void *)&tmpheader, &pos);
				zend_hash_move_forward_ex(Z_ARRVAL_PP(tmpzval), &pos)
			) {
				if (Z_TYPE_PP(tmpheader) == IS_STRING) {
					smart_str_appendl(&tmpstr, Z_STRVAL_PP(tmpheader), Z_STRLEN_PP(tmpheader));
					smart_str_appendl(&tmpstr, "\r\n", sizeof("\r\n") - 1);
				}
			}
			smart_str_0(&tmpstr);
			/* Remove newlines and spaces from start and end. there's at least one extra \r\n at the end that needs to go. */
			if (tmpstr.c) {
				tmp = php_trim(tmpstr.c, strlen(tmpstr.c), NULL, 0, NULL, 3 TSRMLS_CC);
				smart_str_free(&tmpstr);
			}
		}
		if (Z_TYPE_PP(tmpzval) == IS_STRING && Z_STRLEN_PP(tmpzval)) {
			/* Remove newlines and spaces from start and end php_trim will estrndup() */
			tmp = php_trim(Z_STRVAL_PP(tmpzval), Z_STRLEN_PP(tmpzval), NULL, 0, NULL, 3 TSRMLS_CC);
		}
		if (tmp && strlen(tmp) > 0) {
			char *s;

			user_headers = estrdup(tmp);

			/* Make lowercase for easy comparison against 'standard' headers */
			php_strtolower(tmp, strlen(tmp));

			if (!header_init) {
				/* strip POST headers on redirect */
				strip_header(user_headers, tmp, "content-length:");
				strip_header(user_headers, tmp, "content-type:");
			}

			if ((s = strstr(tmp, "user-agent:")) && 
			    (s == tmp || *(s-1) == '\r' || *(s-1) == '\n' || 
			                 *(s-1) == '\t' || *(s-1) == ' ')) {
				 have_header |= HTTP_HEADER_USER_AGENT;
			}
			if ((s = strstr(tmp, "host:")) &&
			    (s == tmp || *(s-1) == '\r' || *(s-1) == '\n' || 
			                 *(s-1) == '\t' || *(s-1) == ' ')) {
				 have_header |= HTTP_HEADER_HOST;
			}
			if ((s = strstr(tmp, "from:")) &&
			    (s == tmp || *(s-1) == '\r' || *(s-1) == '\n' || 
			                 *(s-1) == '\t' || *(s-1) == ' ')) {
				 have_header |= HTTP_HEADER_FROM;
				}
			if ((s = strstr(tmp, "authorization:")) &&
			    (s == tmp || *(s-1) == '\r' || *(s-1) == '\n' || 
			                 *(s-1) == '\t' || *(s-1) == ' ')) {
				 have_header |= HTTP_HEADER_AUTH;
			}
			if ((s = strstr(tmp, "content-length:")) &&
			    (s == tmp || *(s-1) == '\r' || *(s-1) == '\n' || 
			                 *(s-1) == '\t' || *(s-1) == ' ')) {
				 have_header |= HTTP_HEADER_CONTENT_LENGTH;
			}
			if ((s = strstr(tmp, "content-type:")) &&
			    (s == tmp || *(s-1) == '\r' || *(s-1) == '\n' || 
			                 *(s-1) == '\t' || *(s-1) == ' ')) {
				 have_header |= HTTP_HEADER_TYPE;
			}
			if ((s = strstr(tmp, "connection:")) &&
			    (s == tmp || *(s-1) == '\r' || *(s-1) == '\n' || 
			                 *(s-1) == '\t' || *(s-1) == ' ')) {
				 have_header |= HTTP_HEADER_CONNECTION;
			}
			/* remove Proxy-Authorization header */
			if (use_proxy && use_ssl && (s = strstr(tmp, "proxy-authorization:")) &&
			    (s == tmp || *(s-1) == '\r' || *(s-1) == '\n' || 
			                 *(s-1) == '\t' || *(s-1) == ' ')) {
				char *p = s + sizeof("proxy-authorization:") - 1;
				
				while (s > tmp && (*(s-1) == ' ' || *(s-1) == '\t')) s--;
				while (*p != 0 && *p != '\r' && *p != '\n') p++;
				while (*p == '\r' || *p == '\n') p++;
				if (*p == 0) {
					if (s == tmp) {
						efree(user_headers);
						user_headers = NULL;
					} else {
						while (s > tmp && (*(s-1) == '\r' || *(s-1) == '\n')) s--;
						user_headers[s - tmp] = 0;
					}
				} else {
					memmove(user_headers + (s - tmp), user_headers + (p - tmp), strlen(p) + 1);
				}
			}

		}
		if (tmp) {
			efree(tmp);
		}
	}

	/* auth header if it was specified */
	if (((have_header & HTTP_HEADER_AUTH) == 0) && resource->user) {
		/* decode the strings first */
		php_url_decode(resource->user, strlen(resource->user));

		/* scratch is large enough, since it was made large enough for the whole URL */
		strcpy(scratch, resource->user);
		strcat(scratch, ":");

		/* Note: password is optional! */
		if (resource->pass) {
			php_url_decode(resource->pass, strlen(resource->pass));
			strcat(scratch, resource->pass);
		}

		tmp = (char*)php_base64_encode((unsigned char*)scratch, strlen(scratch), NULL);
		
		if (snprintf(scratch, scratch_len, "Authorization: Basic %s\r\n", tmp) > 0) {
			php_stream_write(stream, scratch, strlen(scratch));
			php_stream_notify_info(context, PHP_STREAM_NOTIFY_AUTH_REQUIRED, NULL, 0);
		}

		efree(tmp);
		tmp = NULL;
	}

	/* if the user has configured who they are, send a From: line */
	if (((have_header & HTTP_HEADER_FROM) == 0) && FG(from_address)) {
		if (snprintf(scratch, scratch_len, "From: %s\r\n", FG(from_address)) > 0)
			php_stream_write(stream, scratch, strlen(scratch));
	}

	/* Send Host: header so name-based virtual hosts work */
	if ((have_header & HTTP_HEADER_HOST) == 0) {
		if ((use_ssl && resource->port != 443 && resource->port != 0) || 
			(!use_ssl && resource->port != 80 && resource->port != 0)) {
			if (snprintf(scratch, scratch_len, "Host: %s:%i\r\n", resource->host, resource->port) > 0)
				php_stream_write(stream, scratch, strlen(scratch));
		} else {
			if (snprintf(scratch, scratch_len, "Host: %s\r\n", resource->host) > 0) {
				php_stream_write(stream, scratch, strlen(scratch));
			}
		}
	}

	/* Send a Connection: close header when using HTTP 1.1 or later to avoid
	 * hanging when the server interprets the RFC literally and establishes a
	 * keep-alive connection, unless the user specifically requests something
	 * else by specifying a Connection header in the context options. */
	if (protocol_version &&
	    ((have_header & HTTP_HEADER_CONNECTION) == 0) &&
	    (strncmp(protocol_version, "1.0", MIN(protocol_version_len, 3)) > 0)) {
		php_stream_write_string(stream, "Connection: close\r\n");
	}

	if (context && 
	    php_stream_context_get_option(context, "http", "user_agent", &ua_zval) == SUCCESS &&
		Z_TYPE_PP(ua_zval) == IS_STRING) {
		ua_str = Z_STRVAL_PP(ua_zval);
	} else if (FG(user_agent)) {
		ua_str = FG(user_agent);
	}

	if (((have_header & HTTP_HEADER_USER_AGENT) == 0) && ua_str) {
#define _UA_HEADER "User-Agent: %s\r\n"
		char *ua;
		size_t ua_len;
		
		ua_len = sizeof(_UA_HEADER) + strlen(ua_str);
		
		/* ensure the header is only sent if user_agent is not blank */
		if (ua_len > sizeof(_UA_HEADER)) {
			ua = emalloc(ua_len + 1);
			if ((ua_len = slprintf(ua, ua_len, _UA_HEADER, ua_str)) > 0) {
				ua[ua_len] = 0;
				php_stream_write(stream, ua, ua_len);
			} else {
				php_error_docref(NULL TSRMLS_CC, E_WARNING, "Cannot construct User-agent header");
			}

			if (ua) {
				efree(ua);
			}
		}	
	}

	if (user_headers) {
		/* A bit weird, but some servers require that Content-Length be sent prior to Content-Type for POST
		 * see bug #44603 for details. Since Content-Type maybe part of user's headers we need to do this check first.
		 */
		if (
				header_init &&
				context &&
				!(have_header & HTTP_HEADER_CONTENT_LENGTH) &&
				php_stream_context_get_option(context, "http", "content", &tmpzval) == SUCCESS &&
				Z_TYPE_PP(tmpzval) == IS_STRING && Z_STRLEN_PP(tmpzval) > 0
		) {
			scratch_len = slprintf(scratch, scratch_len, "Content-Length: %d\r\n", Z_STRLEN_PP(tmpzval));
			php_stream_write(stream, scratch, scratch_len);
			have_header |= HTTP_HEADER_CONTENT_LENGTH;
		}

		php_stream_write(stream, user_headers, strlen(user_headers));
		php_stream_write(stream, "\r\n", sizeof("\r\n")-1);
		efree(user_headers);
	}

	/* Request content, such as for POST requests */
	if (header_init && context &&
		php_stream_context_get_option(context, "http", "content", &tmpzval) == SUCCESS &&
		Z_TYPE_PP(tmpzval) == IS_STRING && Z_STRLEN_PP(tmpzval) > 0) {
		if (!(have_header & HTTP_HEADER_CONTENT_LENGTH)) {
			scratch_len = slprintf(scratch, scratch_len, "Content-Length: %d\r\n", Z_STRLEN_PP(tmpzval));
			php_stream_write(stream, scratch, scratch_len);
		}
		if (!(have_header & HTTP_HEADER_TYPE)) {
			php_stream_write(stream, "Content-Type: application/x-www-form-urlencoded\r\n",
				sizeof("Content-Type: application/x-www-form-urlencoded\r\n") - 1);
			php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Content-type not specified assuming application/x-www-form-urlencoded");
		}
		php_stream_write(stream, "\r\n", sizeof("\r\n")-1);
		php_stream_write(stream, Z_STRVAL_PP(tmpzval), Z_STRLEN_PP(tmpzval));
	} else {
		php_stream_write(stream, "\r\n", sizeof("\r\n")-1);
	}

	location[0] = '\0';

	if (!EG(active_symbol_table)) {
		zend_rebuild_symbol_table(TSRMLS_C);
	}

	if (header_init) {
		zval *ztmp;
		MAKE_STD_ZVAL(ztmp);
		array_init(ztmp);
		ZEND_SET_SYMBOL(EG(active_symbol_table), "http_response_header", ztmp);
	}

	{
		zval **rh;
		zend_hash_find(EG(active_symbol_table), "http_response_header", sizeof("http_response_header"), (void **) &rh);
		response_header = *rh;
	}

	if (!php_stream_eof(stream)) {
		size_t tmp_line_len;
		/* get response header */

		if (php_stream_get_line(stream, tmp_line, sizeof(tmp_line) - 1, &tmp_line_len) != NULL) {
			zval *http_response;

			if (tmp_line_len > 9) {
				response_code = atoi(tmp_line + 9);
			} else {
				response_code = 0;
			}
			if (context && SUCCESS==php_stream_context_get_option(context, "http", "ignore_errors", &tmpzval)) {
				ignore_errors = zend_is_true(*tmpzval TSRMLS_CC);
			}
			/* when we request only the header, don't fail even on error codes */
			if ((options & STREAM_ONLY_GET_HEADERS) || ignore_errors) {
				reqok = 1;
			}
			/* all status codes in the 2xx range are defined by the specification as successful;
			 * all status codes in the 3xx range are for redirection, and so also should never
			 * fail */
			if (response_code >= 200 && response_code < 400) {
				reqok = 1;
			} else {
				switch(response_code) {
					case 403:
						php_stream_notify_error(context, PHP_STREAM_NOTIFY_AUTH_RESULT,
								tmp_line, response_code);
						break;
					default:
						/* safety net in the event tmp_line == NULL */
						if (!tmp_line_len) {
							tmp_line[0] = '\0';
						}
						php_stream_notify_error(context, PHP_STREAM_NOTIFY_FAILURE,
								tmp_line, response_code);
				}
			}
			if (tmp_line[tmp_line_len - 1] == '\n') {
				--tmp_line_len;
				if (tmp_line[tmp_line_len - 1] == '\r') {
					--tmp_line_len;
				}
			}
			MAKE_STD_ZVAL(http_response);
			ZVAL_STRINGL(http_response, tmp_line, tmp_line_len, 1);
			zend_hash_next_index_insert(Z_ARRVAL_P(response_header), &http_response, sizeof(zval *), NULL);
		}
	} else {
		php_stream_wrapper_log_error(wrapper, options TSRMLS_CC, "HTTP request failed, unexpected end of socket!");
		goto out;
	}
	
	/* read past HTTP headers */
	
	http_header_line = emalloc(HTTP_HEADER_BLOCK_SIZE);

	while (!body && !php_stream_eof(stream)) {
		size_t http_header_line_length;
		if (php_stream_get_line(stream, http_header_line, HTTP_HEADER_BLOCK_SIZE, &http_header_line_length) && *http_header_line != '\n' && *http_header_line != '\r') {
			char *e = http_header_line + http_header_line_length - 1;
			if (*e != '\n') {
				do { /* partial header */
					if (php_stream_get_line(stream, http_header_line, HTTP_HEADER_BLOCK_SIZE, &http_header_line_length) == NULL) {
						php_stream_wrapper_log_error(wrapper, options TSRMLS_CC, "Failed to read HTTP headers");
						goto out;
					}
					e = http_header_line + http_header_line_length - 1;
				} while (*e != '\n');
				continue;
			}
			while (*e == '\n' || *e == '\r') {
				e--;
			}
			http_header_line_length = e - http_header_line + 1;
			http_header_line[http_header_line_length] = '\0';

			if (!strncasecmp(http_header_line, "Location: ", 10)) {
				if (context && php_stream_context_get_option(context, "http", "follow_location", &tmpzval) == SUCCESS) {
					SEPARATE_ZVAL(tmpzval);
					convert_to_long_ex(tmpzval);
					follow_location = Z_LVAL_PP(tmpzval);
				} else if (!(response_code >= 300 && response_code < 304 || 307 == response_code || 308 == response_code)) {
					/* we shouldn't redirect automatically
					if follow_location isn't set and response_code not in (300, 301, 302, 303 and 307) 
					see http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.3.1
					RFC 7238 defines 308: http://tools.ietf.org/html/rfc7238 */
					follow_location = 0;
				}
				strlcpy(location, http_header_line + 10, sizeof(location));
			} else if (!strncasecmp(http_header_line, "Content-Type: ", 14)) {
				php_stream_notify_info(context, PHP_STREAM_NOTIFY_MIME_TYPE_IS, http_header_line + 14, 0);
			} else if (!strncasecmp(http_header_line, "Content-Length: ", 16)) {
				file_size = atoi(http_header_line + 16);
				php_stream_notify_file_size(context, file_size, http_header_line, 0);
			} else if (!strncasecmp(http_header_line, "Transfer-Encoding: chunked", sizeof("Transfer-Encoding: chunked"))) {

				/* create filter to decode response body */
				if (!(options & STREAM_ONLY_GET_HEADERS)) {
					long decode = 1;

					if (context && php_stream_context_get_option(context, "http", "auto_decode", &tmpzval) == SUCCESS) {
						SEPARATE_ZVAL(tmpzval);
						convert_to_boolean(*tmpzval);
						decode = Z_LVAL_PP(tmpzval);
					}
					if (decode) {
						transfer_encoding = php_stream_filter_create("dechunk", NULL, php_stream_is_persistent(stream) TSRMLS_CC);
						if (transfer_encoding) {
							/* don't store transfer-encodeing header */
							continue;
						}
					}
				}
			}

			if (http_header_line[0] == '\0') {
				body = 1;
			} else {
				zval *http_header;

				MAKE_STD_ZVAL(http_header);

				ZVAL_STRINGL(http_header, http_header_line, http_header_line_length, 1);
				
				zend_hash_next_index_insert(Z_ARRVAL_P(response_header), &http_header, sizeof(zval *), NULL);
			}
		} else {
			break;
		}
	}

	if (!reqok || (location[0] != '\0' && follow_location)) {
		if (!follow_location || (((options & STREAM_ONLY_GET_HEADERS) || ignore_errors) && redirect_max <= 1)) {
			goto out;
		}

		if (location[0] != '\0')
			php_stream_notify_info(context, PHP_STREAM_NOTIFY_REDIRECTED, location, 0);

		php_stream_close(stream);
		stream = NULL;

		if (location[0] != '\0') {

			char new_path[HTTP_HEADER_BLOCK_SIZE];
			char loc_path[HTTP_HEADER_BLOCK_SIZE];

			*new_path='\0';
			if (strlen(location)<8 || (strncasecmp(location, "http://", sizeof("http://")-1) && 
							strncasecmp(location, "https://", sizeof("https://")-1) && 
							strncasecmp(location, "ftp://", sizeof("ftp://")-1) && 
							strncasecmp(location, "ftps://", sizeof("ftps://")-1))) 
			{
				if (*location != '/') {
					if (*(location+1) != '\0' && resource->path) {
						char *s = strrchr(resource->path, '/');
						if (!s) {
							s = resource->path;
							if (!s[0]) {
								efree(s);
								s = resource->path = estrdup("/");
							} else {
								*s = '/';
							}
						}
						s[1] = '\0'; 
						if (resource->path && *(resource->path) == '/' && *(resource->path + 1) == '\0') {
							snprintf(loc_path, sizeof(loc_path) - 1, "%s%s", resource->path, location);
						} else {
							snprintf(loc_path, sizeof(loc_path) - 1, "%s/%s", resource->path, location);
						}
					} else {
						snprintf(loc_path, sizeof(loc_path) - 1, "/%s", location);
					}
				} else {
					strlcpy(loc_path, location, sizeof(loc_path));
				}
				if ((use_ssl && resource->port != 443) || (!use_ssl && resource->port != 80)) {
					snprintf(new_path, sizeof(new_path) - 1, "%s://%s:%d%s", resource->scheme, resource->host, resource->port, loc_path);
				} else {
					snprintf(new_path, sizeof(new_path) - 1, "%s://%s%s", resource->scheme, resource->host, loc_path);
				}
			} else {
				strlcpy(new_path, location, sizeof(new_path));
			}

			php_url_free(resource);
			/* check for invalid redirection URLs */
			if ((resource = php_url_parse(new_path)) == NULL) {
				php_stream_wrapper_log_error(wrapper, options TSRMLS_CC, "Invalid redirect URL! %s", new_path);
				goto out;
			}

#define CHECK_FOR_CNTRL_CHARS(val) { \
	if (val) { \
		unsigned char *s, *e; \
		int l; \
		l = php_url_decode(val, strlen(val)); \
		s = (unsigned char*)val; e = s + l; \
		while (s < e) { \
			if (iscntrl(*s)) { \
				php_stream_wrapper_log_error(wrapper, options TSRMLS_CC, "Invalid redirect URL! %s", new_path); \
				goto out; \
			} \
			s++; \
		} \
	} \
}
			/* check for control characters in login, password & path */
			if (strncasecmp(new_path, "http://", sizeof("http://") - 1) || strncasecmp(new_path, "https://", sizeof("https://") - 1)) {
				CHECK_FOR_CNTRL_CHARS(resource->user)
				CHECK_FOR_CNTRL_CHARS(resource->pass)
				CHECK_FOR_CNTRL_CHARS(resource->path)
			}
			stream = php_stream_url_wrap_http_ex(wrapper, new_path, mode, options, opened_path, context, --redirect_max, HTTP_WRAPPER_REDIRECTED STREAMS_CC TSRMLS_CC);
		} else {
Exemplo n.º 7
0
ONPHP_METHOD(QuerySkeleton, toDialectString)
{
	zval *where;
	unsigned int array_count = 0;
	
	where = ONPHP_READ_PROPERTY(getThis(), "where");
	
	if (
		(Z_TYPE_P(where) == IS_ARRAY)
		&& (array_count = zend_hash_num_elements(Z_ARRVAL_P(where)))
		&& (array_count > 0)
	) {
		zval *exp, *out, *logic, *whereLogic, *dialect;
		unsigned int i, retval_len;
		char *retval;
		char output_logic = 0;
		smart_str clause = {0};
		
		ONPHP_GET_ARGS("O", &dialect, onphp_ce_Dialect);
		
		whereLogic = ONPHP_READ_PROPERTY(getThis(), "whereLogic");
		
		smart_str_appendl(&clause, " WHERE", 6);
		
		for (i = 0; i < array_count; ++i) {
			ONPHP_ARRAY_GET(where, i, exp);
			
			ONPHP_CALL_METHOD_1(exp, "todialectstring", &out, dialect);
			
			if (Z_STRLEN_P(out)) {
				
				ONPHP_ARRAY_GET(whereLogic, i, logic);
				
				if (EG(exception)) {
					zval_ptr_dtor(&out);
					return;
				}
				
				// can be null
				if (Z_TYPE_P(logic) == IS_STRING) {
					onphp_append_zval_to_smart_string(&clause, logic);
				}
				
				smart_str_appendc(&clause, ' ');
				
				onphp_append_zval_to_smart_string(&clause, out);
				
				smart_str_appendc(&clause, ' ');
				
				output_logic = 1;
			} else if (
				(output_logic == 0)
				&& ((i + 1) <= array_count)
				&& ONPHP_ARRAY_ISSET(whereLogic, i + 1)
			) {
				add_index_null(whereLogic, i + 1);
			}
			
			zval_ptr_dtor(&out);
		}
		
		retval = (char *) php_trim(clause.c, clause.len, " ", 1, NULL, 2 TSRMLS_CC);
		smart_str_0(&clause);
		smart_str_free(&clause);
		retval_len = strlen(retval);
		
		RETURN_STRINGL(retval, retval_len, 0);
	}
	
	RETURN_NULL();
}
Exemplo n.º 8
0
php_stream *php_stream_url_wrap_http_ex(php_stream_wrapper *wrapper, char *path, char *mode, int options, char **opened_path, php_stream_context *context, int redirect_max, int header_init STREAMS_DC TSRMLS_DC)
{
	php_stream *stream = NULL;
	php_url *resource = NULL;
	int use_ssl;
	int use_proxy = 0;
	char *scratch = NULL;
	char *tmp = NULL;
	char *ua_str = NULL;
	zval **ua_zval = NULL, **tmpzval = NULL;
	int scratch_len = 0;
	int body = 0;
	char location[HTTP_HEADER_BLOCK_SIZE];
	zval *response_header = NULL;
	int reqok = 0;
	char *http_header_line = NULL;
	char tmp_line[128];
	size_t chunk_size = 0, file_size = 0;
	int eol_detect = 0;
	char *transport_string, *errstr = NULL;
	int transport_len, have_header = 0, request_fulluri = 0;
	char *protocol_version = NULL;
	int protocol_version_len = 3; /* Default: "1.0" */
	struct timeval timeout;
	char *user_headers = NULL;

	tmp_line[0] = '\0';

	if (redirect_max < 1) {
		php_stream_wrapper_log_error(wrapper, options TSRMLS_CC, "Redirection limit reached, aborting");
		return NULL;
	}

	resource = php_url_parse(path);
	if (resource == NULL) {
		return NULL;
	}

	if (strncasecmp(resource->scheme, "http", sizeof("http")) && strncasecmp(resource->scheme, "https", sizeof("https"))) {
		if (!context || 
			php_stream_context_get_option(context, wrapper->wops->label, "proxy", &tmpzval) == FAILURE ||
			Z_TYPE_PP(tmpzval) != IS_STRING ||
			Z_STRLEN_PP(tmpzval) <= 0) {
			php_url_free(resource);
			return php_stream_open_wrapper_ex(path, mode, REPORT_ERRORS, NULL, context);
		}
		/* Called from a non-http wrapper with http proxying requested (i.e. ftp) */
		request_fulluri = 1;
		use_ssl = 0;
		use_proxy = 1;

		transport_len = Z_STRLEN_PP(tmpzval);
		transport_string = estrndup(Z_STRVAL_PP(tmpzval), Z_STRLEN_PP(tmpzval));
	} else {
		/* Normal http request (possibly with proxy) */
	
		if (strpbrk(mode, "awx+")) {
			php_stream_wrapper_log_error(wrapper, options TSRMLS_CC, "HTTP wrapper does not support writeable connections");
			php_url_free(resource);
			return NULL;
		}

		use_ssl = resource->scheme && (strlen(resource->scheme) > 4) && resource->scheme[4] == 's';
		/* choose default ports */
		if (use_ssl && resource->port == 0)
			resource->port = 443;
		else if (resource->port == 0)
			resource->port = 80;

		if (context &&
			php_stream_context_get_option(context, wrapper->wops->label, "proxy", &tmpzval) == SUCCESS &&
			Z_TYPE_PP(tmpzval) == IS_STRING &&
			Z_STRLEN_PP(tmpzval) > 0) {
			use_proxy = 1;
			transport_len = Z_STRLEN_PP(tmpzval);
			transport_string = estrndup(Z_STRVAL_PP(tmpzval), Z_STRLEN_PP(tmpzval));
		} else {
			transport_len = spprintf(&transport_string, 0, "%s://%s:%d", use_ssl ? "ssl" : "tcp", resource->host, resource->port);
		}
	}

	if (context && php_stream_context_get_option(context, wrapper->wops->label, "timeout", &tmpzval) == SUCCESS) {
		SEPARATE_ZVAL(tmpzval);
		convert_to_double_ex(tmpzval);
		timeout.tv_sec = (time_t) Z_DVAL_PP(tmpzval);
		timeout.tv_usec = (size_t) ((Z_DVAL_PP(tmpzval) - timeout.tv_sec) * 1000000);
	} else {
		timeout.tv_sec = FG(default_socket_timeout);
		timeout.tv_usec = 0;
	}

	stream = php_stream_xport_create(transport_string, transport_len, options,
			STREAM_XPORT_CLIENT | STREAM_XPORT_CONNECT,
			NULL, &timeout, context, &errstr, NULL);
    
	if (stream) {
		php_stream_set_option(stream, PHP_STREAM_OPTION_READ_TIMEOUT, 0, &timeout);
	}
			
	if (errstr) {
		php_stream_wrapper_log_error(wrapper, options TSRMLS_CC, "%s", errstr);
		efree(errstr);
		errstr = NULL;
	}

	efree(transport_string);

	if (stream && use_proxy && use_ssl) {
		smart_str header = {0};

		smart_str_appendl(&header, "CONNECT ", sizeof("CONNECT ")-1);
		smart_str_appends(&header, resource->host);
		smart_str_appendc(&header, ':');
		smart_str_append_unsigned(&header, resource->port);
		smart_str_appendl(&header, " HTTP/1.0\r\n\r\n", sizeof(" HTTP/1.0\r\n\r\n")-1);
		if (php_stream_write(stream, header.c, header.len) != header.len) {
			php_stream_wrapper_log_error(wrapper, options TSRMLS_CC, "Cannot connect to HTTPS server through proxy");
			php_stream_close(stream);
			stream = NULL;
		}
 	 	smart_str_free(&header);

 	 	if (stream) {
 	 		char header_line[HTTP_HEADER_BLOCK_SIZE];

			/* get response header */
			while (php_stream_gets(stream, header_line, HTTP_HEADER_BLOCK_SIZE-1) != NULL)	{
				if (header_line[0] == '\n' ||
				    header_line[0] == '\r' ||
				    header_line[0] == '\0') {
				  break;
				}
			}
		}

		/* enable SSL transport layer */
		if (stream) {
			if (php_stream_xport_crypto_setup(stream, STREAM_CRYPTO_METHOD_SSLv23_CLIENT, NULL TSRMLS_CC) < 0 ||
			    php_stream_xport_crypto_enable(stream, 1 TSRMLS_CC) < 0) {
				php_stream_wrapper_log_error(wrapper, options TSRMLS_CC, "Cannot connect to HTTPS server through proxy");
				php_stream_close(stream);
				stream = NULL;
			}
		}
	}

	if (stream == NULL)	
		goto out;

	/* avoid buffering issues while reading header */
	if (options & STREAM_WILL_CAST)
		chunk_size = php_stream_set_chunk_size(stream, 1);
	
	/* avoid problems with auto-detecting when reading the headers -> the headers
	 * are always in canonical \r\n format */
	eol_detect = stream->flags & (PHP_STREAM_FLAG_DETECT_EOL | PHP_STREAM_FLAG_EOL_MAC);
	stream->flags &= ~(PHP_STREAM_FLAG_DETECT_EOL | PHP_STREAM_FLAG_EOL_MAC);

	php_stream_context_set(stream, context);

	php_stream_notify_info(context, PHP_STREAM_NOTIFY_CONNECT, NULL, 0);

	if (header_init && context && php_stream_context_get_option(context, "http", "max_redirects", &tmpzval) == SUCCESS) {
		SEPARATE_ZVAL(tmpzval);
		convert_to_long_ex(tmpzval);
		redirect_max = Z_LVAL_PP(tmpzval);
	}

	if (context && php_stream_context_get_option(context, "http", "method", &tmpzval) == SUCCESS) {
		if (Z_TYPE_PP(tmpzval) == IS_STRING && Z_STRLEN_PP(tmpzval) > 0) {
			scratch_len = strlen(path) + 29 + Z_STRLEN_PP(tmpzval);
			scratch = emalloc(scratch_len);
			strlcpy(scratch, Z_STRVAL_PP(tmpzval), Z_STRLEN_PP(tmpzval) + 1);
			strcat(scratch, " ");
		}
	}
 
	if (context && php_stream_context_get_option(context, "http", "protocol_version", &tmpzval) == SUCCESS) {
		SEPARATE_ZVAL(tmpzval);
		convert_to_double_ex(tmpzval);
		protocol_version_len = spprintf(&protocol_version, 0, "%.1F", Z_DVAL_PP(tmpzval));
	}

	if (!scratch) {
		scratch_len = strlen(path) + 29 + protocol_version_len;
		scratch = emalloc(scratch_len);
		strcpy(scratch, "GET ");
	}

	/* Should we send the entire path in the request line, default to no. */
	if (!request_fulluri &&
		context &&
		php_stream_context_get_option(context, "http", "request_fulluri", &tmpzval) == SUCCESS) {
		zval tmp = **tmpzval;

		zval_copy_ctor(&tmp);
		convert_to_boolean(&tmp);
		request_fulluri = Z_BVAL(tmp) ? 1 : 0;
		zval_dtor(&tmp);
	}

	if (request_fulluri) {
		/* Ask for everything */
		strcat(scratch, path);
	} else {
		/* Send the traditional /path/to/file?query_string */

		/* file */
		if (resource->path && *resource->path) {
			strlcat(scratch, resource->path, scratch_len);
		} else {
			strlcat(scratch, "/", scratch_len);
		}

		/* query string */
		if (resource->query)	{
			strlcat(scratch, "?", scratch_len);
			strlcat(scratch, resource->query, scratch_len);
		}
	}

	/* protocol version we are speaking */
	if (protocol_version) {
		strlcat(scratch, " HTTP/", scratch_len);
		strlcat(scratch, protocol_version, scratch_len);
		strlcat(scratch, "\r\n", scratch_len);
		efree(protocol_version);
		protocol_version = NULL;
	} else {
		strlcat(scratch, " HTTP/1.0\r\n", scratch_len);
	}


	/* send it */
	php_stream_write(stream, scratch, strlen(scratch));

	if (context &&
		php_stream_context_get_option(context, "http", "header", &tmpzval) == SUCCESS &&
		Z_TYPE_PP(tmpzval) == IS_STRING && Z_STRLEN_PP(tmpzval)) {
		/* Remove newlines and spaces from start and end,
		   php_trim will estrndup() */
		tmp = php_trim(Z_STRVAL_PP(tmpzval), Z_STRLEN_PP(tmpzval), NULL, 0, NULL, 3 TSRMLS_CC);
		if (strlen(tmp) > 0) {
			if (!header_init) { /* Remove post headers for redirects */
				int l = strlen(tmp);
				char *s, *s2, *tmp_c = estrdup(tmp);
				
				php_strtolower(tmp_c, l);
				if ((s = strstr(tmp_c, "content-length:"))) {
					if ((s2 = memchr(s, '\n', tmp_c + l - s))) {
						int b = tmp_c + l - 1 - s2;
						memmove(tmp, tmp + (s2 + 1 - tmp_c), b);
						memmove(tmp_c, s2 + 1, b);
						
					} else {
						tmp[s - tmp_c] = *s = '\0';
					}
					l = strlen(tmp_c);
				}
				if ((s = strstr(tmp_c, "content-type:"))) {
					if ((s2 = memchr(s, '\n', tmp_c + l - s))) {
						memmove(tmp, tmp + (s2 + 1 - tmp_c), tmp_c + l - 1 - s2);
					} else {
						tmp[s - tmp_c] = '\0';
					}
				}
				efree(tmp_c);
				tmp_c = php_trim(tmp, strlen(tmp), NULL, 0, NULL, 3 TSRMLS_CC);
				efree(tmp);
				tmp = tmp_c;
			}

			user_headers = estrdup(tmp);

			/* Make lowercase for easy comparison against 'standard' headers */
			php_strtolower(tmp, strlen(tmp));
			if (strstr(tmp, "user-agent:")) {
				 have_header |= HTTP_HEADER_USER_AGENT;
			}
			if (strstr(tmp, "host:")) {
				 have_header |= HTTP_HEADER_HOST;
			}
			if (strstr(tmp, "from:")) {
				 have_header |= HTTP_HEADER_FROM;
				}
			if (strstr(tmp, "authorization:")) {
				 have_header |= HTTP_HEADER_AUTH;
			}
			if (strstr(tmp, "content-length:")) {
				 have_header |= HTTP_HEADER_CONTENT_LENGTH;
			}
			if (strstr(tmp, "content-type:")) {
				 have_header |= HTTP_HEADER_TYPE;
			}
		}
		efree(tmp);
	}

	/* auth header if it was specified */
	if (((have_header & HTTP_HEADER_AUTH) == 0) && resource->user && resource->pass)	{
		/* decode the strings first */
		php_url_decode(resource->user, strlen(resource->user));
		php_url_decode(resource->pass, strlen(resource->pass));

		/* scratch is large enough, since it was made large enough for the whole URL */
		strcpy(scratch, resource->user);
		strcat(scratch, ":");
		strcat(scratch, resource->pass);

		tmp = php_base64_encode((unsigned char*)scratch, strlen(scratch), NULL);
		
		if (snprintf(scratch, scratch_len, "Authorization: Basic %s\r\n", tmp) > 0) {
			php_stream_write(stream, scratch, strlen(scratch));
			php_stream_notify_info(context, PHP_STREAM_NOTIFY_AUTH_REQUIRED, NULL, 0);
		}

		efree(tmp);
		tmp = NULL;
	}

	/* if the user has configured who they are, send a From: line */
	if (((have_header & HTTP_HEADER_FROM) == 0) && cfg_get_string("from", &tmp) == SUCCESS)	{
		if (snprintf(scratch, scratch_len, "From: %s\r\n", tmp) > 0)
			php_stream_write(stream, scratch, strlen(scratch));
	}

	/* Send Host: header so name-based virtual hosts work */
	if ((have_header & HTTP_HEADER_HOST) == 0) {
		if ((use_ssl && resource->port != 443 && resource->port != 0) || 
			(!use_ssl && resource->port != 80 && resource->port != 0))	{
			if (snprintf(scratch, scratch_len, "Host: %s:%i\r\n", resource->host, resource->port) > 0)
				php_stream_write(stream, scratch, strlen(scratch));
		} else {
			if (snprintf(scratch, scratch_len, "Host: %s\r\n", resource->host) > 0) {
				php_stream_write(stream, scratch, strlen(scratch));
			}
		}
	}

	if (context && 
	    php_stream_context_get_option(context, "http", "user_agent", &ua_zval) == SUCCESS &&
		Z_TYPE_PP(ua_zval) == IS_STRING) {
		ua_str = Z_STRVAL_PP(ua_zval);
	} else if (FG(user_agent)) {
		ua_str = FG(user_agent);
	}

	if (((have_header & HTTP_HEADER_USER_AGENT) == 0) && ua_str) {
#define _UA_HEADER "User-Agent: %s\r\n"
		char *ua;
		size_t ua_len;
		
		ua_len = sizeof(_UA_HEADER) + strlen(ua_str);
		
		/* ensure the header is only sent if user_agent is not blank */
		if (ua_len > sizeof(_UA_HEADER)) {
			ua = emalloc(ua_len + 1);
			if ((ua_len = slprintf(ua, ua_len, _UA_HEADER, ua_str)) > 0) {
				ua[ua_len] = 0;
				php_stream_write(stream, ua, ua_len);
			} else {
				php_error_docref(NULL TSRMLS_CC, E_WARNING, "Cannot construct User-agent header");
			}

			if (ua) {
				efree(ua);
			}
		}	
	}

	if (user_headers) {
		/* A bit weird, but some servers require that Content-Length be sent prior to Content-Type for POST
		 * see bug #44603 for details. Since Content-Type maybe part of user's headers we need to do this check first.
		 */
		if (
				header_init &&
				context &&
				!(have_header & HTTP_HEADER_CONTENT_LENGTH) &&
				php_stream_context_get_option(context, "http", "content", &tmpzval) == SUCCESS &&
				Z_TYPE_PP(tmpzval) == IS_STRING && Z_STRLEN_PP(tmpzval) > 0
		) {
			scratch_len = slprintf(scratch, scratch_len, "Content-Length: %d\r\n", Z_STRLEN_PP(tmpzval));
			php_stream_write(stream, scratch, scratch_len);
			have_header |= HTTP_HEADER_CONTENT_LENGTH;
		}

		php_stream_write(stream, user_headers, strlen(user_headers));
		php_stream_write(stream, "\r\n", sizeof("\r\n")-1);
		efree(user_headers);
	}

	/* Request content, such as for POST requests */
	if (header_init && context &&
		php_stream_context_get_option(context, "http", "content", &tmpzval) == SUCCESS &&
		Z_TYPE_PP(tmpzval) == IS_STRING && Z_STRLEN_PP(tmpzval) > 0) {
		if (!(have_header & HTTP_HEADER_CONTENT_LENGTH)) {
			scratch_len = slprintf(scratch, scratch_len, "Content-Length: %d\r\n", Z_STRLEN_PP(tmpzval));
			php_stream_write(stream, scratch, scratch_len);
		}
		if (!(have_header & HTTP_HEADER_TYPE)) {
			php_stream_write(stream, "Content-Type: application/x-www-form-urlencoded\r\n",
				sizeof("Content-Type: application/x-www-form-urlencoded\r\n") - 1);
			php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Content-type not specified assuming application/x-www-form-urlencoded");
		}
		php_stream_write(stream, "\r\n", sizeof("\r\n")-1);
		php_stream_write(stream, Z_STRVAL_PP(tmpzval), Z_STRLEN_PP(tmpzval));
		php_stream_write(stream, "\r\n\r\n", sizeof("\r\n\r\n")-1);
	} else {
		php_stream_write(stream, "\r\n", sizeof("\r\n")-1);
	}

	location[0] = '\0';

	if (header_init) {
		zval *tmp;
		MAKE_STD_ZVAL(tmp);
		array_init(tmp);
		ZEND_SET_SYMBOL(EG(active_symbol_table), "http_response_header", tmp);
	}

	{
		zval **rh;
		zend_hash_find(EG(active_symbol_table), "http_response_header", sizeof("http_response_header"), (void **) &rh);
		response_header = *rh;
	}

	if (!php_stream_eof(stream)) {
		size_t tmp_line_len;
		/* get response header */

		if (php_stream_get_line(stream, tmp_line, sizeof(tmp_line) - 1, &tmp_line_len) != NULL) {
			zval *http_response;
			int response_code;

			if (tmp_line_len > 9) {
				response_code = atoi(tmp_line + 9);
			} else {
				response_code = 0;
			}
			/* when we request only the header, don't fail even on error codes */
			if (options & STREAM_ONLY_GET_HEADERS) {
				reqok = 1;
			}
			switch(response_code) {
				case 200:
				case 206: /* partial content */
				case 302:
				case 303:
				case 301:
					reqok = 1;
					break;
				case 403:
					php_stream_notify_error(context, PHP_STREAM_NOTIFY_AUTH_RESULT,
							tmp_line, response_code);
					break;
				default:
					/* safety net in the event tmp_line == NULL */
					if (!tmp_line_len) {
						tmp_line[0] = '\0';
					}
					php_stream_notify_error(context, PHP_STREAM_NOTIFY_FAILURE,
							tmp_line, response_code);
			}
			if (tmp_line[tmp_line_len - 1] == '\n') {
				--tmp_line_len;
				if (tmp_line[tmp_line_len - 1] == '\r') {
					--tmp_line_len;
				}
			}
			MAKE_STD_ZVAL(http_response);
			ZVAL_STRINGL(http_response, tmp_line, tmp_line_len, 1);
			zend_hash_next_index_insert(Z_ARRVAL_P(response_header), &http_response, sizeof(zval *), NULL);
		}
	} else {
		php_stream_wrapper_log_error(wrapper, options TSRMLS_CC, "HTTP request failed, unexpected end of socket!");
		goto out;
	}
	
	/* read past HTTP headers */
	
	http_header_line = emalloc(HTTP_HEADER_BLOCK_SIZE);

	while (!body && !php_stream_eof(stream)) {
		size_t http_header_line_length;
		if (php_stream_get_line(stream, http_header_line, HTTP_HEADER_BLOCK_SIZE, &http_header_line_length) && *http_header_line != '\n' && *http_header_line != '\r') {
			char *e = http_header_line + http_header_line_length - 1;
			while (*e == '\n' || *e == '\r') {
				e--;
			}
			http_header_line_length = e - http_header_line + 1;
			http_header_line[http_header_line_length] = '\0';

			if (!strncasecmp(http_header_line, "Location: ", 10)) {
				strlcpy(location, http_header_line + 10, sizeof(location));
			} else if (!strncasecmp(http_header_line, "Content-Type: ", 14)) {
				php_stream_notify_info(context, PHP_STREAM_NOTIFY_MIME_TYPE_IS, http_header_line + 14, 0);
			} else if (!strncasecmp(http_header_line, "Content-Length: ", 16)) {
				file_size = atoi(http_header_line + 16);
				php_stream_notify_file_size(context, file_size, http_header_line, 0);
			}

			if (http_header_line[0] == '\0') {
				body = 1;
			} else {
				zval *http_header;

				MAKE_STD_ZVAL(http_header);

				ZVAL_STRINGL(http_header, http_header_line, http_header_line_length, 1);
				
				zend_hash_next_index_insert(Z_ARRVAL_P(response_header), &http_header, sizeof(zval *), NULL);
			}
		} else {
			break;
		}
	}
	
	if (!reqok || location[0] != '\0') {
		if (options & STREAM_ONLY_GET_HEADERS && redirect_max <= 1) {
			goto out;
		}

		if (location[0] != '\0')
			php_stream_notify_info(context, PHP_STREAM_NOTIFY_REDIRECTED, location, 0);

		php_stream_close(stream);
		stream = NULL;

		if (location[0] != '\0')	{

			char new_path[HTTP_HEADER_BLOCK_SIZE];
			char loc_path[HTTP_HEADER_BLOCK_SIZE];

			*new_path='\0';
			if (strlen(location)<8 || (strncasecmp(location, "http://", sizeof("http://")-1) && 
							strncasecmp(location, "https://", sizeof("https://")-1) && 
							strncasecmp(location, "ftp://", sizeof("ftp://")-1) && 
							strncasecmp(location, "ftps://", sizeof("ftps://")-1))) 
			{
				if (*location != '/') {
					if (*(location+1) != '\0' && resource->path) {		
						char *s = strrchr(resource->path, '/');
						if (!s) {
							s = resource->path;
							if (!s[0]) {
								efree(s);
								s = resource->path = estrdup("/");
							} else {
								*s = '/';
							}
						}
						s[1] = '\0'; 
						if (resource->path && *(resource->path) == '/' && *(resource->path + 1) == '\0') {
							snprintf(loc_path, sizeof(loc_path) - 1, "%s%s", resource->path, location);
						} else {
							snprintf(loc_path, sizeof(loc_path) - 1, "%s/%s", resource->path, location);
						}
					} else {
						snprintf(loc_path, sizeof(loc_path) - 1, "/%s", location);
					}
				} else {
					strlcpy(loc_path, location, sizeof(loc_path));
				}
				if ((use_ssl && resource->port != 443) || (!use_ssl && resource->port != 80)) {
					snprintf(new_path, sizeof(new_path) - 1, "%s://%s:%d%s", resource->scheme, resource->host, resource->port, loc_path);
				} else {
					snprintf(new_path, sizeof(new_path) - 1, "%s://%s%s", resource->scheme, resource->host, loc_path);
				}
			} else {
				strlcpy(new_path, location, sizeof(new_path));
			}

			php_url_free(resource);
			/* check for invalid redirection URLs */
			if ((resource = php_url_parse(new_path)) == NULL) {
				php_stream_wrapper_log_error(wrapper, options TSRMLS_CC, "Invalid redirect URL! %s", new_path);
				goto out;
			}

#define CHECK_FOR_CNTRL_CHARS(val) {	\
	if (val) {	\
		unsigned char *s, *e;	\
		int l;	\
		l = php_url_decode(val, strlen(val));	\
		s = val; e = s + l;	\
		while (s < e) {	\
			if (iscntrl(*s)) {	\
				php_stream_wrapper_log_error(wrapper, options TSRMLS_CC, "Invalid redirect URL! %s", new_path);	\
				goto out;	\
			}	\
			s++;	\
		}	\
	}	\
}	\
			/* check for control characters in login, password & path */
			if (strncasecmp(new_path, "http://", sizeof("http://") - 1) || strncasecmp(new_path, "https://", sizeof("https://") - 1)) {
				CHECK_FOR_CNTRL_CHARS(resource->user)
				CHECK_FOR_CNTRL_CHARS(resource->pass)
				CHECK_FOR_CNTRL_CHARS(resource->path)
			}
			stream = php_stream_url_wrap_http_ex(wrapper, new_path, mode, options, opened_path, context, --redirect_max, 0 STREAMS_CC TSRMLS_CC);
		} else {