PageRenderTime 49ms CodeModel.GetById 17ms RepoModel.GetById 1ms app.codeStats 0ms

/hphp/runtime/ext/url/ext_url.cpp

https://github.com/tstarling/hiphop-php
C++ | 370 lines | 310 code | 38 blank | 22 comment | 55 complexity | 1ec052ec1ff278360a954072e342899a MD5 | raw file
  1. /*
  2. +----------------------------------------------------------------------+
  3. | HipHop for PHP |
  4. +----------------------------------------------------------------------+
  5. | Copyright (c) 2010-2014 Facebook, Inc. (http://www.facebook.com) |
  6. | Copyright (c) 1997-2010 The PHP Group |
  7. +----------------------------------------------------------------------+
  8. | This source file is subject to version 3.01 of the PHP license, |
  9. | that is bundled with this package in the file LICENSE, and is |
  10. | available through the world-wide-web at the following url: |
  11. | http://www.php.net/license/3_01.txt |
  12. | If you did not receive a copy of the PHP license and are unable to |
  13. | obtain it through the world-wide-web, please send a note to |
  14. | license@php.net so we can mail you a copy immediately. |
  15. +----------------------------------------------------------------------+
  16. */
  17. #include "hphp/runtime/ext/url/ext_url.h"
  18. #include <set>
  19. #include "hphp/runtime/base/string-util.h"
  20. #include "hphp/runtime/base/zend-url.h"
  21. #include "hphp/runtime/base/string-buffer.h"
  22. #include "hphp/runtime/ext/curl/ext_curl.h"
  23. #include "hphp/runtime/ext/ext_string.h"
  24. #include "hphp/runtime/ext/ext_file.h"
  25. #include "hphp/runtime/ext/pcre/ext_pcre.h"
  26. #include "hphp/runtime/ext/std/ext_std_options.h"
  27. namespace HPHP {
  28. ///////////////////////////////////////////////////////////////////////////////
  29. const int64_t k_PHP_URL_SCHEME = 0;
  30. const int64_t k_PHP_URL_HOST = 1;
  31. const int64_t k_PHP_URL_PORT = 2;
  32. const int64_t k_PHP_URL_USER = 3;
  33. const int64_t k_PHP_URL_PASS = 4;
  34. const int64_t k_PHP_URL_PATH = 5;
  35. const int64_t k_PHP_URL_QUERY = 6;
  36. const int64_t k_PHP_URL_FRAGMENT = 7;
  37. const int64_t k_PHP_QUERY_RFC1738 = 1;
  38. const int64_t k_PHP_QUERY_RFC3986 = 2;
  39. ///////////////////////////////////////////////////////////////////////////////
  40. Variant HHVM_FUNCTION(base64_decode, const String& data,
  41. bool strict /* = false */) {
  42. String decoded = StringUtil::Base64Decode(data, strict);
  43. if (decoded.isNull()) {
  44. return false;
  45. }
  46. return decoded;
  47. }
  48. Variant HHVM_FUNCTION(base64_encode, const String& data) {
  49. String encoded = StringUtil::Base64Encode(data);
  50. if (encoded.isNull()) {
  51. return false;
  52. }
  53. return encoded;
  54. }
  55. Variant HHVM_FUNCTION(get_headers, const String& url, int format /* = 0 */) {
  56. Variant c = HHVM_FN(curl_init)();
  57. HHVM_FN(curl_setopt)(c.toResource(), k_CURLOPT_URL, url);
  58. HHVM_FN(curl_setopt)(c.toResource(), k_CURLOPT_RETURNTRANSFER, true);
  59. HHVM_FN(curl_setopt)(c.toResource(), k_CURLOPT_HEADER, 1);
  60. Variant res = HHVM_FN(curl_exec)(c.toResource());
  61. if (same(res, false)) {
  62. return false;
  63. }
  64. String response = res.toString();
  65. int pos = response.find("\r\n\r\n");
  66. if (pos != String::npos) {
  67. response = response.substr(0, pos);
  68. }
  69. Array ret = f_explode("\r\n", response).toArray();
  70. if (!format) {
  71. return ret;
  72. }
  73. Array assoc;
  74. for (ArrayIter iter(ret); iter; ++iter) {
  75. Array tokens = f_explode(": ", iter.second(), 2).toArray();
  76. if (tokens.size() == 2) {
  77. assoc.set(tokens[0], tokens[1]);
  78. } else {
  79. assoc.append(iter.second());
  80. }
  81. }
  82. return assoc;
  83. }
  84. static String normalize_variable_name(const String& name) {
  85. StringBuffer sb;
  86. for (int i = 0; i < name.size(); i++) {
  87. char ch = name.charAt(i);
  88. if ((i > 0 && ch >= '0' && ch <= '9') ||
  89. (ch >= 'a' && ch <= 'z') ||
  90. (ch == '_')) {
  91. sb.append(ch);
  92. } else if (ch >= 'A' && ch <= 'Z') {
  93. sb.append((char)(ch + 'a' - 'A'));
  94. } else {
  95. sb.append('_');
  96. }
  97. }
  98. return sb.detach();
  99. }
  100. Array HHVM_FUNCTION(get_meta_tags, const String& filename,
  101. bool use_include_path /* = false */) {
  102. String f = f_file_get_contents(filename);
  103. Variant matches;
  104. HHVM_FN(preg_match_all)("/<meta\\s+name=\"(.*?)\"\\s+content=\"(.*?)\".*?>/s",
  105. f, ref(matches), k_PREG_SET_ORDER);
  106. Array ret = Array::Create();
  107. for (ArrayIter iter(matches.toArray()); iter; ++iter) {
  108. Array pair = iter.second().toArray();
  109. ret.set(normalize_variable_name(pair[1].toString()), pair[2]);
  110. }
  111. return ret;
  112. }
  113. ///////////////////////////////////////////////////////////////////////////////
  114. static void url_encode_array(StringBuffer &ret, const Variant& varr,
  115. std::set<void*> &seen_arrs,
  116. const String& num_prefix, const String& key_prefix,
  117. const String& key_suffix, const String& arg_sep,
  118. bool encode_plus = true) {
  119. void *id = varr.is(KindOfArray) ?
  120. (void*)varr.getArrayData() : (void*)varr.getObjectData();
  121. if (!seen_arrs.insert(id).second) {
  122. return; // recursive
  123. }
  124. Array arr;
  125. if (varr.is(KindOfObject)) {
  126. Object o = varr.toObject();
  127. arr = o->isCollection()
  128. ? varr.toArray()
  129. : f_get_object_vars(o).toArray();
  130. } else {
  131. arr = varr.toArray();
  132. }
  133. for (ArrayIter iter(arr); iter; ++iter) {
  134. Variant data = iter.second();
  135. if (data.isNull() || data.isResource()) continue;
  136. String key = iter.first();
  137. bool numeric = key.isNumeric();
  138. if (data.is(KindOfArray) || data.is(KindOfObject)) {
  139. String encoded;
  140. if (numeric) {
  141. encoded = key;
  142. } else {
  143. encoded = StringUtil::UrlEncode(key, encode_plus);
  144. }
  145. StringBuffer new_prefix(key_prefix.size() + num_prefix.size() +
  146. encoded.size() + key_suffix.size() + 4);
  147. new_prefix.append(key_prefix);
  148. if (numeric) new_prefix.append(num_prefix);
  149. new_prefix.append(encoded);
  150. new_prefix.append(key_suffix);
  151. new_prefix.append("%5B");
  152. url_encode_array(ret, data, seen_arrs, String(),
  153. new_prefix.detach(), String("%5D", CopyString),
  154. arg_sep);
  155. } else {
  156. if (!ret.empty()) {
  157. ret.append(arg_sep);
  158. }
  159. ret.append(key_prefix);
  160. if (numeric) {
  161. ret.append(num_prefix);
  162. ret.append(key);
  163. } else {
  164. ret.append(StringUtil::UrlEncode(key, encode_plus));
  165. }
  166. ret.append(key_suffix);
  167. ret.append("=");
  168. if (data.isInteger() || data.is(KindOfBoolean)) {
  169. ret.append(String(data.toInt64()));
  170. } else if (data.is(KindOfDouble)) {
  171. ret.append(String(data.toDouble()));
  172. } else {
  173. ret.append(StringUtil::UrlEncode(data.toString(), encode_plus));
  174. }
  175. }
  176. }
  177. }
  178. const StaticString s_arg_separator_output("arg_separator.output");
  179. Variant HHVM_FUNCTION(http_build_query, const Variant& formdata,
  180. const String& numeric_prefix /* = null_string */,
  181. const String& arg_separator /* = null_string */,
  182. int enc_type /* = k_PHP_QUERY_RFC1738 */) {
  183. if (!formdata.is(KindOfArray) && !formdata.is(KindOfObject)) {
  184. throw_invalid_argument("formdata: (need Array or Object)");
  185. return false;
  186. }
  187. String arg_sep;
  188. if (arg_separator.empty()) {
  189. arg_sep = HHVM_FN(ini_get)(s_arg_separator_output);
  190. } else {
  191. arg_sep = arg_separator;
  192. }
  193. StringBuffer ret(1024);
  194. std::set<void*> seen_arrs;
  195. url_encode_array(ret, formdata, seen_arrs,
  196. numeric_prefix, String(), String(), arg_sep,
  197. enc_type != k_PHP_QUERY_RFC3986);
  198. return ret.detach();
  199. }
  200. ///////////////////////////////////////////////////////////////////////////////
  201. const StaticString
  202. s_scheme("scheme"),
  203. s_host("host"),
  204. s_user("user"),
  205. s_pass("pass"),
  206. s_path("path"),
  207. s_query("query"),
  208. s_fragment("fragment"),
  209. s_port("port");
  210. #define RETURN_COMPONENT(name) \
  211. if (resource.name != NULL) { \
  212. String ret(resource.name, AttachString); \
  213. resource.name = NULL; \
  214. return ret; \
  215. } \
  216. #define SET_COMPONENT(name) \
  217. if (resource.name != NULL) { \
  218. ret.set(s_ ## name, String(resource.name, AttachString)); \
  219. resource.name = NULL; \
  220. } \
  221. Variant HHVM_FUNCTION(parse_url, const String& url,
  222. int64_t component /* = -1 */) {
  223. Url resource;
  224. if (!url_parse(resource, url.data(), url.size())) {
  225. return false;
  226. }
  227. if (component > -1) {
  228. switch (component) {
  229. case k_PHP_URL_SCHEME: RETURN_COMPONENT(scheme); break;
  230. case k_PHP_URL_HOST: RETURN_COMPONENT(host); break;
  231. case k_PHP_URL_USER: RETURN_COMPONENT(user); break;
  232. case k_PHP_URL_PASS: RETURN_COMPONENT(pass); break;
  233. case k_PHP_URL_PATH: RETURN_COMPONENT(path); break;
  234. case k_PHP_URL_QUERY: RETURN_COMPONENT(query); break;
  235. case k_PHP_URL_FRAGMENT: RETURN_COMPONENT(fragment); break;
  236. case k_PHP_URL_PORT:
  237. if (resource.port) {
  238. return resource.port;
  239. }
  240. break;
  241. default:
  242. raise_warning(
  243. "parse_url(): Invalid URL component identifier %" PRId64, component);
  244. return false;
  245. }
  246. return uninit_null();
  247. }
  248. ArrayInit ret(8);
  249. SET_COMPONENT(scheme);
  250. SET_COMPONENT(host);
  251. if (resource.port) {
  252. ret.set(s_port, (int64_t)resource.port);
  253. }
  254. SET_COMPONENT(user);
  255. SET_COMPONENT(pass);
  256. SET_COMPONENT(path);
  257. SET_COMPONENT(query);
  258. SET_COMPONENT(fragment);
  259. return ret.create();
  260. }
  261. String HHVM_FUNCTION(rawurldecode, const String& str) {
  262. return StringUtil::UrlDecode(str, false);
  263. }
  264. String HHVM_FUNCTION(rawurlencode, const String& str) {
  265. return StringUtil::UrlEncode(str, false);
  266. }
  267. String HHVM_FUNCTION(urldecode, const String& str) {
  268. return StringUtil::UrlDecode(str, true);
  269. }
  270. String HHVM_FUNCTION(urlencode, const String& str) {
  271. return StringUtil::UrlEncode(str, true);
  272. }
  273. ///////////////////////////////////////////////////////////////////////////////
  274. const StaticString s_PHP_URL_SCHEME("PHP_URL_SCHEME");
  275. const StaticString s_PHP_URL_HOST("PHP_URL_HOST");
  276. const StaticString s_PHP_URL_PORT("PHP_URL_PORT");
  277. const StaticString s_PHP_URL_USER("PHP_URL_USER");
  278. const StaticString s_PHP_URL_PASS("PHP_URL_PASS");
  279. const StaticString s_PHP_URL_PATH("PHP_URL_PATH");
  280. const StaticString s_PHP_URL_QUERY("PHP_URL_QUERY");
  281. const StaticString s_PHP_URL_FRAGMENT("PHP_URL_FRAGMENT");
  282. const StaticString s_PHP_QUERY_RFC1738("PHP_QUERY_RFC1738");
  283. const StaticString s_PHP_QUERY_RFC3986("PHP_QUERY_RFC3986");
  284. class StandardURLExtension : public Extension {
  285. public:
  286. StandardURLExtension() : Extension("url") {}
  287. virtual void moduleInit() {
  288. Native::registerConstant<KindOfInt64>(
  289. s_PHP_URL_SCHEME.get(), k_PHP_URL_SCHEME
  290. );
  291. Native::registerConstant<KindOfInt64>(
  292. s_PHP_URL_HOST.get(), k_PHP_URL_HOST
  293. );
  294. Native::registerConstant<KindOfInt64>(
  295. s_PHP_URL_PORT.get(), k_PHP_URL_PORT
  296. );
  297. Native::registerConstant<KindOfInt64>(
  298. s_PHP_URL_USER.get(), k_PHP_URL_USER
  299. );
  300. Native::registerConstant<KindOfInt64>(
  301. s_PHP_URL_PASS.get(), k_PHP_URL_PASS
  302. );
  303. Native::registerConstant<KindOfInt64>(
  304. s_PHP_URL_PATH.get(), k_PHP_URL_PATH
  305. );
  306. Native::registerConstant<KindOfInt64>(
  307. s_PHP_URL_QUERY.get(), k_PHP_URL_QUERY
  308. );
  309. Native::registerConstant<KindOfInt64>(
  310. s_PHP_URL_FRAGMENT.get(), k_PHP_URL_FRAGMENT
  311. );
  312. Native::registerConstant<KindOfInt64>(
  313. s_PHP_QUERY_RFC1738.get(), k_PHP_QUERY_RFC1738
  314. );
  315. Native::registerConstant<KindOfInt64>(
  316. s_PHP_QUERY_RFC3986.get(), k_PHP_QUERY_RFC3986
  317. );
  318. HHVM_FE(base64_decode);
  319. HHVM_FE(base64_encode);
  320. HHVM_FE(get_headers);
  321. HHVM_FE(get_meta_tags);
  322. HHVM_FE(http_build_query);
  323. HHVM_FE(parse_url);
  324. HHVM_FE(rawurldecode);
  325. HHVM_FE(rawurlencode);
  326. HHVM_FE(urldecode);
  327. HHVM_FE(urlencode);
  328. loadSystemlib();
  329. }
  330. } s_standardurl_extension;
  331. ///////////////////////////////////////////////////////////////////////////////
  332. }