998951619f
We did not intend to imply our copyrights last forever Closes #759
334 linhas
9.4 KiB
C++
334 linhas
9.4 KiB
C++
/*
|
|
+----------------------------------------------------------------------+
|
|
| HipHop for PHP |
|
|
+----------------------------------------------------------------------+
|
|
| Copyright (c) 2010-2013 Facebook, Inc. (http://www.facebook.com) |
|
|
+----------------------------------------------------------------------+
|
|
| This source file is subject to version 3.01 of the PHP license, |
|
|
| that is bundled with this package in the file LICENSE, and is |
|
|
| available through the world-wide-web at the following url: |
|
|
| http://www.php.net/license/3_01.txt |
|
|
| If you did not receive a copy of the PHP license and are unable to |
|
|
| obtain it through the world-wide-web, please send a note to |
|
|
| license@php.net so we can mail you a copy immediately. |
|
|
+----------------------------------------------------------------------+
|
|
*/
|
|
|
|
#define __STDC_LIMIT_MACROS
|
|
#include <stdint.h>
|
|
|
|
#include "hphp/runtime/base/ini_setting.h"
|
|
#include "hphp/runtime/base/complex_types.h"
|
|
#include "hphp/runtime/base/type_conversions.h"
|
|
#include "hphp/runtime/base/builtin_functions.h"
|
|
#include "hphp/runtime/base/hphp_system.h"
|
|
#include "hphp/runtime/base/runtime_option.h"
|
|
#include "hphp/runtime/base/timeout_thread.h"
|
|
#include "hphp/runtime/ext/extension.h"
|
|
#include "hphp/util/lock.h"
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
// defined in zend/zend_ini.tab.cpp
|
|
|
|
extern bool zend_parse_ini_string
|
|
(HPHP::CStrRef str, HPHP::CStrRef filename, int scanner_mode,
|
|
HPHP::IniSetting::PFN_PARSER_CALLBACK callback, void *arg);
|
|
|
|
namespace HPHP {
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
|
|
bool ini_on_update_bool(CStrRef value, void *p) {
|
|
if (p) {
|
|
if ((value.size() == 2 && strcasecmp("on", value.data()) == 0) ||
|
|
(value.size() == 3 && strcasecmp("yes", value.data()) == 0) ||
|
|
(value.size() == 4 && strcasecmp("true", value.data()) == 0)) {
|
|
*((bool*)p) = true;
|
|
} else {
|
|
*((bool*)p) = value.toBoolean();
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
|
|
bool ini_on_update_long(CStrRef value, void *p) {
|
|
if (p) {
|
|
*((int64_t*)p) = value.toInt64();
|
|
}
|
|
return true;
|
|
}
|
|
|
|
bool ini_on_update_non_negative(CStrRef value, void *p) {
|
|
int64_t v = value.toInt64();
|
|
if (v < 0) {
|
|
return false;
|
|
}
|
|
if (p) {
|
|
*((int64_t*)p) = v;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
bool ini_on_update_real(CStrRef value, void *p) {
|
|
if (p) {
|
|
*((double*)p) = value.toDouble();
|
|
}
|
|
return true;
|
|
}
|
|
|
|
bool ini_on_update_string(CStrRef value, void *p) {
|
|
if (p) {
|
|
*((std::string*)p) = std::string(value.data(), value.size());
|
|
}
|
|
return true;
|
|
}
|
|
|
|
bool ini_on_update_string_non_empty(CStrRef value, void *p) {
|
|
if (value.empty()) {
|
|
return false;
|
|
}
|
|
if (p) {
|
|
*((std::string*)p) = std::string(value.data(), value.size());
|
|
}
|
|
return true;
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
// callbacks for creating arrays out of ini
|
|
|
|
static void php_simple_ini_parser_cb
|
|
(String *arg1, String *arg2, String *arg3, int callback_type, void *arg) {
|
|
assert(arg1);
|
|
if (!arg1 || !arg2) return;
|
|
|
|
Variant *arr = (Variant*)arg;
|
|
switch (callback_type) {
|
|
case IniSetting::ParserEntry:
|
|
arr->set(*arg1, *arg2);
|
|
break;
|
|
case IniSetting::ParserPopEntry:
|
|
{
|
|
Variant &hash = arr->lvalAt(*arg1);
|
|
if (!hash.isArray()) {
|
|
hash = Array::Create();
|
|
}
|
|
if (arg3 && !arg3->empty()) {
|
|
hash.set(*arg3, *arg2);
|
|
} else {
|
|
hash.append(*arg2);
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
struct CallbackData {
|
|
Variant active_section;
|
|
Variant arr;
|
|
};
|
|
|
|
static void php_ini_parser_cb_with_sections
|
|
(String *arg1, String *arg2, String *arg3, int callback_type, void *arg) {
|
|
assert(arg1);
|
|
if (!arg1) return;
|
|
|
|
CallbackData *data = (CallbackData*)arg;
|
|
Variant *arr = &data->arr;
|
|
if (callback_type == IniSetting::ParserSection) {
|
|
data->active_section.unset(); // break ref() from previous section
|
|
data->active_section = Array::Create();
|
|
arr->set(*arg1, ref(data->active_section));
|
|
} else if (arg2) {
|
|
Variant *active_arr;
|
|
if (!data->active_section.isNull()) {
|
|
active_arr = &data->active_section;
|
|
} else {
|
|
active_arr = arr;
|
|
}
|
|
php_simple_ini_parser_cb(arg1, arg2, arg3, callback_type, active_arr);
|
|
}
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
|
|
static Mutex s_mutex;
|
|
Variant IniSetting::FromString(CStrRef ini, CStrRef filename,
|
|
bool process_sections, int scanner_mode) {
|
|
Lock lock(s_mutex); // ini parser is not thread-safe
|
|
|
|
if (process_sections) {
|
|
CallbackData data;
|
|
data.arr = Array::Create();
|
|
if (zend_parse_ini_string
|
|
(ini, filename, scanner_mode, php_ini_parser_cb_with_sections, &data)){
|
|
return data.arr;
|
|
}
|
|
} else {
|
|
Variant ret = Array::Create();
|
|
if (zend_parse_ini_string
|
|
(ini, filename, scanner_mode, php_simple_ini_parser_cb, &ret)) {
|
|
return ret;
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
struct UpdateCallbackData {
|
|
IniSetting::PFN_UPDATE_CALLBACK callback;
|
|
void *p;
|
|
};
|
|
|
|
typedef std::map<std::string, UpdateCallbackData> CallbackMap;
|
|
static IMPLEMENT_THREAD_LOCAL(CallbackMap, s_callbacks);
|
|
|
|
typedef std::map<std::string, std::string> DefaultMap;
|
|
static DefaultMap s_global_ini;
|
|
|
|
void IniSetting::SetGlobalDefault(const char *name, const char *value) {
|
|
assert(name && *name);
|
|
assert(value);
|
|
assert(!Extension::ModulesInitialised());
|
|
|
|
s_global_ini[name] = value;
|
|
}
|
|
|
|
void IniSetting::Bind(const char *name, const char *value,
|
|
PFN_UPDATE_CALLBACK callback, void *p /* = NULL */) {
|
|
assert(name && *name);
|
|
assert(value);
|
|
|
|
UpdateCallbackData &data = (*s_callbacks)[name];
|
|
data.callback = callback;
|
|
data.p = p;
|
|
(*callback)(value, p);
|
|
}
|
|
|
|
void IniSetting::Unbind(const char *name) {
|
|
assert(name && *name);
|
|
s_callbacks->erase(name);
|
|
}
|
|
|
|
bool IniSetting::Get(CStrRef name, String &value) {
|
|
if (name == "error_reporting") {
|
|
value = String((int64_t)g_context->getErrorReportingLevel());
|
|
return true;
|
|
}
|
|
if (name == "memory_limit") {
|
|
int64_t v = g_context->getRequestMemoryMaxBytes();
|
|
if (v == INT64_MAX) v = -1;
|
|
value = String(v);
|
|
return true;
|
|
}
|
|
if (name == "max_execution_time" || name == "maximum_execution_time") {
|
|
value = String((int64_t)g_context->getRequestTimeLimit());
|
|
return true;
|
|
}
|
|
if (name == "hphp.build_id") {
|
|
value = String(RuntimeOption::BuildId);
|
|
return true;
|
|
}
|
|
if (name == "hphp.compiler_version") {
|
|
value = String(getHphpCompilerVersion());
|
|
return true;
|
|
}
|
|
if (name == "hphp.compiler_id") {
|
|
value = String(getHphpCompilerId());
|
|
return true;
|
|
}
|
|
if (name == "arg_separator.output") {
|
|
value = g_context->getArgSeparatorOutput();
|
|
return true;
|
|
}
|
|
if (name == "upload_max_filesize") {
|
|
int uploadMaxFilesize = VirtualHost::GetUploadMaxFileSize() / (1 << 20);
|
|
value = String(uploadMaxFilesize) + "M";
|
|
return true;
|
|
}
|
|
if (name == "post_max_size") {
|
|
int postMaxSize = VirtualHost::GetMaxPostSize();
|
|
value = String(postMaxSize);
|
|
return true;
|
|
}
|
|
if (name == "log_errors") {
|
|
value = g_context->getLogErrors() ? "1" : "0";
|
|
return true;
|
|
}
|
|
if (name == "error_log") {
|
|
value = g_context->getErrorLog();
|
|
return true;
|
|
}
|
|
if (name == "notice_frequency") {
|
|
value = String((int64_t)RuntimeOption::NoticeFrequency);
|
|
return true;
|
|
}
|
|
if (name == "warning_frequency") {
|
|
value = String((int64_t)RuntimeOption::WarningFrequency);
|
|
return true;
|
|
}
|
|
if (name == "include_path") {
|
|
value = g_context->getIncludePath();
|
|
return true;
|
|
}
|
|
|
|
DefaultMap::iterator iter = s_global_ini.find(name.data());
|
|
if (iter != s_global_ini.end()) {
|
|
value = iter->second;
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
bool IniSetting::Set(CStrRef name, CStrRef value) {
|
|
CallbackMap::iterator iter = s_callbacks->find(name.data());
|
|
if (iter != s_callbacks->end()) {
|
|
return (*iter->second.callback)(value, iter->second.p);
|
|
}
|
|
if (name == "memory_limit") {
|
|
if (!value.empty()) {
|
|
int64_t newInt = value.toInt64();
|
|
char lastChar = value.charAt(value.size() - 1);
|
|
if (lastChar == 'K' || lastChar == 'k') {
|
|
newInt <<= 10;
|
|
} else if (lastChar == 'M' || lastChar == 'm') {
|
|
newInt <<= 20;
|
|
} else if (lastChar == 'G' || lastChar == 'g') {
|
|
newInt <<= 30;
|
|
}
|
|
g_context->setRequestMemoryMaxBytes(newInt);
|
|
return true;
|
|
}
|
|
} else if (name == "max_execution_time" || name == "maximum_execution_time"){
|
|
int64_t limit = value.toInt64();
|
|
TimeoutThread::DeferTimeout(limit);
|
|
// Just for ini_get
|
|
g_context->setRequestTimeLimit(limit);
|
|
return true;
|
|
} else if (name == "arg_separator.output") {
|
|
g_context->setArgSeparatorOutput(value);
|
|
return true;
|
|
} else if (name == "log_errors") {
|
|
bool log;
|
|
ini_on_update_bool(value, &log);
|
|
g_context->setLogErrors(log);
|
|
return true;
|
|
} else if (name == "error_log") {
|
|
g_context->setErrorLog(value);
|
|
return true;
|
|
} else if (name == "notice_frequency") {
|
|
RuntimeOption::NoticeFrequency = value.toInt64();
|
|
return true;
|
|
} else if (name == "warning_frequency") {
|
|
RuntimeOption::WarningFrequency = value.toInt64();
|
|
return true;
|
|
} else if (name == "include_path") {
|
|
g_context->setIncludePath(value);
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
}
|