PageRenderTime 40ms CodeModel.GetById 14ms RepoModel.GetById 0ms app.codeStats 0ms

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

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