/* * For namespaced collections, returns an "alternate" name, which is a * collection name with or without the namespace qualifier, depending on * what's passed. * If no alternate name is found, returns nullptr. */ static const StringData* getAlternateCollectionName(const StringData* clsName) { typedef hphp_hash_map<const StringData*, const StringData*, string_data_hash, string_data_isame> ClsNameMap; auto getAltMap = [] { typedef std::pair<StaticString, StaticString> SStringPair; static ClsNameMap m; static std::vector<SStringPair> mappings { std::make_pair(StaticString("Vector"), StaticString("HH\\Vector")), std::make_pair(StaticString("Map"), StaticString("HH\\Map")), std::make_pair(StaticString("Set"), StaticString("HH\\Set")), std::make_pair(StaticString("Pair"), StaticString("HH\\Pair")) }; for (const auto& p : mappings) { m[p.first.get()] = p.second.get(); m[p.second.get()] = p.first.get(); } // As part of StableMap merging into Map, StableMap is an alias for HH\\Map, // but Map is the sole alias for HH\\Map m[StaticString("StableMap").get()] = StaticString("HH\\Map").get(); return &m; }; static const ClsNameMap* altMap = getAltMap(); auto it = altMap->find(clsName); return it != altMap->end() ? it->second : nullptr; }
void Controller::initializeUnionStation(Client *client, Request *req, RequestAnalysis &analysis) { if (analysis.unionStationSupport) { Options &options = req->options; ServerKit::HeaderTable &headers = req->secureHeaders; const LString *key = headers.lookup("!~UNION_STATION_KEY"); if (key == NULL || key->size == 0) { disconnectWithError(&client, "header !~UNION_STATION_KEY must be set."); return; } key = psg_lstr_make_contiguous(key, req->pool); const LString *filters = headers.lookup("!~UNION_STATION_FILTERS"); if (filters != NULL) { filters = psg_lstr_make_contiguous(filters, req->pool); } options.transaction = unionStationContext->newTransaction( options.getAppGroupName(), "requests", string(key->start->data, key->size), (filters != NULL) ? string(filters->start->data, filters->size) : string()); if (!options.transaction->isNull()) { options.analytics = true; options.unionStationKey = StaticString(key->start->data, key->size); } req->beginStopwatchLog(&req->stopwatchLogs.requestProcessing, "request processing"); req->logMessage(string("Request method: ") + http_method_str(req->method)); req->logMessage("URI: " + StaticString(req->path.start->data, req->path.size)); } }
void PancakeHTTPRewriteRegisterDefaultVariables() { PancakeHTTPRewriteRegisterVariable(StaticString("$HTTPKeepAlive"), PANCAKE_HTTP_REWRITE_BOOL, 0, NULL, PancakeHTTPRewriteGetHTTPKeepAlive, PancakeHTTPRewriteSetHTTPKeepAlive); PancakeHTTPRewriteRegisterVariable(StaticString("$HTTPAnswerCode"), PANCAKE_HTTP_REWRITE_INT, 0, NULL, PancakeHTTPRewriteGetHTTPAnswerCode, PancakeHTTPRewriteSetHTTPAnswerCode); PancakeHTTPRewriteRegisterVariable(StaticString("$HTTPClientContentLength"), PANCAKE_HTTP_REWRITE_INT, PANCAKE_HTTP_REWRITE_READ_ONLY, NULL, PancakeHTTPRewriteGetHTTPClientContentLength, NULL); PancakeHTTPRewriteRegisterVariable(StaticString("$HTTPVersion"), PANCAKE_HTTP_REWRITE_INT, 0, NULL, PancakeHTTPRewriteGetHTTPVersion, PancakeHTTPRewriteSetHTTPVersion); PancakeHTTPRewriteRegisterVariable(StaticString("$HTTPMethod"), PANCAKE_HTTP_REWRITE_STRING, PANCAKE_HTTP_REWRITE_READ_ONLY, NULL, PancakeHTTPRewriteGetHTTPMethod, NULL); PancakeHTTPRewriteRegisterVariable(StaticString("$DocumentURI"), PANCAKE_HTTP_REWRITE_STRING, 0, NULL, PancakeHTTPRewriteGetDocumentURI, PancakeHTTPRewriteSetDocumentURI); PancakeHTTPRewriteRegisterVariable(StaticString("$MIMEType"), PANCAKE_HTTP_REWRITE_STRING, PANCAKE_HTTP_REWRITE_READ_ONLY, NULL, PancakeHTTPRewriteGetMIMEType, NULL); PancakeHTTPRewriteRegisterVariable(StaticString("$HTTPS"), PANCAKE_HTTP_REWRITE_BOOL, PANCAKE_HTTP_REWRITE_READ_ONLY, NULL, PancakeHTTPRewriteGetHTTPS, NULL); PancakeHTTPRewriteRegisterCallback(StaticString("ThrowException"), PancakeHTTPRewriteThrowException); }
void printAppOutput(pid_t pid, const char *channelName, const char *message, unsigned int size) { if (printAppOutputAsDebuggingMessages) { P_DEBUG("App " << pid << " " << channelName << ": " << StaticString(message, size)); } else { char pidStr[sizeof("4294967295")]; unsigned int pidStrLen, channelNameLen, totalLen; try { pidStrLen = integerToOtherBase<pid_t, 10>(pid, pidStr, sizeof(pidStr)); } catch (const std::length_error &) { pidStr[0] = '?'; pidStr[1] = '\0'; pidStrLen = 1; } channelNameLen = strlen(channelName); totalLen = (sizeof("App X Y: \n") - 2) + pidStrLen + channelNameLen + size; if (totalLen < 1024) { char buf[1024]; realPrintAppOutput(buf, sizeof(buf), pidStr, pidStrLen, channelName, channelNameLen, message, size); } else { DynamicBuffer buf(totalLen); realPrintAppOutput(buf.data, totalLen, pidStr, pidStrLen, channelName, channelNameLen, message, size); } } }
void _prepareLogEntry(FastStringStream<> &sstream, const char *file, unsigned int line) { struct tm the_tm; char datetime_buf[32]; int datetime_size; struct timeval tv; gettimeofday(&tv, NULL); localtime_r(&tv.tv_sec, &the_tm); datetime_size = snprintf(datetime_buf, sizeof(datetime_buf), "%d-%02d-%02d %02d:%02d:%02d.%04llu", the_tm.tm_year + 1900, the_tm.tm_mon + 1, the_tm.tm_mday, the_tm.tm_hour, the_tm.tm_min, the_tm.tm_sec, (unsigned long long) tv.tv_usec / 100); sstream << "[ " << StaticString(datetime_buf, datetime_size) << " " << std::dec << getpid() << "/" << std::hex << pthread_self() << std::dec << " "; if (startsWith(file, P_STATIC_STRING("ext/"))) { // special reduncancy filter because most code resides in these paths file += sizeof("ext/") - 1; if (startsWith(file, P_STATIC_STRING("common/"))) { file += sizeof("common/") - 1; } } if (TRUNCATE_LOGPATHS_TO_MAXCHARS > 0) { truncateBeforeTokens(file, P_STATIC_STRING("/\\"), TRUNCATE_LOGPATHS_TO_MAXCHARS, sstream); } else { sstream << file; } sstream << ":" << line << " ]: "; }
void Client::onAppInputChunk(const char *data, size_t size, void *userData) { Client *client = (Client *) userData; assert(client != NULL); assert(client->requestHandler != NULL); client->requestHandler->onAppInputChunk(client->shared_from_this(), StaticString(data, size)); }
Value ValueIteratorBase::key() const { const Value::CZString czstring = (*current_).first; if (czstring.data()) { if (czstring.isStaticString()) return Value(StaticString(czstring.data())); return Value(czstring.data(), czstring.data() + czstring.length()); } return Value(czstring.index()); }
void Controller::fillPoolOptionSecToMsec(Request *req, unsigned int &field, const HashedStaticString &name) { const LString *value = req->secureHeaders.lookup(name); if (value != NULL && value->size > 0) { value = psg_lstr_make_contiguous(value, req->pool); field = stringToInt(StaticString(value->start->data, value->size)) * 1000; } }
void parseTcpSocketAddress(const StaticString &address, string &host, unsigned short &port) { if (getSocketAddressType(address) != SAT_TCP) { throw ArgumentException("Not a valid TCP socket address"); } StaticString hostAndPort(address.data() + sizeof("tcp://") - 1, address.size() - sizeof("tcp://") + 1); if (hostAndPort.empty()) { throw ArgumentException("Not a valid TCP socket address"); } if (hostAndPort[0] == '[') { // IPv6 address, e.g.: // [::1]:3000 const char *hostEnd = (const char *) memchr(hostAndPort.data(), ']', hostAndPort.size()); if (hostEnd == NULL || hostAndPort.size() <= string::size_type(hostEnd - hostAndPort.data()) + 3) { throw ArgumentException("Not a valid TCP socket address"); } const char *sep = hostEnd + 1; host.assign(hostAndPort.data() + 1, hostEnd - hostAndPort.data() - 1); port = stringToUint(StaticString( sep + 1, hostAndPort.data() + hostAndPort.size() - sep - 1 )); } else { // IPv4 address, e.g.: // 127.0.0.1:3000 const char *sep = (const char *) memchr(hostAndPort.data(), ':', hostAndPort.size()); if (sep == NULL || hostAndPort.size() <= string::size_type(sep - hostAndPort.data()) + 2) { throw ArgumentException("Not a valid TCP socket address"); } host.assign(hostAndPort.data(), sep - hostAndPort.data()); port = stringToUint(StaticString( sep + 1, hostAndPort.data() + hostAndPort.size() - sep - 1 )); } }
void Controller::fillPoolOption(Request *req, StaticString &field, const HashedStaticString &name) { const LString *value = req->secureHeaders.lookup(name); if (value != NULL && value->size > 0) { value = psg_lstr_make_contiguous(value, req->pool); field = StaticString(value->start->data, value->size); } }
static void HHVM_METHOD(UVUdp, __construct, const Variant &v_loop) { if(v_loop.isNull()){ initUVUdpObject(this_, uv_default_loop()); return; } Object loop = v_loop.toObject(); checkUVLoopInstance(loop, 1, s_uvudp, StaticString("__construct")); auto* loop_data = Native::data<UVLoopData>(loop.get()); SET_LOOP(this_, loop, s_uvudp); initUVUdpObject(this_, loop_data->loop); }
static bool HHVM_STATIC_METHOD(EventUtil, setSocketOption, const Resource &socket, int64_t level, int64_t optname, const Variant &optval) { evutil_socket_t fd = resource_to_fd(socket); struct linger lv; struct timeval tv; void *opt_ptr; int optlen; int ov; if(fd == -1){ return false; } switch(optname){ case SO_LINGER:{ const Array optval_a = optval.toCArrRef(); lv.l_onoff = (unsigned short) optval_a[StaticString("l_onoff")].toInt64Val(); lv.l_linger = (unsigned short) optval_a[StaticString("l_linger")].toInt64Val(); optlen = sizeof(lv); opt_ptr = &lv; break; } case SO_RCVTIMEO: case SO_SNDTIMEO: { const Array optval_a = optval.toCArrRef(); tv.tv_sec = optval_a[StaticString("sec")].toInt64Val(); tv.tv_usec = optval_a[StaticString("usec")].toInt64Val(); optlen = sizeof(tv); opt_ptr = &tv; break; } default: { ov = optval.toInt64Val(); optlen = sizeof(ov); opt_ptr = &ov; break; } } return setsockopt(fd, level, optname, opt_ptr, optlen) == 0; }
void PipeWatcher::threadMain() { TRACE_POINT(); { boost::unique_lock<boost::mutex> lock(startSyncher); while (!started) { startCond.wait(lock); } } UPDATE_TRACE_POINT(); while (!this_thread::interruption_requested()) { char buf[1024 * 8]; ssize_t ret; UPDATE_TRACE_POINT(); ret = syscalls::read(fd, buf, sizeof(buf)); if (ret == 0) { break; } else if (ret == -1) { UPDATE_TRACE_POINT(); if (errno == ECONNRESET) { break; } else if (errno != EAGAIN) { int e = errno; P_WARN("Cannot read from process " << pid << " " << name << ": " << strerror(e) << " (errno=" << e << ")"); break; } } else if (ret == 1 && buf[0] == '\n') { UPDATE_TRACE_POINT(); printAppOutput(pid, name, "", 0); } else { UPDATE_TRACE_POINT(); vector<StaticString> lines; ssize_t ret2 = ret; if (ret2 > 0 && buf[ret2 - 1] == '\n') { ret2--; } split(StaticString(buf, ret2), '\n', lines); foreach (const StaticString line, lines) { printAppOutput(pid, name, line.data(), line.size()); } } if (onData != NULL) { onData(buf, ret); } }
string cEscapeString(const StaticString &input) { string result; const char *current = input.c_str(); const char *end = current + input.size(); result.reserve(input.size()); while (current < end) { char c = *current; if (c >= 32 && c <= 126) { // Printable ASCII. result.append(1, c); } else { char buf[sizeof("\\xFF")]; switch (c) { case '\0': // Explicitly in hex format in order to avoid confusion // with any '0' characters that come after this byte. result.append("\\x00"); break; case '\t': result.append("\\t"); break; case '\n': result.append("\\n"); break; case '\r': result.append("\\r"); break; case '\e': result.append("\\e"); break; default: buf[0] = '\\'; buf[1] = 'x'; toHex(StaticString(current, 1), buf + 2, true); buf[4] = '\0'; result.append(buf, sizeof(buf) - 1); break; } } current++; } return result; }
void StringUtil::InitLiteralStrings(StaticString literalStrings[], int nliteralStrings, const char *literalStringBuf, int literalStringBufSize, const char *literalStringLen, int literalStringLenSize) { int bufSize = literalStringBufSize; int lenSize = literalStringLenSize; static char *uncompressedBuf; // permanently allocated char *uncompressedLen; if (uncompressedBuf) { throw Exception("StringUtil::InitLiteralStrings called twice"); } uncompressedBuf = gzdecode(literalStringBuf, bufSize); if (uncompressedBuf == NULL) { throw Exception("Bad literalStringBuf %p", literalStringBuf); } uncompressedLen = gzdecode(literalStringLen, lenSize); if (uncompressedLen == NULL) { throw Exception("Bad literalStringLen %p", literalStringLen); } const char *pb = uncompressedBuf; const char *pl = uncompressedLen; const char *endBuf = pb + bufSize; const char *endLen = pl + lenSize; for (int i = 0; i < nliteralStrings; i++) { int size; memcpy(&size, pl, sizeof(size)); literalStrings[i] = StaticString(pb, size); pb += size; ASSERT(*pb == '\0'); pb++; pl += sizeof(size); } if (pb != endBuf) { throw Exception("Bad literalStringBuf %p", literalStringBuf); } if (pl != endLen) { throw Exception("Bad literalStringLen %p", literalStringLen); } free(uncompressedLen); }
static void HHVM_METHOD(UVIdle, __construct, const Variant &v_loop) { auto* data = Native::data<UVNativeData>(this_); data->resource_handle = (void *) new uv_idle_ext_t(); uv_idle_ext_t *idle_handle = fetchResource(data); idle_handle->start = false; idle_handle->idle_object_data = NULL; if(v_loop.isNull()){ uv_idle_init(uv_default_loop(), idle_handle); return; } Object loop = v_loop.toObject(); checkUVLoopInstance(loop, 1, s_uvidle, StaticString("__construct")); auto* loop_data = Native::data<UVLoopData>(loop.get()); SET_LOOP(this_, loop, s_uvidle); uv_idle_init(loop_data->loop, idle_handle); }
inline static void cnsStr(const StaticString & name, const char * value) { Native::registerConstant<KindOfStaticString>( name.get(), StaticString(value).get()); }
namespace HPHP { /////////////////////////////////////////////////////////////////////////////// const int64_t k_INPUT_POST = 0; const int64_t k_INPUT_GET = 1; const int64_t k_INPUT_COOKIE = 2; const int64_t k_INPUT_ENV = 4; const int64_t k_INPUT_SERVER = 5; const int64_t k_INPUT_SESSION = 6; const int64_t k_INPUT_REQUEST = 99; const int64_t k_FILTER_FLAG_NONE = 0; const int64_t k_FILTER_REQUIRE_SCALAR = 33554432; const int64_t k_FILTER_REQUIRE_ARRAY = 16777216; const int64_t k_FILTER_FORCE_ARRAY = 67108864; const int64_t k_FILTER_NULL_ON_FAILURE = 134217728; const int64_t k_FILTER_VALIDATE_INT = 257; const int64_t k_FILTER_VALIDATE_BOOLEAN = 258; const int64_t k_FILTER_VALIDATE_FLOAT = 259; const int64_t k_FILTER_VALIDATE_REGEXP = 272; const int64_t k_FILTER_VALIDATE_URL = 273; const int64_t k_FILTER_VALIDATE_EMAIL = 274; const int64_t k_FILTER_VALIDATE_IP = 275; const int64_t k_FILTER_VALIDATE_MAC = 276; const int64_t k_FILTER_DEFAULT = 516; const int64_t k_FILTER_UNSAFE_RAW = 516; const int64_t k_FILTER_SANITIZE_STRING = 513; const int64_t k_FILTER_SANITIZE_STRIPPED = 513; const int64_t k_FILTER_SANITIZE_ENCODED = 514; const int64_t k_FILTER_SANITIZE_SPECIAL_CHARS = 515; const int64_t k_FILTER_SANITIZE_FULL_SPECIAL_CHARS = 515; const int64_t k_FILTER_SANITIZE_EMAIL = 517; const int64_t k_FILTER_SANITIZE_URL = 518; const int64_t k_FILTER_SANITIZE_NUMBER_INT = 519; const int64_t k_FILTER_SANITIZE_NUMBER_FLOAT = 520; const int64_t k_FILTER_SANITIZE_MAGIC_QUOTES = 521; const int64_t k_FILTER_CALLBACK = 1024; const int64_t k_FILTER_FLAG_ALLOW_OCTAL = 1; const int64_t k_FILTER_FLAG_ALLOW_HEX = 2; const int64_t k_FILTER_FLAG_STRIP_LOW = 4; const int64_t k_FILTER_FLAG_STRIP_HIGH = 8; const int64_t k_FILTER_FLAG_ENCODE_LOW = 16; const int64_t k_FILTER_FLAG_ENCODE_HIGH = 32; const int64_t k_FILTER_FLAG_ENCODE_AMP = 64; const int64_t k_FILTER_FLAG_NO_ENCODE_QUOTES = 128; const int64_t k_FILTER_FLAG_EMPTY_STRING_NULL = 256; const int64_t k_FILTER_FLAG_STRIP_BACKTICK = 512; const int64_t k_FILTER_FLAG_ALLOW_FRACTION = 4096; const int64_t k_FILTER_FLAG_ALLOW_THOUSAND = 8192; const int64_t k_FILTER_FLAG_ALLOW_SCIENTIFIC = 16384; const int64_t k_FILTER_FLAG_SCHEME_REQUIRED = 65536; const int64_t k_FILTER_FLAG_HOST_REQUIRED = 131072; const int64_t k_FILTER_FLAG_PATH_REQUIRED = 262144; const int64_t k_FILTER_FLAG_QUERY_REQUIRED = 524288; const int64_t k_FILTER_FLAG_IPV4 = 1048576; const int64_t k_FILTER_FLAG_IPV6 = 2097152; const int64_t k_FILTER_FLAG_NO_RES_RANGE = 4194304; const int64_t k_FILTER_FLAG_NO_PRIV_RANGE = 8388608; const StaticString s_GET("_GET"), s_POST("_POST"), s_COOKIE("_COOKIE"), s_SERVER("_SERVER"), s_ENV("_ENV"); struct FilterRequestData final : RequestEventHandler { void requestInit() override { // This doesn't copy them yet, but will do COW if they are modified m_GET = php_global(s_GET).toArray(); m_POST = php_global(s_POST).toArray(); m_COOKIE = php_global(s_COOKIE).toArray(); m_SERVER = php_global(s_SERVER).toArray(); m_ENV = php_global(s_ENV).toArray(); } void requestShutdown() override { m_GET = nullptr; m_POST = nullptr; m_COOKIE = nullptr; m_SERVER = nullptr; m_ENV = nullptr; } Array getVar(int64_t type) { switch (type) { case k_INPUT_GET: return m_GET; case k_INPUT_POST: return m_POST; case k_INPUT_COOKIE: return m_COOKIE; case k_INPUT_SERVER: return m_SERVER; case k_INPUT_ENV: return m_ENV; } return empty_array(); } private: Array m_GET; Array m_POST; Array m_COOKIE; Array m_SERVER; Array m_ENV; }; IMPLEMENT_STATIC_REQUEST_LOCAL(FilterRequestData, s_filter_request_data); static class FilterExtension : public Extension { public: FilterExtension() : Extension("filter", "0.11.0") {} virtual void moduleLoad(const IniSetting::Map& ini, Hdf config) { HHVM_FE(__SystemLib_filter_input_get_var); HHVM_FE(_filter_snapshot_globals); } virtual void requestInit() { // warm up the s_filter_request_data s_filter_request_data->requestInit(); } } s_filter_extension; /////////////////////////////////////////////////////////////////////////////// typedef struct filter_list_entry { StaticString name; int64_t id; Variant (*function)(PHP_INPUT_FILTER_PARAM_DECL); } filter_list_entry; static const filter_list_entry filter_list[] = { { StaticString("int"), k_FILTER_VALIDATE_INT, php_filter_int }, { StaticString("boolean"), k_FILTER_VALIDATE_BOOLEAN, php_filter_boolean }, { StaticString("float"), k_FILTER_VALIDATE_FLOAT, php_filter_float }, { StaticString("validate_regexp"), k_FILTER_VALIDATE_REGEXP, php_filter_validate_regexp }, { StaticString("validate_url"), k_FILTER_VALIDATE_URL, php_filter_validate_url }, { StaticString("validate_email"), k_FILTER_VALIDATE_EMAIL, php_filter_validate_email }, { StaticString("validate_ip"), k_FILTER_VALIDATE_IP, php_filter_validate_ip }, { StaticString("validate_mac"), k_FILTER_VALIDATE_MAC, php_filter_validate_mac }, { StaticString("string"), k_FILTER_SANITIZE_STRING, php_filter_string }, { StaticString("stripped"), k_FILTER_SANITIZE_STRING, php_filter_string }, { StaticString("encoded"), k_FILTER_SANITIZE_ENCODED, php_filter_encoded }, { StaticString("special_chars"), k_FILTER_SANITIZE_SPECIAL_CHARS, php_filter_special_chars }, { StaticString("full_special_chars"), k_FILTER_SANITIZE_FULL_SPECIAL_CHARS, php_filter_full_special_chars }, { StaticString("unsafe_raw"), k_FILTER_UNSAFE_RAW, php_filter_unsafe_raw }, { StaticString("email"), k_FILTER_SANITIZE_EMAIL, php_filter_email }, { StaticString("url"), k_FILTER_SANITIZE_URL, php_filter_url }, { StaticString("number_int"), k_FILTER_SANITIZE_NUMBER_INT, php_filter_number_int }, { StaticString("number_float"), k_FILTER_SANITIZE_NUMBER_FLOAT, php_filter_number_float }, { StaticString("magic_quotes"), k_FILTER_SANITIZE_MAGIC_QUOTES, php_filter_magic_quotes }, { StaticString("callback"), k_FILTER_CALLBACK, php_filter_callback }, }; const StaticString s_flags("flags"), s_default("default"), s_options("options"); static Variant fail(bool return_null, const Variant& options) { if (options.isArray()) { const Array& arr(options.toArray()); if (arr.exists(s_default)) { return arr[s_default]; } } if (return_null) { return init_null(); } return false; } static const filter_list_entry* php_find_filter(uint64_t id) { int i, size = sizeof(filter_list) / sizeof(filter_list_entry); for (i = 0; i < size; ++i) { if (filter_list[i].id == id) { return &filter_list[i]; } } return nullptr; } #define FAIL_IF(x) do { if (x) return false; } while (0) static bool filter_var(Variant& ret, const Variant& variable, int64_t filter, const Variant& options) { const filter_list_entry* filter_func = php_find_filter(filter); if (!filter_func) { return false; } int64_t flags; Variant option_array; if (options.isArray()) { auto arr = options.toArray(); flags = arr[s_flags].toInt64(); option_array = arr[s_options]; } else { flags = options.toInt64(); } FAIL_IF(variable.isObject() && !variable.getObjectData()->hasToString()); ret = filter_func->function(variable.toString(), flags, option_array); if (option_array.isArray() && option_array.toArray().exists(s_default) && ((flags & k_FILTER_NULL_ON_FAILURE && ret.isNull()) || (!(flags & k_FILTER_NULL_ON_FAILURE) && ret.isBoolean() && ret.asBooleanVal() == 0))) { ret = option_array.toArray()[s_default]; } return true; } static bool filter_recursive(Variant& ret, const Variant& variable, int64_t filter, const Variant& options) { Array arr; for (ArrayIter iter(variable.toArray()); iter; ++iter) { Variant v; if (iter.second().isArray()) { FAIL_IF(!filter_recursive(v, iter.second().toArray(), filter, options)); } else { FAIL_IF(!filter_var(v, iter.second(), filter, options)); } arr.add(iter.first(), v); } ret = arr; return true; } #undef FAIL_IF /////////////////////////////////////////////////////////////////////////////// Variant f_filter_list() { size_t size = sizeof(filter_list) / sizeof(filter_list_entry); Array ret; for (size_t i = 0; i < size; ++i) { ret.append(filter_list[i].name); } return ret; } Variant f_filter_id(const String& filtername) { size_t size = sizeof(filter_list) / sizeof(filter_list_entry); for (size_t i = 0; i < size; ++i) { if (filter_list[i].name == filtername) { return filter_list[i].id; } } return false; } #define FAIL_IF(x) \ do { \ if (x) return fail(filter_flags & k_FILTER_NULL_ON_FAILURE, options); \ } while(0) Variant f_filter_var(const Variant& variable, int64_t filter /* = 516 */, const Variant& options /* = empty_array_ref */) { int64_t filter_flags; if (options.isArray()) { filter_flags = options.toCArrRef()[s_flags].toInt64(); } else { filter_flags = options.toInt64(); } if (!(filter_flags & k_FILTER_REQUIRE_ARRAY || filter_flags & k_FILTER_FORCE_ARRAY)) { filter_flags |= k_FILTER_REQUIRE_SCALAR; } // No idea why, but zend does this.. if (filter == k_FILTER_CALLBACK) { filter_flags = 0; } if (variable.isArray()) { FAIL_IF(filter_flags & k_FILTER_REQUIRE_SCALAR); Variant ret; FAIL_IF(!filter_recursive(ret, variable, filter, options)); return ret; } FAIL_IF(filter_flags & k_FILTER_REQUIRE_ARRAY); Variant ret; FAIL_IF(!filter_var(ret, variable, filter, options)); if (filter_flags & k_FILTER_FORCE_ARRAY && !ret.isArray()) { ret = make_packed_array(ret); } return ret; } #undef FAIL_IF Array HHVM_FUNCTION(__SystemLib_filter_input_get_var, int64_t variable_name) { return s_filter_request_data->getVar(variable_name); } void HHVM_FUNCTION(_filter_snapshot_globals) { s_filter_request_data->requestInit(); } /////////////////////////////////////////////////////////////////////////////// }
StaticString makeStaticStringWithNull(const string &data) { return StaticString(data.c_str(), data.size() + 1); }
StaticString makeStaticStringWithNull(const char *data) { return StaticString(data, strlen(data) + 1); }
unsigned int Controller::determineHeaderSizeForSessionProtocol(Request *req, SessionProtocolWorkingState &state, string delta_monotonic) { unsigned int dataSize = sizeof(boost::uint32_t); state.path = req->getPathWithoutQueryString(); state.hasBaseURI = req->options.baseURI != P_STATIC_STRING("/") && startsWith(state.path, req->options.baseURI); if (state.hasBaseURI) { state.path = state.path.substr(req->options.baseURI.size()); if (state.path.empty()) { state.path = P_STATIC_STRING("/"); } } state.queryString = req->getQueryString(); state.methodStr = StaticString(http_method_str(req->method)); state.remoteAddr = req->secureHeaders.lookup(REMOTE_ADDR); state.remotePort = req->secureHeaders.lookup(REMOTE_PORT); state.remoteUser = req->secureHeaders.lookup(REMOTE_USER); state.contentType = req->headers.lookup(HTTP_CONTENT_TYPE); if (req->hasBody()) { state.contentLength = req->headers.lookup(HTTP_CONTENT_LENGTH); } else { state.contentLength = NULL; } if (req->envvars != NULL) { size_t len = modp_b64_decode_len(req->envvars->size); state.environmentVariablesData = (char *) malloc(len); if (state.environmentVariablesData == NULL) { throw RuntimeException("Unable to allocate memory for base64 " "decoding of environment variables"); } len = modp_b64_decode(state.environmentVariablesData, req->envvars->start->data, req->envvars->size); if (len == (size_t) -1) { throw RuntimeException("Unable to base64 decode environment variables"); } state.environmentVariablesSize = len; } dataSize += sizeof("REQUEST_URI"); dataSize += req->path.size + 1; dataSize += sizeof("PATH_INFO"); dataSize += state.path.size() + 1; dataSize += sizeof("SCRIPT_NAME"); if (state.hasBaseURI) { dataSize += req->options.baseURI.size(); } else { dataSize += sizeof(""); } dataSize += sizeof("QUERY_STRING"); dataSize += state.queryString.size() + 1; dataSize += sizeof("REQUEST_METHOD"); dataSize += state.methodStr.size() + 1; if (req->host != NULL && req->host->size > 0) { const LString *host = psg_lstr_make_contiguous(req->host, req->pool); const char *sep = (const char *) memchr(host->start->data, ':', host->size); if (sep != NULL) { state.serverName = StaticString(host->start->data, sep - host->start->data); state.serverPort = StaticString(sep + 1, host->start->data + host->size - sep - 1); } else { state.serverName = StaticString(host->start->data, host->size); if (req->https) { state.serverPort = P_STATIC_STRING("443"); } else { state.serverPort = P_STATIC_STRING("80"); } } } else { state.serverName = defaultServerName; state.serverPort = defaultServerPort; } dataSize += sizeof("SERVER_NAME"); dataSize += state.serverName.size() + 1; dataSize += sizeof("SERVER_PORT"); dataSize += state.serverPort.size() + 1; dataSize += sizeof("SERVER_SOFTWARE"); dataSize += serverSoftware.size() + 1; dataSize += sizeof("SERVER_PROTOCOL"); dataSize += sizeof("HTTP/1.1"); dataSize += sizeof("REMOTE_ADDR"); if (state.remoteAddr != NULL) { dataSize += state.remoteAddr->size + 1; } else { dataSize += sizeof("127.0.0.1"); } dataSize += sizeof("REMOTE_PORT"); if (state.remotePort != NULL) { dataSize += state.remotePort->size + 1; } else { dataSize += sizeof("0"); } if (state.remoteUser != NULL) { dataSize += sizeof("REMOTE_USER"); dataSize += state.remoteUser->size + 1; } if (state.contentType != NULL) { dataSize += sizeof("CONTENT_TYPE"); dataSize += state.contentType->size + 1; } if (state.contentLength != NULL) { dataSize += sizeof("CONTENT_LENGTH"); dataSize += state.contentLength->size + 1; } dataSize += sizeof("PASSENGER_CONNECT_PASSWORD"); dataSize += ApplicationPool2::ApiKey::SIZE + 1; if (req->https) { dataSize += sizeof("HTTPS"); dataSize += sizeof("on"); } if (req->options.analytics) { dataSize += sizeof("PASSENGER_TXN_ID"); dataSize += req->options.transaction->getTxnId().size() + 1; dataSize += sizeof("PASSENGER_DELTA_MONOTONIC"); dataSize += delta_monotonic.size() + 1; } if (req->upgraded()) { dataSize += sizeof("HTTP_CONNECTION"); dataSize += sizeof("upgrade"); } ServerKit::HeaderTable::Iterator it(req->headers); while (*it != NULL) { dataSize += sizeof("HTTP_") - 1 + it->header->key.size + 1; dataSize += it->header->val.size + 1; it.next(); } if (state.environmentVariablesData != NULL) { dataSize += state.environmentVariablesSize; } return dataSize + 1; }
void moduleInit() override { Native::registerConstant<KindOfStaticString>( s_MCRYPT_3DES.get(), StaticString("tripledes").get() ); Native::registerConstant<KindOfStaticString>( s_MCRYPT_ARCFOUR.get(), StaticString("arcfour").get() ); Native::registerConstant<KindOfStaticString>( s_MCRYPT_ARCFOUR_IV.get(), StaticString("arcfour-iv").get() ); Native::registerConstant<KindOfStaticString>( s_MCRYPT_BLOWFISH.get(), StaticString("blowfish").get() ); Native::registerConstant<KindOfStaticString>( s_MCRYPT_BLOWFISH_COMPAT.get(), StaticString("blowfish-compat").get() ); Native::registerConstant<KindOfStaticString>( s_MCRYPT_CAST_128.get(), StaticString("cast-128").get() ); Native::registerConstant<KindOfStaticString>( s_MCRYPT_CAST_256.get(), StaticString("cast-256").get() ); Native::registerConstant<KindOfStaticString>( s_MCRYPT_CRYPT.get(), StaticString("crypt").get() ); Native::registerConstant<KindOfInt64>( s_MCRYPT_DECRYPT.get(), 1 ); Native::registerConstant<KindOfStaticString>( s_MCRYPT_DES.get(), StaticString("des").get() ); Native::registerConstant<KindOfInt64>( s_MCRYPT_DEV_RANDOM.get(), RANDOM ); Native::registerConstant<KindOfInt64>( s_MCRYPT_DEV_URANDOM.get(), URANDOM ); Native::registerConstant<KindOfInt64>( s_MCRYPT_ENCRYPT.get(), 0 ); Native::registerConstant<KindOfStaticString>( s_MCRYPT_ENIGNA.get(), StaticString("crypt").get() ); Native::registerConstant<KindOfStaticString>( s_MCRYPT_GOST.get(), StaticString("gost").get() ); Native::registerConstant<KindOfStaticString>( s_MCRYPT_IDEA.get(), StaticString("idea").get() ); Native::registerConstant<KindOfStaticString>( s_MCRYPT_LOKI97.get(), StaticString("loki97").get() ); Native::registerConstant<KindOfStaticString>( s_MCRYPT_MARS.get(), StaticString("mars").get() ); Native::registerConstant<KindOfStaticString>( s_MCRYPT_MODE_CBC.get(), StaticString("cbc").get() ); Native::registerConstant<KindOfStaticString>( s_MCRYPT_MODE_CFB.get(), StaticString("cfb").get() ); Native::registerConstant<KindOfStaticString>( s_MCRYPT_MODE_ECB.get(), StaticString("ecb").get() ); Native::registerConstant<KindOfStaticString>( s_MCRYPT_MODE_NOFB.get(), StaticString("nofb").get() ); Native::registerConstant<KindOfStaticString>( s_MCRYPT_MODE_OFB.get(), StaticString("ofb").get() ); Native::registerConstant<KindOfStaticString>( s_MCRYPT_MODE_STREAM.get(), StaticString("stream").get() ); Native::registerConstant<KindOfStaticString>( s_MCRYPT_PANAMA.get(), StaticString("panama").get() ); Native::registerConstant<KindOfInt64>( s_MCRYPT_RAND.get(), RAND ); Native::registerConstant<KindOfStaticString>( s_MCRYPT_RC2.get(), StaticString("rc2").get() ); Native::registerConstant<KindOfStaticString>( s_MCRYPT_RC6.get(), StaticString("rc6").get() ); Native::registerConstant<KindOfStaticString>( s_MCRYPT_RIJNDAEL_128.get(), StaticString("rijndael-128").get() ); Native::registerConstant<KindOfStaticString>( s_MCRYPT_RIJNDAEL_192.get(), StaticString("rijndael-192").get() ); Native::registerConstant<KindOfStaticString>( s_MCRYPT_RIJNDAEL_256.get(), StaticString("rijndael-256").get() ); Native::registerConstant<KindOfStaticString>( s_MCRYPT_SAFER128.get(), StaticString("safer-sk128").get() ); Native::registerConstant<KindOfStaticString>( s_MCRYPT_SAFER64.get(), StaticString("safer-sk64").get() ); Native::registerConstant<KindOfStaticString>( s_MCRYPT_SAFERPLUS.get(), StaticString("saferplus").get() ); Native::registerConstant<KindOfStaticString>( s_MCRYPT_SERPENT.get(), StaticString("serpent").get() ); Native::registerConstant<KindOfStaticString>( s_MCRYPT_SKIPJACK.get(), StaticString("skipjack").get() ); Native::registerConstant<KindOfStaticString>( s_MCRYPT_THREEWAY.get(), StaticString("threeway").get() ); Native::registerConstant<KindOfStaticString>( s_MCRYPT_TRIPLEDES.get(), StaticString("tripledes").get() ); Native::registerConstant<KindOfStaticString>( s_MCRYPT_TWOFISH.get(), StaticString("twofish").get() ); Native::registerConstant<KindOfStaticString>( s_MCRYPT_WAKE.get(), StaticString("wake").get() ); Native::registerConstant<KindOfStaticString>( s_MCRYPT_XTEA.get(), StaticString("xtea").get() ); HHVM_FE(mcrypt_module_open); HHVM_FE(mcrypt_module_close); HHVM_FE(mcrypt_list_algorithms); HHVM_FE(mcrypt_list_modes); HHVM_FE(mcrypt_module_get_algo_block_size); HHVM_FE(mcrypt_module_get_algo_key_size); HHVM_FE(mcrypt_module_get_supported_key_sizes); HHVM_FE(mcrypt_module_is_block_algorithm_mode); HHVM_FE(mcrypt_module_is_block_algorithm); HHVM_FE(mcrypt_module_is_block_mode); HHVM_FE(mcrypt_module_self_test); HHVM_FE(mcrypt_create_iv); HHVM_FE(mcrypt_encrypt); HHVM_FE(mcrypt_decrypt); HHVM_FE(mcrypt_cbc); HHVM_FE(mcrypt_cfb); HHVM_FE(mcrypt_ecb); HHVM_FE(mcrypt_ofb); HHVM_FE(mcrypt_get_block_size); HHVM_FE(mcrypt_get_cipher_name); HHVM_FE(mcrypt_get_iv_size); HHVM_FE(mcrypt_get_key_size); HHVM_FE(mcrypt_enc_get_algorithms_name); HHVM_FE(mcrypt_enc_get_block_size); HHVM_FE(mcrypt_enc_get_iv_size); HHVM_FE(mcrypt_enc_get_key_size); HHVM_FE(mcrypt_enc_get_modes_name); HHVM_FE(mcrypt_enc_get_supported_key_sizes); HHVM_FE(mcrypt_enc_is_block_algorithm_mode); HHVM_FE(mcrypt_enc_is_block_algorithm); HHVM_FE(mcrypt_enc_is_block_mode); HHVM_FE(mcrypt_enc_self_test); HHVM_FE(mcrypt_generic_init); HHVM_FE(mcrypt_generic); HHVM_FE(mdecrypt_generic); HHVM_FE(mcrypt_generic_deinit); HHVM_FE(mcrypt_generic_end); loadSystemlib(); }
void Controller::createNewPoolOptions(Client *client, Request *req, const HashedStaticString &appGroupName) { ServerKit::HeaderTable &secureHeaders = req->secureHeaders; Options &options = req->options; SKC_TRACE(client, 2, "Creating new pool options: app group name=" << appGroupName); options = Options(); const LString *scriptName = secureHeaders.lookup("!~SCRIPT_NAME"); const LString *appRoot = secureHeaders.lookup("!~PASSENGER_APP_ROOT"); if (scriptName == NULL || scriptName->size == 0) { if (appRoot == NULL || appRoot->size == 0) { const LString *documentRoot = secureHeaders.lookup("!~DOCUMENT_ROOT"); if (OXT_UNLIKELY(documentRoot == NULL || documentRoot->size == 0)) { disconnectWithError(&client, "client did not send a !~PASSENGER_APP_ROOT or a !~DOCUMENT_ROOT header"); return; } documentRoot = psg_lstr_make_contiguous(documentRoot, req->pool); appRoot = psg_lstr_create(req->pool, extractDirNameStatic(StaticString(documentRoot->start->data, documentRoot->size))); } else { appRoot = psg_lstr_make_contiguous(appRoot, req->pool); } options.appRoot = HashedStaticString(appRoot->start->data, appRoot->size); } else { if (appRoot == NULL || appRoot->size == 0) { const LString *documentRoot = secureHeaders.lookup("!~DOCUMENT_ROOT"); if (OXT_UNLIKELY(documentRoot == NULL || documentRoot->size == 0)) { disconnectWithError(&client, "client did not send a !~DOCUMENT_ROOT header"); return; } documentRoot = psg_lstr_null_terminate(documentRoot, req->pool); documentRoot = resolveSymlink(StaticString(documentRoot->start->data, documentRoot->size), req->pool); appRoot = psg_lstr_create(req->pool, extractDirNameStatic(StaticString(documentRoot->start->data, documentRoot->size))); } else { appRoot = psg_lstr_make_contiguous(appRoot, req->pool); } options.appRoot = HashedStaticString(appRoot->start->data, appRoot->size); scriptName = psg_lstr_make_contiguous(scriptName, req->pool); options.baseURI = StaticString(scriptName->start->data, scriptName->size); } fillPoolOptionsFromConfigCaches(options, req->pool, req->config); const LString *appType = secureHeaders.lookup("!~PASSENGER_APP_TYPE"); if (appType == NULL || appType->size == 0) { AppTypeDetector detector; PassengerAppType type = detector.checkAppRoot(options.appRoot); if (type == PAT_NONE || type == PAT_ERROR) { disconnectWithError(&client, "client did not send a recognized !~PASSENGER_APP_TYPE header"); return; } options.appType = getAppTypeName(type); } else { fillPoolOption(req, options.appType, "!~PASSENGER_APP_TYPE"); } options.appGroupName = appGroupName; fillPoolOption(req, options.appType, "!~PASSENGER_APP_TYPE"); fillPoolOption(req, options.environment, "!~PASSENGER_APP_ENV"); fillPoolOption(req, options.ruby, "!~PASSENGER_RUBY"); fillPoolOption(req, options.python, "!~PASSENGER_PYTHON"); fillPoolOption(req, options.nodejs, "!~PASSENGER_NODEJS"); fillPoolOption(req, options.meteorAppSettings, "!~PASSENGER_METEOR_APP_SETTINGS"); fillPoolOption(req, options.user, "!~PASSENGER_USER"); fillPoolOption(req, options.group, "!~PASSENGER_GROUP"); fillPoolOption(req, options.minProcesses, "!~PASSENGER_MIN_PROCESSES"); fillPoolOption(req, options.maxProcesses, "!~PASSENGER_MAX_PROCESSES"); fillPoolOption(req, options.spawnMethod, "!~PASSENGER_SPAWN_METHOD"); fillPoolOption(req, options.startCommand, "!~PASSENGER_START_COMMAND"); fillPoolOptionSecToMsec(req, options.startTimeout, "!~PASSENGER_START_TIMEOUT"); fillPoolOption(req, options.maxPreloaderIdleTime, "!~PASSENGER_MAX_PRELOADER_IDLE_TIME"); fillPoolOption(req, options.maxRequestQueueSize, "!~PASSENGER_MAX_REQUEST_QUEUE_SIZE"); fillPoolOption(req, options.abortWebsocketsOnProcessShutdown, "!~PASSENGER_ABORT_WEBSOCKETS_ON_PROCESS_SHUTDOWN"); fillPoolOption(req, options.forceMaxConcurrentRequestsPerProcess, "!~PASSENGER_FORCE_MAX_CONCURRENT_REQUESTS_PER_PROCESS"); fillPoolOption(req, options.restartDir, "!~PASSENGER_RESTART_DIR"); fillPoolOption(req, options.startupFile, "!~PASSENGER_STARTUP_FILE"); fillPoolOption(req, options.loadShellEnvvars, "!~PASSENGER_LOAD_SHELL_ENVVARS"); fillPoolOption(req, options.fileDescriptorUlimit, "!~PASSENGER_APP_FILE_DESCRIPTOR_ULIMIT"); fillPoolOption(req, options.raiseInternalError, "!~PASSENGER_RAISE_INTERNAL_ERROR"); fillPoolOption(req, options.lveMinUid, "!~PASSENGER_LVE_MIN_UID"); /******************/ boost::shared_ptr<Options> optionsCopy = boost::make_shared<Options>(options); optionsCopy->persist(options); optionsCopy->clearPerRequestFields(); optionsCopy->detachFromUnionStationTransaction(); poolOptionsCache.insert(options.getAppGroupName(), optionsCopy); }
* using definitions from src/ruby_supportlib/phusion_passenger/apache2/config_options.rb. * Edits to SetHeaders.cpp will be lost. * * To update SetHeaders.cpp: * rake apache2 * * To force regeneration of SetHeaders.cpp: * rm -f src/apache2_module/SetHeaders.cpp * rake src/apache2_module/SetHeaders.cpp */ addHeader(result, StaticString("!~PASSENGER_RUBY", sizeof("!~PASSENGER_RUBY") - 1), config->ruby ? config->ruby : serverConfig.defaultRuby); addHeader(result, StaticString("!~PASSENGER_PYTHON", sizeof("!~PASSENGER_PYTHON") - 1), config->python); addHeader(result, StaticString("!~PASSENGER_NODEJS", sizeof("!~PASSENGER_NODEJS") - 1), config->nodejs); addHeader(result, StaticString("!~PASSENGER_METEOR_APP_SETTINGS", sizeof("!~PASSENGER_METEOR_APP_SETTINGS") - 1), config->meteorAppSettings);
namespace HPHP { /////////////////////////////////////////////////////////////////////////////// #define DEFINE_CONSTANT(name, value) \ const int64_t k_##name = value; \ const StaticString s_##name(#name) \ DEFINE_CONSTANT(INPUT_POST, 0); DEFINE_CONSTANT(INPUT_GET, 1); DEFINE_CONSTANT(INPUT_COOKIE, 2); DEFINE_CONSTANT(INPUT_ENV, 4); DEFINE_CONSTANT(INPUT_SERVER, 5); DEFINE_CONSTANT(INPUT_SESSION, 6); DEFINE_CONSTANT(INPUT_REQUEST, 99); DEFINE_CONSTANT(FILTER_FLAG_NONE, 0); DEFINE_CONSTANT(FILTER_REQUIRE_SCALAR, 33554432); DEFINE_CONSTANT(FILTER_REQUIRE_ARRAY, 16777216); DEFINE_CONSTANT(FILTER_FORCE_ARRAY, 67108864); DEFINE_CONSTANT(FILTER_NULL_ON_FAILURE, 134217728); DEFINE_CONSTANT(FILTER_VALIDATE_INT, 257); DEFINE_CONSTANT(FILTER_VALIDATE_BOOLEAN, 258); DEFINE_CONSTANT(FILTER_VALIDATE_FLOAT, 259); DEFINE_CONSTANT(FILTER_VALIDATE_REGEXP, 272); DEFINE_CONSTANT(FILTER_VALIDATE_URL, 273); DEFINE_CONSTANT(FILTER_VALIDATE_EMAIL, 274); DEFINE_CONSTANT(FILTER_VALIDATE_IP, 275); DEFINE_CONSTANT(FILTER_VALIDATE_MAC, 276); DEFINE_CONSTANT(FILTER_DEFAULT, 516); DEFINE_CONSTANT(FILTER_UNSAFE_RAW, 516); DEFINE_CONSTANT(FILTER_SANITIZE_STRING, 513); DEFINE_CONSTANT(FILTER_SANITIZE_STRIPPED, 513); DEFINE_CONSTANT(FILTER_SANITIZE_ENCODED, 514); DEFINE_CONSTANT(FILTER_SANITIZE_SPECIAL_CHARS, 515); DEFINE_CONSTANT(FILTER_SANITIZE_FULL_SPECIAL_CHARS, 515); DEFINE_CONSTANT(FILTER_SANITIZE_EMAIL, 517); DEFINE_CONSTANT(FILTER_SANITIZE_URL, 518); DEFINE_CONSTANT(FILTER_SANITIZE_NUMBER_INT, 519); DEFINE_CONSTANT(FILTER_SANITIZE_NUMBER_FLOAT, 520); DEFINE_CONSTANT(FILTER_SANITIZE_MAGIC_QUOTES, 521); DEFINE_CONSTANT(FILTER_CALLBACK, 1024); DEFINE_CONSTANT(FILTER_FLAG_ALLOW_OCTAL, 1); DEFINE_CONSTANT(FILTER_FLAG_ALLOW_HEX, 2); DEFINE_CONSTANT(FILTER_FLAG_STRIP_LOW, 4); DEFINE_CONSTANT(FILTER_FLAG_STRIP_HIGH, 8); DEFINE_CONSTANT(FILTER_FLAG_ENCODE_LOW, 16); DEFINE_CONSTANT(FILTER_FLAG_ENCODE_HIGH, 32); DEFINE_CONSTANT(FILTER_FLAG_ENCODE_AMP, 64); DEFINE_CONSTANT(FILTER_FLAG_NO_ENCODE_QUOTES, 128); DEFINE_CONSTANT(FILTER_FLAG_EMPTY_STRING_NULL, 256); DEFINE_CONSTANT(FILTER_FLAG_STRIP_BACKTICK, 512); DEFINE_CONSTANT(FILTER_FLAG_ALLOW_FRACTION, 4096); DEFINE_CONSTANT(FILTER_FLAG_ALLOW_THOUSAND, 8192); DEFINE_CONSTANT(FILTER_FLAG_ALLOW_SCIENTIFIC, 16384); DEFINE_CONSTANT(FILTER_FLAG_SCHEME_REQUIRED, 65536); DEFINE_CONSTANT(FILTER_FLAG_HOST_REQUIRED, 131072); DEFINE_CONSTANT(FILTER_FLAG_PATH_REQUIRED, 262144); DEFINE_CONSTANT(FILTER_FLAG_QUERY_REQUIRED, 524288); DEFINE_CONSTANT(FILTER_FLAG_IPV4, 1048576); DEFINE_CONSTANT(FILTER_FLAG_IPV6, 2097152); DEFINE_CONSTANT(FILTER_FLAG_NO_RES_RANGE, 4194304); DEFINE_CONSTANT(FILTER_FLAG_NO_PRIV_RANGE, 8388608); #undef DEFINE_CONSTANT const StaticString s_GET("_GET"), s_POST("_POST"), s_COOKIE("_COOKIE"), s_SERVER("_SERVER"), s_ENV("_ENV"); struct FilterRequestData final { void requestInit() { // This doesn't copy them yet, but will do COW if they are modified m_GET = php_global(s_GET).toArray(); m_POST = php_global(s_POST).toArray(); m_COOKIE = php_global(s_COOKIE).toArray(); m_SERVER = php_global(s_SERVER).toArray(); m_ENV = php_global(s_ENV).toArray(); } void requestShutdown() { m_GET.detach(); m_POST.detach(); m_COOKIE.detach(); m_SERVER.detach(); m_ENV.detach(); } Array getVar(int64_t type) { switch (type) { case k_INPUT_GET: return m_GET; case k_INPUT_POST: return m_POST; case k_INPUT_COOKIE: return m_COOKIE; case k_INPUT_SERVER: return m_SERVER; case k_INPUT_ENV: return m_ENV; } return empty_array(); } void vscan(IMarker& mark) const { mark(m_GET); mark(m_POST); mark(m_COOKIE); mark(m_SERVER); mark(m_ENV); } private: Array m_GET; Array m_POST; Array m_COOKIE; Array m_SERVER; Array m_ENV; }; IMPLEMENT_THREAD_LOCAL_NO_CHECK(FilterRequestData, s_filter_request_data); #define REGISTER_CONSTANT(name) \ Native::registerConstant<KindOfInt64>(s_##name.get(), k_##name) \ static class FilterExtension final : public Extension { public: FilterExtension() : Extension("filter", "0.11.0") {} void moduleLoad(const IniSetting::Map& ini, Hdf config) override { HHVM_FE(__SystemLib_filter_input_get_var); HHVM_FE(_filter_snapshot_globals); } void moduleInit() override { REGISTER_CONSTANT(INPUT_POST); REGISTER_CONSTANT(INPUT_GET); REGISTER_CONSTANT(INPUT_COOKIE); REGISTER_CONSTANT(INPUT_ENV); REGISTER_CONSTANT(INPUT_SERVER); REGISTER_CONSTANT(INPUT_SESSION); REGISTER_CONSTANT(INPUT_REQUEST); REGISTER_CONSTANT(FILTER_FLAG_NONE); REGISTER_CONSTANT(FILTER_REQUIRE_SCALAR); REGISTER_CONSTANT(FILTER_REQUIRE_ARRAY); REGISTER_CONSTANT(FILTER_FORCE_ARRAY); REGISTER_CONSTANT(FILTER_NULL_ON_FAILURE); REGISTER_CONSTANT(FILTER_VALIDATE_INT); REGISTER_CONSTANT(FILTER_VALIDATE_BOOLEAN); REGISTER_CONSTANT(FILTER_VALIDATE_FLOAT); REGISTER_CONSTANT(FILTER_VALIDATE_REGEXP); REGISTER_CONSTANT(FILTER_VALIDATE_URL); REGISTER_CONSTANT(FILTER_VALIDATE_EMAIL); REGISTER_CONSTANT(FILTER_VALIDATE_IP); REGISTER_CONSTANT(FILTER_VALIDATE_MAC); REGISTER_CONSTANT(FILTER_DEFAULT); REGISTER_CONSTANT(FILTER_UNSAFE_RAW); REGISTER_CONSTANT(FILTER_SANITIZE_STRING); REGISTER_CONSTANT(FILTER_SANITIZE_STRIPPED); REGISTER_CONSTANT(FILTER_SANITIZE_ENCODED); REGISTER_CONSTANT(FILTER_SANITIZE_SPECIAL_CHARS); REGISTER_CONSTANT(FILTER_SANITIZE_FULL_SPECIAL_CHARS); REGISTER_CONSTANT(FILTER_SANITIZE_EMAIL); REGISTER_CONSTANT(FILTER_SANITIZE_URL); REGISTER_CONSTANT(FILTER_SANITIZE_NUMBER_INT); REGISTER_CONSTANT(FILTER_SANITIZE_NUMBER_FLOAT); REGISTER_CONSTANT(FILTER_SANITIZE_MAGIC_QUOTES); REGISTER_CONSTANT(FILTER_CALLBACK); REGISTER_CONSTANT(FILTER_FLAG_ALLOW_OCTAL); REGISTER_CONSTANT(FILTER_FLAG_ALLOW_HEX); REGISTER_CONSTANT(FILTER_FLAG_STRIP_LOW); REGISTER_CONSTANT(FILTER_FLAG_STRIP_HIGH); REGISTER_CONSTANT(FILTER_FLAG_ENCODE_LOW); REGISTER_CONSTANT(FILTER_FLAG_ENCODE_HIGH); REGISTER_CONSTANT(FILTER_FLAG_ENCODE_AMP); REGISTER_CONSTANT(FILTER_FLAG_NO_ENCODE_QUOTES); REGISTER_CONSTANT(FILTER_FLAG_EMPTY_STRING_NULL); REGISTER_CONSTANT(FILTER_FLAG_STRIP_BACKTICK); REGISTER_CONSTANT(FILTER_FLAG_ALLOW_FRACTION); REGISTER_CONSTANT(FILTER_FLAG_ALLOW_THOUSAND); REGISTER_CONSTANT(FILTER_FLAG_ALLOW_SCIENTIFIC); REGISTER_CONSTANT(FILTER_FLAG_SCHEME_REQUIRED); REGISTER_CONSTANT(FILTER_FLAG_HOST_REQUIRED); REGISTER_CONSTANT(FILTER_FLAG_PATH_REQUIRED); REGISTER_CONSTANT(FILTER_FLAG_QUERY_REQUIRED); REGISTER_CONSTANT(FILTER_FLAG_IPV4); REGISTER_CONSTANT(FILTER_FLAG_IPV6); REGISTER_CONSTANT(FILTER_FLAG_NO_RES_RANGE); REGISTER_CONSTANT(FILTER_FLAG_NO_PRIV_RANGE); HHVM_FE(filter_list); HHVM_FE(filter_id); HHVM_FE(filter_var); loadSystemlib(); } void threadInit() override { s_filter_request_data.getCheck(); } void requestShutdown() override { // warm up the s_filter_request_data s_filter_request_data->requestShutdown(); } void vscan(IMarker& m) const override { s_filter_request_data->vscan(m); } } s_filter_extension; namespace { InitFiniNode globalsInit([]() { s_filter_request_data->requestInit(); }, InitFiniNode::When::GlobalsInit); } #undef REGISTER_CONSTANT /////////////////////////////////////////////////////////////////////////////// typedef struct filter_list_entry { StaticString name; int64_t id; Variant (*function)(PHP_INPUT_FILTER_PARAM_DECL); } filter_list_entry; static const filter_list_entry filter_list[] = { { StaticString("int"), k_FILTER_VALIDATE_INT, php_filter_int }, { StaticString("boolean"), k_FILTER_VALIDATE_BOOLEAN, php_filter_boolean }, { StaticString("float"), k_FILTER_VALIDATE_FLOAT, php_filter_float }, { StaticString("validate_regexp"), k_FILTER_VALIDATE_REGEXP, php_filter_validate_regexp }, { StaticString("validate_url"), k_FILTER_VALIDATE_URL, php_filter_validate_url }, { StaticString("validate_email"), k_FILTER_VALIDATE_EMAIL, php_filter_validate_email }, { StaticString("validate_ip"), k_FILTER_VALIDATE_IP, php_filter_validate_ip }, { StaticString("validate_mac"), k_FILTER_VALIDATE_MAC, php_filter_validate_mac }, { StaticString("string"), k_FILTER_SANITIZE_STRING, php_filter_string }, { StaticString("stripped"), k_FILTER_SANITIZE_STRING, php_filter_string }, { StaticString("encoded"), k_FILTER_SANITIZE_ENCODED, php_filter_encoded }, { StaticString("special_chars"), k_FILTER_SANITIZE_SPECIAL_CHARS, php_filter_special_chars }, { StaticString("full_special_chars"), k_FILTER_SANITIZE_FULL_SPECIAL_CHARS, php_filter_full_special_chars }, { StaticString("unsafe_raw"), k_FILTER_UNSAFE_RAW, php_filter_unsafe_raw }, { StaticString("email"), k_FILTER_SANITIZE_EMAIL, php_filter_email }, { StaticString("url"), k_FILTER_SANITIZE_URL, php_filter_url }, { StaticString("number_int"), k_FILTER_SANITIZE_NUMBER_INT, php_filter_number_int }, { StaticString("number_float"), k_FILTER_SANITIZE_NUMBER_FLOAT, php_filter_number_float }, { StaticString("magic_quotes"), k_FILTER_SANITIZE_MAGIC_QUOTES, php_filter_magic_quotes }, { StaticString("callback"), k_FILTER_CALLBACK, php_filter_callback }, }; const StaticString s_flags("flags"), s_default("default"), s_options("options"); static Variant fail(bool return_null, const Variant& options) { if (options.isArray()) { const Array& arr(options.toArray()); if (arr.exists(s_default)) { return arr[s_default]; } } if (return_null) { return init_null(); } return false; } static const filter_list_entry* php_find_filter(uint64_t id) { int i, size = sizeof(filter_list) / sizeof(filter_list_entry); for (i = 0; i < size; ++i) { if (filter_list[i].id == id) { return &filter_list[i]; } } return nullptr; } #define FAIL_IF(x) do { if (x) return false; } while (0) static bool filter_var(Variant& ret, const Variant& variable, int64_t filter, const Variant& options) { const filter_list_entry* filter_func = php_find_filter(filter); if (!filter_func) { return false; } int64_t flags; Variant option_array; if (options.isArray()) { auto arr = options.toArray(); flags = arr[s_flags].toInt64(); option_array = arr[s_options]; } else { flags = options.toInt64(); } FAIL_IF(variable.isObject() && !variable.getObjectData()->hasToString()); ret = filter_func->function(variable.toString(), flags, option_array); if (option_array.isArray() && option_array.toArray().exists(s_default) && ((flags & k_FILTER_NULL_ON_FAILURE && ret.isNull()) || (!(flags & k_FILTER_NULL_ON_FAILURE) && ret.isBoolean() && ret.asBooleanVal() == 0))) { ret = option_array.toArray()[s_default]; } return true; } static bool filter_recursive(Variant& ret, const Variant& variable, int64_t filter, const Variant& options) { Array arr; for (ArrayIter iter(variable.toArray()); iter; ++iter) { Variant v; if (iter.second().isArray()) { FAIL_IF(!filter_recursive(v, iter.second().toArray(), filter, options)); } else { FAIL_IF(!filter_var(v, iter.second(), filter, options)); } arr.add(iter.first(), v); } ret = arr; return true; } #undef FAIL_IF /////////////////////////////////////////////////////////////////////////////// Variant HHVM_FUNCTION(filter_list) { size_t size = sizeof(filter_list) / sizeof(filter_list_entry); Array ret; for (size_t i = 0; i < size; ++i) { ret.append(filter_list[i].name); } return ret; } Variant HHVM_FUNCTION(filter_id, const Variant& filtername) { if (filtername.isArray()) { raise_warning("Array to string conversion"); return init_null(); } size_t size = sizeof(filter_list) / sizeof(filter_list_entry); for (size_t i = 0; i < size; ++i) { if (filter_list[i].name == filtername) { return filter_list[i].id; } } return false; } #define FAIL_IF(x) \ do { \ if (x) return fail(filter_flags & k_FILTER_NULL_ON_FAILURE, options); \ } while(0) Variant HHVM_FUNCTION(filter_var, const Variant& variable, int64_t filter /* = 516 */, const Variant& options /* = empty_array_ref */) { int64_t filter_flags; if (options.isArray()) { filter_flags = options.toCArrRef()[s_flags].toInt64(); } else { filter_flags = options.toInt64(); } if (!(filter_flags & k_FILTER_REQUIRE_ARRAY || filter_flags & k_FILTER_FORCE_ARRAY)) { filter_flags |= k_FILTER_REQUIRE_SCALAR; } // No idea why, but zend does this.. if (filter == k_FILTER_CALLBACK) { filter_flags = 0; } if (variable.isArray()) { FAIL_IF(filter_flags & k_FILTER_REQUIRE_SCALAR); Variant ret; FAIL_IF(!filter_recursive(ret, variable, filter, options)); return ret; } FAIL_IF(filter_flags & k_FILTER_REQUIRE_ARRAY); Variant ret; FAIL_IF(!filter_var(ret, variable, filter, options)); if (filter_flags & k_FILTER_FORCE_ARRAY && !ret.isArray()) { ret = make_packed_array(ret); } return ret; } #undef FAIL_IF Array HHVM_FUNCTION(__SystemLib_filter_input_get_var, int64_t variable_name) { return s_filter_request_data->getVar(variable_name); } void HHVM_FUNCTION(_filter_snapshot_globals) { s_filter_request_data->requestInit(); } /////////////////////////////////////////////////////////////////////////////// }
// The 'self' parameter is for keeping the current Group object alive while this thread is running. void Group::spawnThreadOOBWRequest(GroupPtr self, ProcessPtr process) { TRACE_POINT(); this_thread::disable_interruption di; this_thread::disable_syscall_interruption dsi; Socket *socket; Connection connection; PoolPtr pool = getPool(); Pool::DebugSupportPtr debug = pool->debugSupport; UPDATE_TRACE_POINT(); P_DEBUG("Performing OOBW request for process " << process->inspect()); if (debug != NULL && debug->oobw) { debug->debugger->send("OOBW request about to start"); debug->messages->recv("Proceed with OOBW request"); } UPDATE_TRACE_POINT(); { // Standard resource management boilerplate stuff... boost::unique_lock<boost::mutex> lock(pool->syncher); if (OXT_UNLIKELY(!process->isAlive() || process->enabled == Process::DETACHED || !isAlive())) { return; } if (process->enabled != Process::DISABLED) { UPDATE_TRACE_POINT(); P_INFO("Out-of-Band Work canceled: process " << process->inspect() << " was concurrently re-enabled."); if (debug != NULL && debug->oobw) { debug->debugger->send("OOBW request canceled"); } return; } assert(process->oobwStatus == Process::OOBW_IN_PROGRESS); assert(process->sessions == 0); socket = process->sessionSockets.top(); assert(socket != NULL); } UPDATE_TRACE_POINT(); unsigned long long timeout = 1000 * 1000 * 60; // 1 min try { this_thread::restore_interruption ri(di); this_thread::restore_syscall_interruption rsi(dsi); // Grab a connection. The connection is marked as fail in order to // ensure it is closed / recycled after this request (otherwise we'd // need to completely read the response). connection = socket->checkoutConnection(); connection.fail = true; ScopeGuard guard(boost::bind(&Socket::checkinConnection, socket, connection)); // This is copied from RequestHandler when it is sending data using the // "session" protocol. char sizeField[sizeof(uint32_t)]; SmallVector<StaticString, 10> data; data.push_back(StaticString(sizeField, sizeof(uint32_t))); data.push_back(makeStaticStringWithNull("REQUEST_METHOD")); data.push_back(makeStaticStringWithNull("OOBW")); data.push_back(makeStaticStringWithNull("PASSENGER_CONNECT_PASSWORD")); data.push_back(makeStaticStringWithNull(process->connectPassword)); uint32_t dataSize = 0; for (unsigned int i = 1; i < data.size(); i++) { dataSize += (uint32_t) data[i].size(); } Uint32Message::generate(sizeField, dataSize); gatheredWrite(connection.fd, &data[0], data.size(), &timeout); // We do not care what the actual response is ... just wait for it. UPDATE_TRACE_POINT(); waitUntilReadable(connection.fd, &timeout); } catch (const SystemException &e) { P_ERROR("*** ERROR: " << e.what() << "\n" << e.backtrace()); } catch (const TimeoutException &e) { P_ERROR("*** ERROR: " << e.what() << "\n" << e.backtrace()); } UPDATE_TRACE_POINT(); vector<Callback> actions; { // Standard resource management boilerplate stuff... PoolPtr pool = getPool(); boost::unique_lock<boost::mutex> lock(pool->syncher); if (OXT_UNLIKELY(!process->isAlive() || !isAlive())) { return; } process->oobwStatus = Process::OOBW_NOT_ACTIVE; if (process->enabled == Process::DISABLED) { enable(process, actions); assignSessionsToGetWaiters(actions); } pool->fullVerifyInvariants(); initiateNextOobwRequest(); } UPDATE_TRACE_POINT(); runAllActions(actions); actions.clear(); UPDATE_TRACE_POINT(); P_DEBUG("Finished OOBW request for process " << process->inspect()); if (debug != NULL && debug->oobw) { debug->debugger->send("OOBW request finished"); } }
namespace HPHP { /////////////////////////////////////////////////////////////////////////////// static StaticString s_spl_autoload("spl_autoload"); static StaticString s_spl_autoload_call("spl_autoload_call"); static StaticString s_default_extensions(".inc,.php"); static StaticString s_rewind("rewind"); static StaticString s_valid("valid"); static StaticString s_next("next"); static StaticString s_current("current"); static StaticString s_key("key"); static StaticString s_getIterator("getIterator"); static const StaticString spl_classes[] = { StaticString("AppendIterator"), StaticString("ArrayIterator"), StaticString("ArrayObject"), StaticString("BadFunctionCallException"), StaticString("BadMethodCallException"), StaticString("CachingIterator"), StaticString("Countable"), StaticString("DirectoryIterator"), StaticString("DomainException"), StaticString("EmptyIterator"), StaticString("FilesystemIterator"), StaticString("FilterIterator"), StaticString("GlobIterator"), StaticString("InfiniteIterator"), StaticString("InvalidArgumentException"), StaticString("IteratorIterator"), StaticString("LengthException"), StaticString("LimitIterator"), StaticString("LogicException"), StaticString("MultipleIterator"), StaticString("NoRewindIterator"), StaticString("OuterIterator"), StaticString("OutOfBoundsException"), StaticString("OutOfRangeException"), StaticString("OverflowException"), StaticString("ParentIterator"), StaticString("RangeException"), StaticString("RecursiveArrayIterator"), StaticString("RecursiveCachingIterator"), StaticString("RecursiveDirectoryIterator"), StaticString("RecursiveFilterIterator"), StaticString("RecursiveIterator"), StaticString("RecursiveIteratorIterator"), StaticString("RecursiveRegexIterator"), StaticString("RecursiveTreeIterator"), StaticString("RegexIterator"), StaticString("RuntimeException"), StaticString("SeekableIterator"), StaticString("SplDoublyLinkedList"), StaticString("SplFileInfo"), StaticString("SplFileObject"), StaticString("SplFixedArray"), StaticString("SplHeap"), StaticString("SplMinHeap"), StaticString("SplMaxHeap"), StaticString("SplObjectStorage"), StaticString("SplObserver"), StaticString("SplPriorityQueue"), StaticString("SplQueue"), StaticString("SplStack"), StaticString("SplSubject"), StaticString("SplTempFileObject"), StaticString("UnderflowException"), StaticString("UnexpectedValueException"), }; Array f_spl_classes() { const size_t num_classes = sizeof(spl_classes) / sizeof(spl_classes[0]); ArrayInit ret(num_classes); for (size_t i = 0; i < num_classes; ++i) { ret.set(spl_classes[i], spl_classes[i]); } return ret.create(); } void throw_spl_exception(const char *fmt, ...) { va_list ap; va_start(ap, fmt); std::string msg; Util::string_vsnprintf(msg, fmt, ap); va_end(ap); throw Object(SystemLib::AllocExceptionObject(Variant(msg))); } static bool s_inited = false; static int64_t s_hash_mask_handle = 0; static Mutex s_mutex; String f_spl_object_hash(CObjRef obj) { if (!s_inited) { Lock lock(s_mutex); if (!s_inited) { f_mt_srand(); s_hash_mask_handle |= f_mt_rand(); s_hash_mask_handle <<= 16; s_hash_mask_handle |= f_mt_rand(); s_hash_mask_handle <<= 16; s_hash_mask_handle |= f_mt_rand(); s_hash_mask_handle <<= 16; s_hash_mask_handle |= f_mt_rand(); s_inited = true; } } char buf[33]; snprintf(buf, sizeof(buf), "%032" PRIx64, s_hash_mask_handle ^ (int64_t)obj.get()); return String(buf, CopyString); } int64_t f_hphp_object_pointer(CObjRef obj) { return (int64_t)obj.get();} Variant f_hphp_get_this() { return g_vmContext->getThis(); } Variant f_class_implements(CVarRef obj, bool autoload /* = true */) { Class* cls; if (obj.isString()) { cls = Unit::getClass(obj.getStringData(), autoload); if (!cls) { return false; } } else if (obj.isObject()) { cls = obj.getObjectData()->getVMClass(); } else { return false; } Array ret(Array::Create()); const Class::InterfaceMap& ifaces = cls->allInterfaces(); for (int i = 0, size = ifaces.size(); i < size; i++) { ret.set(ifaces[i]->nameRef(), ifaces[i]->nameRef()); } return ret; } Variant f_class_parents(CVarRef obj, bool autoload /* = true */) { Class* cls; if (obj.isString()) { cls = Unit::getClass(obj.getStringData(), autoload); if (!cls) { return false; } } else if (obj.isObject()) { cls = obj.getObjectData()->getVMClass(); } else { return false; } Array ret(Array::Create()); for (cls = cls->parent(); cls; cls = cls->parent()) { auto& clsName = cls->nameRef(); ret.set(clsName, clsName); } return ret; } Variant f_class_uses(CVarRef obj, bool autoload /* = true */) { Class* cls; if (obj.isString()) { cls = Unit::getClass(obj.getStringData(), autoload); if (!cls) { return false; } } else if (obj.isObject()) { cls = obj.getObjectData()->getVMClass(); } else { return false; } Array ret(Array::Create()); for (auto& elem : cls->usedTraits()) { auto& traitName = elem.get()->nameRef(); ret.set(traitName, traitName); } return ret; } Object get_traversable_object_iterator(CVarRef obj) { if (!obj.instanceof(SystemLib::s_TraversableClass)) { raise_error("Argument must implement interface Traversable"); } bool isIteratorAggregate; Object itObj = obj.getObjectData() ->iterableObject(isIteratorAggregate, true); if (!isIteratorAggregate) { if (obj.instanceof(SystemLib::s_IteratorAggregateClass)) { raise_error("Objects returned by getIterator() must be traversable or " "implement interface Iterator"); } else { raise_error( "Class %s must implement interface Traversable as part of either " "Iterator or IteratorAggregate", obj.toObject()->o_getClassName()->data() ); } } return itObj; } Variant f_iterator_apply(CVarRef obj, CVarRef func, CArrRef params /* = null_array */) { Object pobj = get_traversable_object_iterator(obj); pobj->o_invoke_few_args(s_rewind, 0); int64_t count = 0; while (same(pobj->o_invoke_few_args(s_valid, 0), true)) { if (!same(vm_call_user_func(func, params), true)) { break; } ++count; pobj->o_invoke_few_args(s_next, 0); } return count; } Variant f_iterator_count(CVarRef obj) { Object pobj = get_traversable_object_iterator(obj); pobj->o_invoke_few_args(s_rewind, 0); int64_t count = 0; while (same(pobj->o_invoke_few_args(s_valid, 0), true)) { ++count; pobj->o_invoke_few_args(s_next, 0); } return count; } Variant f_iterator_to_array(CVarRef obj, bool use_keys /* = true */) { Object pobj = get_traversable_object_iterator(obj); Array ret(Array::Create()); pobj->o_invoke_few_args(s_rewind, 0); while (same(pobj->o_invoke_few_args(s_valid, 0), true)) { Variant val = pobj->o_invoke_few_args(s_current, 0); if (use_keys) { Variant key = pobj->o_invoke_few_args(s_key, 0); ret.set(key, val); } else { ret.append(val); } pobj->o_invoke_few_args(s_next, 0); } return ret; } bool f_spl_autoload_register(CVarRef autoload_function /* = null_variant */, bool throws /* = true */, bool prepend /* = false */) { if (autoload_function.same(s_spl_autoload_call)) { if (throws) { throw_spl_exception("Function spl_autoload_call()" "cannot be registered"); } return false; } CVarRef func = autoload_function.isNull() ? s_spl_autoload : autoload_function; bool res = AutoloadHandler::s_instance->addHandler(func, prepend); if (!res && throws) { throw_spl_exception("Invalid autoload_function specified"); } return res; } bool f_spl_autoload_unregister(CVarRef autoload_function) { if (autoload_function.same(s_spl_autoload_call)) { AutoloadHandler::s_instance->removeAllHandlers(); } else { AutoloadHandler::s_instance->removeHandler(autoload_function); } return true; } Variant f_spl_autoload_functions() { CArrRef handlers = AutoloadHandler::s_instance->getHandlers(); if (handlers.isNull()) return false; else return handlers.values(); } void f_spl_autoload_call(CStrRef class_name) { AutoloadHandler::s_instance->invokeHandler(class_name, true); } namespace { class ExtensionList : public RequestEventHandler { public: virtual void requestInit() { extensions = CREATE_VECTOR2(String(".inc"), String(".php")); } virtual void requestShutdown() { extensions.reset(); } Array extensions; }; IMPLEMENT_STATIC_REQUEST_LOCAL(ExtensionList, s_extension_list); } String f_spl_autoload_extensions(CStrRef file_extensions /* = null_string */) { if (!file_extensions.isNull()) { s_extension_list->extensions = StringUtil::Explode(file_extensions, ",") .toArray(); return file_extensions; } return StringUtil::Implode(s_extension_list->extensions, ","); } void f_spl_autoload(CStrRef class_name, CStrRef file_extensions /* = null_string */) { Array ext = file_extensions.isNull() ? s_extension_list->extensions : StringUtil::Explode(file_extensions, ",").toArray(); String lClass = StringUtil::ToLower(class_name); bool found = false; for (ArrayIter iter(ext); iter; ++iter) { String fileName = lClass + iter.second(); include(fileName, true, "", false); if (f_class_exists(class_name, false)) { found = true; break; } } if (!found && !AutoloadHandler::s_instance->isRunning()) { throw_spl_exception("Class %s could not be loaded", class_name.c_str()); } } /////////////////////////////////////////////////////////////////////////////// }