Arquivos
hhvm/hphp/runtime/ext/ext_url.cpp
T
Edwin Smith fe32089a67 Reduce use of AttachLiteral StringData construction
This is the first results from profiling callsites of
StringData::initLiteral.  This diff converts a handful more
string literals to StaticString, removes overloaded Variant
comparison operators (operator==, etc), and avoids
constructing new strings in a few cases in tvCastToString
and tvCastToStringInPlace.
2013-06-06 12:00:06 -07:00

292 linhas
8.8 KiB
C++

/*
+----------------------------------------------------------------------+
| HipHop for PHP |
+----------------------------------------------------------------------+
| Copyright (c) 2010-2013 Facebook, Inc. (http://www.facebook.com) |
| Copyright (c) 1997-2010 The PHP Group |
+----------------------------------------------------------------------+
| This source file is subject to version 3.01 of the PHP license, |
| that is bundled with this package in the file LICENSE, and is |
| available through the world-wide-web at the following url: |
| http://www.php.net/license/3_01.txt |
| If you did not receive a copy of the PHP license and are unable to |
| obtain it through the world-wide-web, please send a note to |
| license@php.net so we can mail you a copy immediately. |
+----------------------------------------------------------------------+
*/
#include "hphp/runtime/ext/ext_url.h"
#include "hphp/runtime/base/string_util.h"
#include "hphp/runtime/base/zend/zend_url.h"
#include "hphp/runtime/base/util/string_buffer.h"
#include "hphp/runtime/ext/ext_curl.h"
#include "hphp/runtime/ext/ext_string.h"
#include "hphp/runtime/ext/ext_file.h"
#include "hphp/runtime/ext/ext_preg.h"
#include "hphp/runtime/ext/ext_options.h"
namespace HPHP {
///////////////////////////////////////////////////////////////////////////////
Variant f_base64_decode(CStrRef data, bool strict /* = false */) {
String decoded = StringUtil::Base64Decode(data, strict);
if (decoded.isNull()) {
return false;
}
return decoded;
}
String f_base64_encode(CStrRef data) {
String encoded = StringUtil::Base64Encode(data);
if (encoded.isNull()) {
return false;
}
return encoded;
}
Variant f_get_headers(CStrRef url, int format /* = 0 */) {
Variant c = f_curl_init();
f_curl_setopt(c, k_CURLOPT_URL, url);
f_curl_setopt(c, k_CURLOPT_RETURNTRANSFER, true);
f_curl_setopt(c, k_CURLOPT_HEADER, 1);
Variant res = f_curl_exec(c);
if (same(res, false)) {
return false;
}
String response = res.toString();
int pos = response.find("\r\n\r\n");
if (pos != String::npos) {
response = response.substr(0, pos);
}
Array ret = f_explode("\r\n", response);
if (!format) {
return ret;
}
Array assoc;
for (ArrayIter iter(ret); iter; ++iter) {
Array tokens = f_explode(": ", iter.second(), 2);
if (tokens.size() == 2) {
assoc.set(tokens[0], tokens[1]);
} else {
assoc.append(iter.second());
}
}
return assoc;
}
static String normalize_variable_name(CStrRef name) {
StringBuffer sb;
for (int i = 0; i < name.size(); i++) {
char ch = name.charAt(i);
if ((i > 0 && ch >= '0' && ch <= '9') ||
(ch >= 'a' && ch <= 'z') ||
(ch == '_')) {
sb.append(ch);
} else if (ch >= 'A' && ch <= 'Z') {
sb.append((char)(ch + 'a' - 'A'));
} else {
sb.append('_');
}
}
return sb.detach();
}
Array f_get_meta_tags(CStrRef filename, bool use_include_path /* = false */) {
String f = f_file_get_contents(filename);
Variant matches;
f_preg_match_all("/<meta\\s+name=\"(.*?)\"\\s+content=\"(.*?)\".*?>/s",
f, ref(matches), k_PREG_SET_ORDER);
Array ret = Array::Create();
for (ArrayIter iter(matches); iter; ++iter) {
Array pair = iter.second();
ret.set(normalize_variable_name(pair[1].toString()), pair[2]);
}
return ret;
}
///////////////////////////////////////////////////////////////////////////////
static void url_encode_array(StringBuffer &ret, CVarRef varr,
std::set<void*> &seen_arrs,
CStrRef num_prefix, CStrRef key_prefix,
CStrRef key_suffix, CStrRef arg_sep) {
void *id = varr.is(KindOfArray) ?
(void*)varr.getArrayData() : (void*)varr.getObjectData();
if (!seen_arrs.insert(id).second) {
return; // recursive
}
Array arr = varr.toArray();
for (ArrayIter iter(arr); iter; ++iter) {
Variant data = iter.second();
if (data.isNull() || data.isResource()) continue;
String key = iter.first();
bool numeric = key.isNumeric();
if (data.is(KindOfArray) || data.is(KindOfObject)) {
String encoded;
if (numeric) {
encoded = key;
} else {
encoded = StringUtil::UrlEncode(key);
}
StringBuffer new_prefix(key_prefix.size() + num_prefix.size() +
encoded.size() + key_suffix.size() + 4);
new_prefix += key_prefix;
if (numeric) new_prefix += num_prefix;
new_prefix += encoded;
new_prefix += key_suffix;
new_prefix += "%5B";
url_encode_array(ret, data, seen_arrs, String(),
new_prefix.detach(), String("%5D", AttachLiteral),
arg_sep);
} else {
if (!ret.empty()) {
ret += arg_sep;
}
ret += key_prefix;
if (numeric) {
ret += num_prefix;
ret += key;
} else {
ret += StringUtil::UrlEncode(key);
}
ret += key_suffix;
ret += "=";
if (data.isInteger() || data.is(KindOfBoolean)) {
ret += String(data.toInt64());
} else if (data.is(KindOfDouble)) {
ret += String(data.toDouble());
} else {
ret += StringUtil::UrlEncode(data.toString());
}
}
}
}
static const StaticString s_arg_separator_output("arg_separator.output");
Variant f_http_build_query(CVarRef formdata,
CStrRef numeric_prefix /* = null_string */,
CStrRef arg_separator /* = null_string */) {
if (!formdata.is(KindOfArray) && !formdata.is(KindOfObject)) {
throw_invalid_argument("formdata: (need Array or Object)");
return false;
}
String arg_sep;
if (arg_separator.isNull()) {
arg_sep = f_ini_get(s_arg_separator_output);
} else {
arg_sep = arg_separator;
}
StringBuffer ret(1024);
std::set<void*> seen_arrs;
url_encode_array(ret, formdata, seen_arrs,
numeric_prefix, String(), String(), arg_sep);
return ret.detach();
}
///////////////////////////////////////////////////////////////////////////////
static const StaticString
s_scheme("scheme"),
s_host("host"),
s_user("user"),
s_pass("pass"),
s_path("path"),
s_query("query"),
s_fragment("fragment"),
s_port("port");
#define RETURN_COMPONENT(name) \
if (resource.name != NULL) { \
String ret(resource.name, AttachString); \
resource.name = NULL; \
return ret; \
} \
#define SET_COMPONENT(name) \
if (resource.name != NULL) { \
ret.set(s_ ## name, String(resource.name, AttachString)); \
resource.name = NULL; \
} \
#define PHP_URL_SCHEME 0
#define PHP_URL_HOST 1
#define PHP_URL_PORT 2
#define PHP_URL_USER 3
#define PHP_URL_PASS 4
#define PHP_URL_PATH 5
#define PHP_URL_QUERY 6
#define PHP_URL_FRAGMENT 7
Variant f_parse_url(CStrRef url, int component /* = -1 */) {
Url resource;
if (!url_parse(resource, url.data(), url.size())) {
raise_notice("invalid url: %s", url.data());
return false;
}
if (component > -1) {
switch (component) {
case PHP_URL_SCHEME: RETURN_COMPONENT(scheme); break;
case PHP_URL_HOST: RETURN_COMPONENT(host); break;
case PHP_URL_USER: RETURN_COMPONENT(user); break;
case PHP_URL_PASS: RETURN_COMPONENT(pass); break;
case PHP_URL_PATH: RETURN_COMPONENT(path); break;
case PHP_URL_QUERY: RETURN_COMPONENT(query); break;
case PHP_URL_FRAGMENT: RETURN_COMPONENT(fragment); break;
case PHP_URL_PORT:
if (resource.port) {
return resource.port;
}
break;
default:
throw_invalid_argument("component: %d", component);
return false;
}
return uninit_null();
}
ArrayInit ret(8);
SET_COMPONENT(scheme);
SET_COMPONENT(host);
SET_COMPONENT(user);
SET_COMPONENT(pass);
SET_COMPONENT(path);
SET_COMPONENT(query);
SET_COMPONENT(fragment);
if (resource.port) {
ret.set(s_port, (int64_t)resource.port);
}
return ret.create();
}
String f_rawurldecode(CStrRef str) {
return StringUtil::UrlDecode(str, false);
}
String f_rawurlencode(CStrRef str) {
return StringUtil::UrlEncode(str, false);
}
String f_urldecode(CStrRef str) {
return StringUtil::UrlDecode(str, true);
}
String f_urlencode(CStrRef str) {
return StringUtil::UrlEncode(str, true);
}
///////////////////////////////////////////////////////////////////////////////
}