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()); } } } }
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("arg_separator.output"); } else { arg_sep = arg_separator; } StringBuffer ret(1024); std::set<void*> seen_arrs; url_encode_array(ret, formdata.toArray(), seen_arrs, numeric_prefix, String(), String(), arg_sep); return String(ret); }
Variant HHVM_FUNCTION(http_build_query, const Variant& formdata, const String& numeric_prefix /* = null_string */, const String& arg_separator /* = null_string */, int enc_type /* = k_PHP_QUERY_RFC1738 */) { if (!formdata.isArray() && !formdata.is(KindOfObject)) { throw_invalid_argument("formdata: (need Array or Object)"); return false; } String arg_sep; if (arg_separator.empty()) { arg_sep = HHVM_FN(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, enc_type != k_PHP_QUERY_RFC3986); return ret.detach(); }
static void url_encode_array(StringBuffer &ret, const Variant& varr, std::set<void*> &seen_arrs, const String& num_prefix, const String& key_prefix, const String& key_suffix, const String& arg_sep, bool encode_plus = true) { void *id = varr.isArray() ? (void*)varr.getArrayData() : (void*)varr.getObjectData(); if (!seen_arrs.insert(id).second) { return; // recursive } // Allow multiple non-recursive references to the same array/object SCOPE_EXIT { seen_arrs.erase(id); }; Array arr; if (varr.is(KindOfObject)) { Object o = varr.toObject(); arr = o->isCollection() ? varr.toArray() : HHVM_FN(get_object_vars(o)); } else { 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.isArray() || data.is(KindOfObject)) { String encoded; if (numeric) { encoded = key; } else { encoded = StringUtil::UrlEncode(key, encode_plus); } StringBuffer new_prefix(key_prefix.size() + num_prefix.size() + encoded.size() + key_suffix.size() + 4); new_prefix.append(key_prefix); if (numeric) new_prefix.append(num_prefix); new_prefix.append(encoded); new_prefix.append(key_suffix); new_prefix.append("%5B"); url_encode_array(ret, data, seen_arrs, String(), new_prefix.detach(), String("%5D", CopyString), arg_sep); } else { if (!ret.empty()) { ret.append(arg_sep); } ret.append(key_prefix); if (numeric) { ret.append(num_prefix); ret.append(key); } else { ret.append(StringUtil::UrlEncode(key, encode_plus)); } ret.append(key_suffix); ret.append("="); if (data.isInteger() || data.is(KindOfBoolean)) { ret.append(String(data.toInt64())); } else if (data.is(KindOfDouble)) { ret.append(String(data.toDouble())); } else { ret.append(StringUtil::UrlEncode(data.toString(), encode_plus)); } } } }
static void url_encode_array(StringBuffer &ret, CVarRef varr, std::set<void*> &seen_arrs, const String& num_prefix, const String& key_prefix, const String& key_suffix, const String& arg_sep) { void *id = varr.is(KindOfArray) ? (void*)varr.getArrayData() : (void*)varr.getObjectData(); if (!seen_arrs.insert(id).second) { return; // recursive } Array arr; if (varr.is(KindOfObject)) { Object o = varr.toObject(); arr = (o.objectForCall()->isCollection()) ? varr.toArray() : f_get_object_vars(o).toArray(); } else { 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.append(key_prefix); if (numeric) new_prefix.append(num_prefix); new_prefix.append(encoded); new_prefix.append(key_suffix); new_prefix.append("%5B"); url_encode_array(ret, data, seen_arrs, String(), new_prefix.detach(), String("%5D", CopyString), arg_sep); } else { if (!ret.empty()) { ret.append(arg_sep); } ret.append(key_prefix); if (numeric) { ret.append(num_prefix); ret.append(key); } else { ret.append(StringUtil::UrlEncode(key)); } ret.append(key_suffix); ret.append("="); if (data.isInteger() || data.is(KindOfBoolean)) { ret.append(String(data.toInt64())); } else if (data.is(KindOfDouble)) { ret.append(String(data.toDouble())); } else { ret.append(StringUtil::UrlEncode(data.toString())); } } } }