Comparar commits
25 Commits
| Autor | SHA1 | Data | |
|---|---|---|---|
| 14e4d2d21c | |||
| 691535343a | |||
| 08fa42f2cb | |||
| a25e23a681 | |||
| 3504e7accf | |||
| 8f9ff8b3a4 | |||
| 62c4857595 | |||
| 99cfd7c3c7 | |||
| 352bcbb504 | |||
| 3af6d9ae90 | |||
| b8e48ac92d | |||
| 8561dc79d6 | |||
| a4f2211d79 | |||
| 6561d14139 | |||
| 0772c54bb9 | |||
| 3c6d7674ec | |||
| 8cd216c0ab | |||
| e3b61e5a9d | |||
| ccebd2ff11 | |||
| 6087e04bf3 | |||
| 8079b5c58e | |||
| 10ddab3b1d | |||
| 140fe234fc | |||
| 9dec860d42 | |||
| 247c911c5f |
@@ -8,6 +8,11 @@ before_script:
|
||||
# for some tests
|
||||
- time sudo locale-gen de_DE && sudo locale-gen zh_CN.utf8 && sudo locale-gen fr_FR
|
||||
- time HPHP_HOME=`pwd` make -j 6
|
||||
# mysql configuration for unit-tests
|
||||
- mysql -e 'CREATE DATABASE IF NOT EXISTS hhvm;'
|
||||
- export PDO_MYSQL_TEST_DSN="mysql:host=127.0.0.1;dbname=hhvm"
|
||||
- export PDO_MYSQL_TEST_USER="travis"
|
||||
- export PDO_MYSQL_TEST_PASS=""
|
||||
|
||||
# Test suites take longer to run in RepoAuthoritative mode (-r) than normal so
|
||||
# split out the -r from normal runs and further split the -r runs by suite to
|
||||
|
||||
@@ -3940,6 +3940,10 @@ bool EmitterVisitor::visitImpl(ConstructPtr node) {
|
||||
ClassConstantExpressionPtr cc(
|
||||
static_pointer_cast<ClassConstantExpression>(node));
|
||||
StringData* nName = makeStaticString(cc->getConName());
|
||||
auto const getOriginalClassName = [&] {
|
||||
const std::string& clsName = cc->getOriginalClassName();
|
||||
return makeStaticString(clsName);
|
||||
};
|
||||
if (cc->isStatic()) {
|
||||
// static::Constant
|
||||
e.LateBoundCls();
|
||||
@@ -3953,9 +3957,12 @@ bool EmitterVisitor::visitImpl(ConstructPtr node) {
|
||||
} else if (cc->getOriginalClass() &&
|
||||
!cc->getOriginalClass()->isTrait()) {
|
||||
// C::Constant inside a class
|
||||
const std::string& clsName = cc->getOriginalClassName();
|
||||
StringData* nCls = makeStaticString(clsName);
|
||||
e.ClsCnsD(nName, nCls);
|
||||
auto nCls = getOriginalClassName();
|
||||
if (cc->isColonColonClass()) {
|
||||
e.String(nCls);
|
||||
} else {
|
||||
e.ClsCnsD(nName, nCls);
|
||||
}
|
||||
} else if (cc->isSelf()) {
|
||||
// self::Constant inside trait or pseudomain
|
||||
e.Self();
|
||||
@@ -3971,9 +3978,15 @@ bool EmitterVisitor::visitImpl(ConstructPtr node) {
|
||||
// will set cc->originalClassName to the trait's name for
|
||||
// the isSelf and isParent cases, but self and parent must
|
||||
// be resolved dynamically when used inside of traits.
|
||||
const std::string& clsName = cc->getOriginalClassName();
|
||||
StringData* nCls = makeStaticString(clsName);
|
||||
e.ClsCnsD(nName, nCls);
|
||||
auto nCls = getOriginalClassName();
|
||||
if (cc->isColonColonClass()) {
|
||||
std::ostringstream s;
|
||||
s << "Cannont access " << nCls->data() << "::" << nName->data() <<
|
||||
" when no class scope is active";
|
||||
throw IncludeTimeFatalException(e.getNode(), s.str().c_str());
|
||||
} else {
|
||||
e.ClsCnsD(nName, nCls);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -46,6 +46,7 @@ public:
|
||||
bool isValid() const { return m_valid; }
|
||||
bool isDynamic() const;
|
||||
bool hasClass() const { return m_defScope != 0; }
|
||||
bool isColonColonClass() const { return m_varName == "class"; }
|
||||
private:
|
||||
std::string m_varName;
|
||||
BlockScope *m_defScope;
|
||||
|
||||
+2886
-2895
Diferenças do arquivo suprimidas por serem muito extensas
Carregar Diff
@@ -797,6 +797,30 @@ void Parser::onClassConst(Token &out, Token &cls, Token &name, bool text) {
|
||||
out->exp = con;
|
||||
}
|
||||
|
||||
void Parser::onClassClass(Token &out, Token &cls, Token &name,
|
||||
bool inStaticContext) {
|
||||
if (inStaticContext) {
|
||||
if (cls->same("parent") || cls->same("static")) {
|
||||
PARSE_ERROR(
|
||||
"%s::class cannot be used for compile-time class name resolution",
|
||||
cls->text().c_str()
|
||||
);
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (cls->same("self") || cls->same("parent") || cls->same("static")) {
|
||||
if (cls->same("self") && m_inTrait) {
|
||||
// Sooo... self:: works dynamically for everything in a trait except
|
||||
// for self::CLASS where it returns the trait name. Great...
|
||||
onScalar(out, T_TRAIT_C, cls);
|
||||
} else {
|
||||
onClassConst(out, cls, name, inStaticContext);
|
||||
}
|
||||
} else {
|
||||
onScalar(out, T_STRING, cls);
|
||||
}
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// function/method declaration
|
||||
|
||||
|
||||
@@ -190,6 +190,7 @@ public:
|
||||
void onCollectionPair(Token &out, Token *pairs, Token *name, Token &value);
|
||||
void onUserAttribute(Token &out, Token *attrList, Token &name, Token &value);
|
||||
void onClassConst(Token &out, Token &cls, Token &name, bool text);
|
||||
void onClassClass(Token &out, Token &cls, Token &name, bool text);
|
||||
void fixStaticVars();
|
||||
void onFunctionStart(Token &name, bool doPushComment = true);
|
||||
void onFunction(Token &out, Token *modifier, Token &ret, Token &ref,
|
||||
|
||||
Arquivo executável → Arquivo normal
+7
-2
@@ -2179,6 +2179,9 @@ static_class_constant:
|
||||
| T_XHP_LABEL T_DOUBLE_COLON
|
||||
ident { $1.xhpLabel();
|
||||
_p->onClassConst($$, $1, $3, 1);}
|
||||
| class_namespace_string_typeargs
|
||||
T_DOUBLE_COLON
|
||||
T_CLASS { _p->onClassClass($$, $1, $3, 1);}
|
||||
;
|
||||
|
||||
scalar:
|
||||
@@ -2571,8 +2574,10 @@ variable_list:
|
||||
;
|
||||
|
||||
class_constant:
|
||||
static_class_name
|
||||
T_DOUBLE_COLON ident { _p->onClassConst($$, $1, $3, 0);}
|
||||
static_class_name
|
||||
T_DOUBLE_COLON ident { _p->onClassConst($$, $1, $3, 0);}
|
||||
| static_class_name
|
||||
T_DOUBLE_COLON T_CLASS { _p->onClassClass($$, $1, $3, 0);}
|
||||
;
|
||||
|
||||
/* hack productions -- these allow some extra stuff in hack
|
||||
|
||||
@@ -639,6 +639,10 @@ struct Parser : ParserBase {
|
||||
.setExtra(new OnClassConstEI(text));
|
||||
}
|
||||
|
||||
void onClassClass(Token &out, Token &cls, Token &name, bool text) {
|
||||
onClassConst(out, cls, name, text);
|
||||
}
|
||||
|
||||
void fixStaticVars() { /* TODO */}
|
||||
|
||||
void onFunctionStart(Token& name, bool doPushComment = true) {
|
||||
|
||||
@@ -17,6 +17,8 @@
|
||||
#include "hphp/runtime/base/bstring.h"
|
||||
#include "hphp/util/util.h"
|
||||
|
||||
#include "folly/Portability.h"
|
||||
|
||||
namespace HPHP {
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
@@ -30,14 +32,16 @@ bool bstrcaseeq(const char* left, const char* right, size_t n) {
|
||||
if (left == right) return true;
|
||||
|
||||
// Fast case sensitive comparison, unrolled to do 8 bytes at a time.
|
||||
typedef uint64_t widecmp_t;
|
||||
size_t i = 0;
|
||||
#ifndef FOLLY_SANITIZE_ADDRESS
|
||||
typedef uint64_t widecmp_t;
|
||||
if (n >= sizeof(widecmp_t)) {
|
||||
while (*(const widecmp_t*)(&left[i]) == *(const widecmp_t*)(&right[i])) {
|
||||
i += sizeof(widecmp_t);
|
||||
if (i >= (n - (sizeof(widecmp_t) - 1))) break;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
// Finish whatever is left over.
|
||||
for (; i < n; ++i) {
|
||||
|
||||
@@ -1103,7 +1103,6 @@ AutoloadHandler::Result AutoloadHandler::loadFromMap(const String& name,
|
||||
bool toLower,
|
||||
const T &checkExists) {
|
||||
assert(!m_map.isNull());
|
||||
JIT::VMRegAnchor _;
|
||||
while (true) {
|
||||
CVarRef &type_map = m_map.get()->get(kind);
|
||||
auto const typeMapCell = type_map.asCell();
|
||||
@@ -1118,31 +1117,33 @@ AutoloadHandler::Result AutoloadHandler::loadFromMap(const String& name,
|
||||
fName = m_map_root + fName;
|
||||
}
|
||||
}
|
||||
|
||||
bool initial;
|
||||
VMExecutionContext* ec = g_vmContext;
|
||||
Unit* u = ec->evalInclude(fName.get(), nullptr, &initial);
|
||||
if (u) {
|
||||
if (initial) {
|
||||
TypedValue retval;
|
||||
ec->invokeFunc(&retval, u->getMain(), init_null_variant,
|
||||
nullptr, nullptr, nullptr, nullptr,
|
||||
ExecutionContext::InvokePseudoMain);
|
||||
tvRefcountedDecRef(&retval);
|
||||
try {
|
||||
JIT::VMRegAnchor _;
|
||||
bool initial;
|
||||
VMExecutionContext* ec = g_vmContext;
|
||||
Unit* u = ec->evalInclude(fName.get(), nullptr, &initial);
|
||||
if (u) {
|
||||
if (initial) {
|
||||
TypedValue retval;
|
||||
ec->invokeFunc(&retval, u->getMain(), init_null_variant,
|
||||
nullptr, nullptr, nullptr, nullptr,
|
||||
ExecutionContext::InvokePseudoMain);
|
||||
tvRefcountedDecRef(&retval);
|
||||
}
|
||||
ok = true;
|
||||
}
|
||||
ok = true;
|
||||
}
|
||||
} catch (...) {}
|
||||
}
|
||||
if (ok && checkExists(name)) {
|
||||
return Success;
|
||||
}
|
||||
CVarRef &onFail = m_map.get()->get(s_failure);
|
||||
if (onFail.isNull()) return Failure;
|
||||
CVarRef &func = m_map.get()->get(s_failure);
|
||||
if (func.isNull()) return Failure;
|
||||
// can throw, otherwise
|
||||
// - true means the map was updated. try again
|
||||
// - false means we should stop applying autoloaders (only affects classes)
|
||||
// - anything else means keep going
|
||||
Variant action = vm_call_user_func(onFail, make_packed_array(kind, name));
|
||||
Variant action = vm_call_user_func(func, make_packed_array(kind, name));
|
||||
auto const actionCell = action.asCell();
|
||||
if (actionCell->m_type == KindOfBoolean) {
|
||||
if (actionCell->m_data.num) continue;
|
||||
@@ -1318,8 +1319,10 @@ void AutoloadHandler::removeHandler(CVarRef handler) {
|
||||
// Use find_if instead of remove_if since we know there can only be one match
|
||||
// in the vector.
|
||||
auto const& compareBundles = CompareBundles(cufIter.get());
|
||||
m_handlers.erase(
|
||||
std::find_if(m_handlers.begin(), m_handlers.end(), compareBundles));
|
||||
auto it = std::find_if(m_handlers.begin(), m_handlers.end(), compareBundles);
|
||||
if (it != m_handlers.end()) {
|
||||
m_handlers.erase(it);
|
||||
}
|
||||
}
|
||||
|
||||
void AutoloadHandler::removeAllHandlers() {
|
||||
|
||||
@@ -54,8 +54,6 @@ int64_t VMExecutionContext::s_threadIdxCounter = 0;
|
||||
Mutex VMExecutionContext::s_threadIdxLock;
|
||||
hphp_hash_map<pid_t, int64_t> VMExecutionContext::s_threadIdxMap;
|
||||
|
||||
const StaticString BaseExecutionContext::s_amp("&");
|
||||
|
||||
BaseExecutionContext::BaseExecutionContext() :
|
||||
m_fp(nullptr), m_pc(nullptr),
|
||||
m_transport(nullptr),
|
||||
@@ -69,6 +67,84 @@ BaseExecutionContext::BaseExecutionContext() :
|
||||
|
||||
setRequestMemoryMaxBytes(String(RuntimeOption::RequestMemoryMaxBytes));
|
||||
restoreIncludePath();
|
||||
|
||||
IniSetting::Bind(IniSetting::CORE, "arg_separator.output", "&",
|
||||
ini_on_update_string, ini_get_string,
|
||||
&m_argSeparatorOutput);
|
||||
IniSetting::Bind(IniSetting::CORE, "error_reporting",
|
||||
ini_on_update_int, ini_get_int,
|
||||
&m_errorReportingLevel);
|
||||
IniSetting::Bind(IniSetting::CORE, "memory_limit",
|
||||
[this](const String& value, void* p) {
|
||||
this->setRequestMemoryMaxBytes(value);
|
||||
return true;
|
||||
},
|
||||
ini_get_string,
|
||||
&m_maxMemory);
|
||||
IniSetting::Bind(IniSetting::CORE, "log_errors",
|
||||
[this](const String& value, void* p) {
|
||||
bool log;
|
||||
ini_on_update_bool(value, &log);
|
||||
this->setLogErrors(log);
|
||||
return true;
|
||||
},
|
||||
ini_get_bool_as_int,
|
||||
&m_logErrors);
|
||||
IniSetting::Bind(IniSetting::CORE, "error_log",
|
||||
[this](const String& value, void* p) {
|
||||
this->setErrorLog(value);
|
||||
return true;
|
||||
},
|
||||
ini_get_string,
|
||||
&m_errorLog);
|
||||
IniSetting::Bind(IniSetting::CORE, "include_path",
|
||||
[this](const String& value, void* p) {
|
||||
this->setIncludePath(value);
|
||||
return true;
|
||||
},
|
||||
[this](void*) {
|
||||
return this->getIncludePath();
|
||||
});
|
||||
IniSetting::Bind(IniSetting::CORE, "hphp.compiler_id",
|
||||
ini_on_update_fail,
|
||||
[](void*) {
|
||||
return String(getHphpCompilerId());
|
||||
});
|
||||
IniSetting::Bind(IniSetting::CORE, "hphp.compiler_version",
|
||||
ini_on_update_fail,
|
||||
[](void*) {
|
||||
return String(getHphpCompilerVersion());
|
||||
});
|
||||
IniSetting::Bind(IniSetting::CORE, "hphp.build_id",
|
||||
ini_on_update_fail,
|
||||
ini_get_stdstring,
|
||||
&RuntimeOption::BuildId);
|
||||
IniSetting::Bind(IniSetting::CORE, "file_uploads",
|
||||
ini_on_update_fail, ini_get_bool_as_int,
|
||||
&RuntimeOption::EnableFileUploads);
|
||||
IniSetting::Bind(IniSetting::CORE, "upload_tmp_dir",
|
||||
ini_on_update_fail, ini_get_stdstring,
|
||||
&RuntimeOption::UploadTmpDir);
|
||||
IniSetting::Bind(IniSetting::CORE, "upload_max_filesize",
|
||||
ini_on_update_fail,
|
||||
[](void*) {
|
||||
int uploadMaxFilesize =
|
||||
VirtualHost::GetUploadMaxFileSize() / (1 << 20);
|
||||
return String(uploadMaxFilesize) + "M";
|
||||
});
|
||||
IniSetting::Bind(IniSetting::CORE, "post_max_size",
|
||||
ini_on_update_fail,
|
||||
[](void*) {
|
||||
return String(VirtualHost::GetMaxPostSize());
|
||||
});
|
||||
IniSetting::Bind(IniSetting::CORE, "allow_url_fopen",
|
||||
ini_on_update_fail, ini_get_static_string_1);
|
||||
IniSetting::Bind(IniSetting::CORE, "notice_frequency",
|
||||
ini_on_update_int, ini_get_int,
|
||||
&RuntimeOption::NoticeFrequency);
|
||||
IniSetting::Bind(IniSetting::CORE, "warning_frequency",
|
||||
ini_on_update_int, ini_get_int,
|
||||
&RuntimeOption::WarningFrequency);
|
||||
}
|
||||
|
||||
VMExecutionContext::VMExecutionContext() :
|
||||
|
||||
@@ -19,6 +19,7 @@
|
||||
|
||||
#include "hphp/runtime/base/class-info.h"
|
||||
#include "hphp/runtime/base/complex-types.h"
|
||||
#include "hphp/runtime/base/ini-setting.h"
|
||||
#include "hphp/runtime/server/transport.h"
|
||||
#include "hphp/runtime/base/debuggable.h"
|
||||
#include "hphp/runtime/server/virtual-host.h"
|
||||
@@ -265,6 +266,8 @@ public:
|
||||
m_out = sb;
|
||||
return current;
|
||||
}
|
||||
String getRawPostData() const { return m_rawPostData; }
|
||||
void setRawPostData(String& pd) { m_rawPostData = pd; }
|
||||
|
||||
/**
|
||||
* Request sequences and program execution hooks.
|
||||
@@ -323,11 +326,6 @@ public:
|
||||
void setTimeZone(const String& timezone) { m_timezone = timezone;}
|
||||
String getDefaultTimeZone() const { return m_timezoneDefault;}
|
||||
void setDefaultTimeZone(const String& s) { m_timezoneDefault = s;}
|
||||
String getArgSeparatorOutput() const {
|
||||
if (m_argSeparatorOutput.isNull()) return s_amp;
|
||||
return m_argSeparatorOutput;
|
||||
}
|
||||
void setArgSeparatorOutput(const String& s) { m_argSeparatorOutput = s;}
|
||||
void setThrowAllErrors(bool f) { m_throwAllErrors = f; }
|
||||
bool getThrowAllErrors() const { return m_throwAllErrors; }
|
||||
void setExitCallback(Variant f) { m_exitCallback = f; }
|
||||
@@ -367,6 +365,7 @@ private:
|
||||
int m_protectedLevel;
|
||||
PFUNC_STDOUT m_stdout;
|
||||
void *m_stdoutData;
|
||||
String m_rawPostData;
|
||||
|
||||
// request handlers
|
||||
std::set<RequestEventHandler*> m_requestEventHandlerSet;
|
||||
|
||||
+105
-140
@@ -28,9 +28,24 @@
|
||||
#include "hphp/runtime/ext/extension.h"
|
||||
#include "hphp/util/lock.h"
|
||||
|
||||
#define PHP_INI_USER 1
|
||||
#define PHP_INI_PERDIR (1<<1)
|
||||
#define PHP_INI_SYSTEM (1<<2)
|
||||
#define PHP_INI_ALL (PHP_INI_USER|PHP_INI_PERDIR|PHP_INI_SYSTEM)
|
||||
|
||||
namespace HPHP {
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
const Extension* IniSetting::CORE = (Extension*)(-1);
|
||||
|
||||
const StaticString
|
||||
s_1("1"),
|
||||
s_0("0"),
|
||||
s_global_value("global_value"),
|
||||
s_local_value("local_value"),
|
||||
s_access("access"),
|
||||
s_core("core");
|
||||
|
||||
bool ini_on_update_bool(const String& value, void *p) {
|
||||
if (p) {
|
||||
if ((value.size() == 2 && strcasecmp("on", value.data()) == 0) ||
|
||||
@@ -44,6 +59,13 @@ bool ini_on_update_bool(const String& value, void *p) {
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ini_on_update_int(const String& value, void *p) {
|
||||
if (p) {
|
||||
*((int*)p) = value.toInt32();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ini_on_update_long(const String& value, void *p) {
|
||||
if (p) {
|
||||
*((int64_t*)p) = value.toInt64();
|
||||
@@ -69,19 +91,16 @@ bool ini_on_update_real(const String& value, void *p) {
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ini_on_update_string(const String& value, void *p) {
|
||||
bool ini_on_update_stdstring(const String& value, void *p) {
|
||||
if (p) {
|
||||
*((std::string*)p) = std::string(value.data(), value.size());
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ini_on_update_string_non_empty(const String& value, void *p) {
|
||||
if (value.empty()) {
|
||||
return false;
|
||||
}
|
||||
bool ini_on_update_string(const String& value, void *p) {
|
||||
if (p) {
|
||||
*((std::string*)p) = std::string(value.data(), value.size());
|
||||
*((String*)p) = value;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
@@ -90,6 +109,17 @@ String ini_get_bool(void *p) {
|
||||
return *(bool*) p;
|
||||
}
|
||||
|
||||
String ini_get_bool_as_int(void* p) {
|
||||
if (*((bool*)p)) {
|
||||
return s_1;
|
||||
}
|
||||
return s_0;
|
||||
}
|
||||
|
||||
String ini_get_int(void *p) {
|
||||
return *((int*)p);
|
||||
}
|
||||
|
||||
String ini_get_long(void *p) {
|
||||
return *((int64_t*)p);
|
||||
}
|
||||
@@ -99,9 +129,17 @@ String ini_get_real(void *p) {
|
||||
}
|
||||
|
||||
String ini_get_string(void *p) {
|
||||
return *((String*)p);
|
||||
}
|
||||
|
||||
String ini_get_stdstring(void *p) {
|
||||
return *((std::string*)p);
|
||||
}
|
||||
|
||||
String ini_get_static_string_1(void* p) {
|
||||
return s_1;
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// callbacks for creating arrays out of ini
|
||||
|
||||
@@ -184,6 +222,7 @@ Variant IniSetting::FromString(const String& ini, const String& filename,
|
||||
}
|
||||
|
||||
struct IniCallbackData {
|
||||
const Extension* extension;
|
||||
IniSetting::UpdateCallback updateCallback;
|
||||
IniSetting::GetCallback getCallback;
|
||||
void *p;
|
||||
@@ -203,17 +242,28 @@ void IniSetting::SetGlobalDefault(const char *name, const char *value) {
|
||||
s_global_ini[name] = value;
|
||||
}
|
||||
|
||||
void IniSetting::Bind(const char *name, const char *value,
|
||||
void IniSetting::Bind(const Extension* extension,
|
||||
const char *name, const char *value,
|
||||
UpdateCallback updateCallback, GetCallback getCallback,
|
||||
void *p /* = NULL */) {
|
||||
assert(value);
|
||||
|
||||
Bind(extension, name, updateCallback, getCallback, p);
|
||||
|
||||
updateCallback(value, p);
|
||||
}
|
||||
|
||||
void IniSetting::Bind(const Extension* extension,
|
||||
const char *name,
|
||||
UpdateCallback updateCallback, GetCallback getCallback,
|
||||
void *p /* = NULL */) {
|
||||
assert(name && *name);
|
||||
assert(value);
|
||||
|
||||
auto &data = (*s_callbacks)[name];
|
||||
data.extension = extension;
|
||||
data.updateCallback = updateCallback;
|
||||
data.getCallback = getCallback;
|
||||
data.p = p;
|
||||
(*updateCallback)(value, p);
|
||||
}
|
||||
|
||||
void IniSetting::Unbind(const char *name) {
|
||||
@@ -221,102 +271,7 @@ void IniSetting::Unbind(const char *name) {
|
||||
s_callbacks->erase(name);
|
||||
}
|
||||
|
||||
const StaticString
|
||||
s_allow_url_fopen("allow_url_fopen"),
|
||||
s_error_reporting("error_reporting"),
|
||||
s_memory_limit("memory_limit"),
|
||||
s_max_execution_time("max_execution_time"),
|
||||
s_maximum_execution_time("maximum_execution_time"),
|
||||
s_hphp_build_id("hphp.build_id"),
|
||||
s_hphp_compiler_version("hphp.compiler_version"),
|
||||
s_hphp_compiler_id("hphp.compiler_id"),
|
||||
s_arg_separator_output("arg_separator.output"),
|
||||
s_file_uploads("file_uploads"),
|
||||
s_upload_tmp_dir("upload_tmp_dir"),
|
||||
s_upload_max_filesize("upload_max_filesize"),
|
||||
s_post_max_size("post_max_size"),
|
||||
s_log_errors("log_errors"),
|
||||
s_error_log("error_log"),
|
||||
s_notice_frequency("notice_frequency"),
|
||||
s_warning_frequency("warning_frequency"),
|
||||
s_include_path("include_path"),
|
||||
s_1("1"),
|
||||
s_0("0");
|
||||
|
||||
bool IniSetting::Get(const String& name, String &value) {
|
||||
if (name == s_error_reporting) {
|
||||
value = String((int64_t)g_context->getErrorReportingLevel());
|
||||
return true;
|
||||
}
|
||||
if (name == s_memory_limit) {
|
||||
value = g_context->getRequestMemoryMaxBytes();
|
||||
return true;
|
||||
}
|
||||
if (name == s_max_execution_time || name == s_maximum_execution_time) {
|
||||
int64_t timeout = ThreadInfo::s_threadInfo.getNoCheck()->
|
||||
m_reqInjectionData.getTimeout();
|
||||
value = String(timeout);
|
||||
return true;
|
||||
}
|
||||
if (name == s_hphp_build_id) {
|
||||
value = String(RuntimeOption::BuildId);
|
||||
return true;
|
||||
}
|
||||
if (name == s_hphp_compiler_version) {
|
||||
value = String(getHphpCompilerVersion());
|
||||
return true;
|
||||
}
|
||||
if (name == s_hphp_compiler_id) {
|
||||
value = String(getHphpCompilerId());
|
||||
return true;
|
||||
}
|
||||
if (name == s_arg_separator_output) {
|
||||
value = g_context->getArgSeparatorOutput();
|
||||
return true;
|
||||
}
|
||||
if (name == s_file_uploads) {
|
||||
value = RuntimeOption::EnableFileUploads ? s_1 : s_0;
|
||||
return true;
|
||||
}
|
||||
if (name == s_upload_tmp_dir) {
|
||||
value = String(RuntimeOption::UploadTmpDir);
|
||||
return true;
|
||||
}
|
||||
if (name == s_upload_max_filesize) {
|
||||
int uploadMaxFilesize = VirtualHost::GetUploadMaxFileSize() / (1 << 20);
|
||||
value = String(uploadMaxFilesize) + "M";
|
||||
return true;
|
||||
}
|
||||
if (name == s_post_max_size) {
|
||||
int postMaxSize = VirtualHost::GetMaxPostSize();
|
||||
value = String(postMaxSize);
|
||||
return true;
|
||||
}
|
||||
if (name == s_log_errors) {
|
||||
value = g_context->getLogErrors() ? s_1 : s_0;
|
||||
return true;
|
||||
}
|
||||
if (name == s_error_log) {
|
||||
value = g_context->getErrorLog();
|
||||
return true;
|
||||
}
|
||||
if (name == s_notice_frequency) {
|
||||
value = String((int64_t)RuntimeOption::NoticeFrequency);
|
||||
return true;
|
||||
}
|
||||
if (name == s_warning_frequency) {
|
||||
value = String((int64_t)RuntimeOption::WarningFrequency);
|
||||
return true;
|
||||
}
|
||||
if (name == s_include_path) {
|
||||
value = g_context->getIncludePath();
|
||||
return true;
|
||||
}
|
||||
if (name == s_allow_url_fopen) {
|
||||
value = s_1;
|
||||
return true;
|
||||
}
|
||||
|
||||
DefaultMap::iterator iter = s_global_ini.find(name.data());
|
||||
if (iter != s_global_ini.end()) {
|
||||
value = iter->second;
|
||||
@@ -325,7 +280,7 @@ bool IniSetting::Get(const String& name, String &value) {
|
||||
|
||||
CallbackMap::iterator cb_iter = s_callbacks->find(name.data());
|
||||
if (cb_iter != s_callbacks->end()) {
|
||||
value = (*cb_iter->second.getCallback)(cb_iter->second.p);
|
||||
value = cb_iter->second.getCallback(cb_iter->second.p);
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -335,46 +290,56 @@ bool IniSetting::Get(const String& name, String &value) {
|
||||
bool IniSetting::Set(const String& name, const String& value) {
|
||||
CallbackMap::iterator iter = s_callbacks->find(name.data());
|
||||
if (iter != s_callbacks->end()) {
|
||||
return (*iter->second.updateCallback)(value, iter->second.p);
|
||||
}
|
||||
|
||||
if (name == s_error_reporting) {
|
||||
g_context->setErrorReportingLevel(value.toInt64());
|
||||
return true;
|
||||
} else if (name == s_memory_limit) {
|
||||
if (!value.empty()) {
|
||||
g_context->setRequestMemoryMaxBytes(value);
|
||||
return true;
|
||||
if (iter->second.updateCallback) {
|
||||
return iter->second.updateCallback(value, iter->second.p);
|
||||
}
|
||||
} else if (name == s_max_execution_time || name == s_maximum_execution_time) {
|
||||
int64_t limit = value.toInt64();
|
||||
ThreadInfo::s_threadInfo.getNoCheck()->
|
||||
m_reqInjectionData.setTimeout(limit);
|
||||
return true;
|
||||
} else if (name == s_arg_separator_output) {
|
||||
g_context->setArgSeparatorOutput(value);
|
||||
return true;
|
||||
} else if (name == s_log_errors) {
|
||||
bool log;
|
||||
ini_on_update_bool(value, &log);
|
||||
g_context->setLogErrors(log);
|
||||
return true;
|
||||
} else if (name == s_error_log) {
|
||||
g_context->setErrorLog(value);
|
||||
return true;
|
||||
} else if (name == s_notice_frequency) {
|
||||
RuntimeOption::NoticeFrequency = value.toInt64();
|
||||
return true;
|
||||
} else if (name == s_warning_frequency) {
|
||||
RuntimeOption::WarningFrequency = value.toInt64();
|
||||
return true;
|
||||
} else if (name == s_include_path) {
|
||||
g_context->setIncludePath(value);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
Array IniSetting::GetAll(const String& ext_name, bool details) {
|
||||
Array r = Array::Create();
|
||||
|
||||
const Extension* ext = nullptr;
|
||||
if (!ext_name.empty()) {
|
||||
if (ext_name == s_core) {
|
||||
ext = IniSetting::CORE;
|
||||
} else {
|
||||
ext = Extension::GetExtension(ext_name);
|
||||
if (!ext) {
|
||||
raise_warning("Unable to find extension '%s'",
|
||||
ext_name.toCppString().c_str());
|
||||
return r;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (auto& iter: (*s_callbacks)) {
|
||||
if (ext && ext != iter.second.extension) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (details) {
|
||||
Array item = Array::Create();
|
||||
String value(iter.second.getCallback(iter.second.p));
|
||||
item.add(s_global_value, value);
|
||||
item.add(s_local_value, value);
|
||||
// HHVM doesn't support varying access levels, but we can at least
|
||||
// indicate if ini_set() should work
|
||||
if (iter.second.updateCallback) {
|
||||
item.add(s_access, Variant(PHP_INI_ALL));
|
||||
} else {
|
||||
item.add(s_access, Variant(PHP_INI_SYSTEM | PHP_INI_PERDIR));
|
||||
}
|
||||
r.add(String(iter.first), item);
|
||||
} else {
|
||||
r.add(String(iter.first), iter.second.getCallback(iter.second.p));
|
||||
}
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
}
|
||||
|
||||
@@ -22,8 +22,11 @@
|
||||
namespace HPHP {
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
class Extension;
|
||||
|
||||
class IniSetting {
|
||||
public:
|
||||
static const Extension* CORE;
|
||||
enum ScannerMode {
|
||||
NormalScanner,
|
||||
RawScanner,
|
||||
@@ -38,8 +41,8 @@ public:
|
||||
typedef void (*PFN_PARSER_CALLBACK)(String *arg1, String *arg2, String *arg3,
|
||||
int callback_type, void *arg);
|
||||
|
||||
typedef bool (*UpdateCallback)(const String& value, void *p);
|
||||
typedef String (*GetCallback)(void *p);
|
||||
typedef std::function<bool(const String& value, void*p)> UpdateCallback;
|
||||
typedef std::function<String(void* p)> GetCallback;
|
||||
|
||||
public:
|
||||
static Variant FromString(const String& ini, const String& filename,
|
||||
@@ -47,8 +50,14 @@ public:
|
||||
|
||||
static bool Get(const String& name, String &value);
|
||||
static bool Set(const String& name, const String& value);
|
||||
static Array GetAll(const String& extension, bool details);
|
||||
|
||||
static void Bind(const char *name, const char *value,
|
||||
static void Bind(const Extension* extension,
|
||||
const char *name, const char *value,
|
||||
UpdateCallback updateCallback, GetCallback getCallback,
|
||||
void *p = nullptr);
|
||||
static void Bind(const Extension* extension,
|
||||
const char *name,
|
||||
UpdateCallback updateCallback, GetCallback getCallback,
|
||||
void *p = nullptr);
|
||||
static void Unbind(const char *name);
|
||||
@@ -57,17 +66,23 @@ public:
|
||||
|
||||
};
|
||||
|
||||
#define ini_on_update_fail HPHP::IniSetting::UpdateCallback()
|
||||
bool ini_on_update_int(const String& value, void *p);
|
||||
bool ini_on_update_bool(const String& value, void *p);
|
||||
bool ini_on_update_long(const String& value, void *p);
|
||||
bool ini_on_update_non_negative(const String& value, void *p);
|
||||
bool ini_on_update_real(const String& value, void *p);
|
||||
bool ini_on_update_stdstring(const String& value, void *p);
|
||||
bool ini_on_update_string(const String& value, void *p);
|
||||
bool ini_on_update_string_non_empty(const String& value, void *p);
|
||||
|
||||
String ini_get_int(void *p);
|
||||
String ini_get_bool(void *p);
|
||||
String ini_get_bool_as_int(void *p);
|
||||
String ini_get_long(void *p);
|
||||
String ini_get_real(void *p);
|
||||
String ini_get_string(void *p);
|
||||
String ini_get_stdstring(void *p);
|
||||
String ini_get_static_string_1(void *p);
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
}
|
||||
|
||||
@@ -20,6 +20,7 @@
|
||||
#include "hphp/runtime/base/temp-file.h"
|
||||
#include "hphp/runtime/base/mem-file.h"
|
||||
#include "hphp/runtime/base/output-file.h"
|
||||
#include "hphp/runtime/server/http-protocol.h"
|
||||
#include <memory>
|
||||
|
||||
namespace HPHP {
|
||||
@@ -82,15 +83,8 @@ File* PhpStreamWrapper::open(const String& filename, const String& mode,
|
||||
}
|
||||
|
||||
if (!strcasecmp(req, "input")) {
|
||||
Transport *transport = g_context->getTransport();
|
||||
if (transport) {
|
||||
int size = 0;
|
||||
const void *data = transport->getPostData(size);
|
||||
if (data && size) {
|
||||
return NEWOBJ(MemFile)((const char *)data, size);
|
||||
}
|
||||
}
|
||||
return NEWOBJ(MemFile)(nullptr, 0);
|
||||
auto raw_post = g_context->getRawPostData();
|
||||
return NEWOBJ(MemFile)(raw_post.c_str(), raw_post.size());
|
||||
}
|
||||
|
||||
if (!strcasecmp(req, "output")) {
|
||||
|
||||
@@ -157,18 +157,6 @@ static __thread int t_last_error_code;
|
||||
|
||||
namespace {
|
||||
|
||||
void preg_init_thread_locals() {
|
||||
IniSetting::Bind("pcre.backtrack_limit",
|
||||
std::to_string(RuntimeOption::PregBacktraceLimit).c_str(),
|
||||
ini_on_update_long, ini_get_long,
|
||||
&g_context->m_preg_backtrace_limit);
|
||||
IniSetting::Bind("pcre.recursion_limit",
|
||||
std::to_string(RuntimeOption::PregRecursionLimit).c_str(),
|
||||
ini_on_update_long, ini_get_long,
|
||||
&g_context->m_preg_recursion_limit);
|
||||
}
|
||||
InitFiniNode init(preg_init_thread_locals, InitFiniNode::When::ThreadInit);
|
||||
|
||||
template<bool useSmartFree = false>
|
||||
struct FreeHelperImpl : private boost::noncopyable {
|
||||
explicit FreeHelperImpl(void* p) : p(p) {}
|
||||
|
||||
@@ -989,8 +989,9 @@ static int execute_program_impl(int argc, char** argv) {
|
||||
desc.add_options()
|
||||
("help", "display this message")
|
||||
("version", "display version number")
|
||||
("compiler-id", "display the git hash for the compiler id")
|
||||
("repo-schema", "display the repo schema id used by this app")
|
||||
("php", "emulate the standard php command line")
|
||||
("compiler-id", "display the git hash for the compiler")
|
||||
("repo-schema", "display the repository schema id")
|
||||
("mode,m", value<string>(&po.mode)->default_value("run"),
|
||||
"run | debug (d) | server (s) | daemon | replay | translate (t)")
|
||||
("config,c", value<string>(&po.config),
|
||||
|
||||
@@ -106,6 +106,7 @@ std::string RuntimeOption::Host;
|
||||
std::string RuntimeOption::DefaultServerNameSuffix;
|
||||
std::string RuntimeOption::ServerType = "libevent";
|
||||
std::string RuntimeOption::ServerIP;
|
||||
std::string RuntimeOption::ServerFileSocket;
|
||||
std::string RuntimeOption::ServerPrimaryIP;
|
||||
int RuntimeOption::ServerPort;
|
||||
int RuntimeOption::ServerPortFd = -1;
|
||||
@@ -730,6 +731,7 @@ void RuntimeOption::Load(Hdf &config,
|
||||
DefaultServerNameSuffix = server["DefaultServerNameSuffix"].getString();
|
||||
ServerType = server["Type"].getString(ServerType);
|
||||
ServerIP = server["IP"].getString();
|
||||
ServerFileSocket = server["FileSocket"].getString();
|
||||
ServerPrimaryIP = Util::GetPrimaryIP();
|
||||
ServerPort = server["Port"].getUInt16(80);
|
||||
ServerBacklog = server["Backlog"].getInt16(128);
|
||||
|
||||
@@ -107,6 +107,7 @@ public:
|
||||
static std::string DefaultServerNameSuffix;
|
||||
static std::string ServerType;
|
||||
static std::string ServerIP;
|
||||
static std::string ServerFileSocket;
|
||||
static std::string ServerPrimaryIP;
|
||||
static int ServerPort;
|
||||
static int ServerPortFd;
|
||||
|
||||
@@ -37,6 +37,9 @@ public:
|
||||
|
||||
/*
|
||||
* Efficient string concatenation.
|
||||
*
|
||||
* StringBuffer is designed not to contain any malloc()d memory (only
|
||||
* per-request smart allocated memory) based on sweeping-related assumptions.
|
||||
*/
|
||||
struct StringBuffer {
|
||||
static const int kDefaultOutputLimit = StringData::MaxSize;
|
||||
|
||||
@@ -24,6 +24,7 @@
|
||||
#include "hphp/runtime/base/types.h"
|
||||
#include "hphp/runtime/base/hphp-system.h"
|
||||
#include "hphp/runtime/base/code-coverage.h"
|
||||
#include "hphp/runtime/base/ini-setting.h"
|
||||
#include "hphp/runtime/base/rds.h"
|
||||
#include "hphp/util/lock.h"
|
||||
#include "hphp/util/alloc.h"
|
||||
@@ -41,6 +42,19 @@ __thread char* ThreadInfo::t_stackbase = 0;
|
||||
|
||||
IMPLEMENT_THREAD_LOCAL_NO_CHECK(ThreadInfo, ThreadInfo::s_threadInfo);
|
||||
|
||||
String ini_get_max_execution_time(void*) {
|
||||
int64_t timeout = ThreadInfo::s_threadInfo.getNoCheck()->
|
||||
m_reqInjectionData.getTimeout();
|
||||
return String(timeout);
|
||||
}
|
||||
|
||||
bool ini_on_update_max_execution_time(const String& value, void*) {
|
||||
int64_t limit = value.toInt64();
|
||||
ThreadInfo::s_threadInfo.getNoCheck()->
|
||||
m_reqInjectionData.setTimeout(limit);
|
||||
return true;
|
||||
}
|
||||
|
||||
ThreadInfo::ThreadInfo()
|
||||
: m_stacklimit(0), m_executing(Idling) {
|
||||
assert(!t_stackbase);
|
||||
@@ -55,6 +69,13 @@ ThreadInfo::ThreadInfo()
|
||||
RDS::threadInit();
|
||||
onSessionInit();
|
||||
|
||||
IniSetting::Bind(IniSetting::CORE, "max_execution_time",
|
||||
ini_on_update_max_execution_time,
|
||||
ini_get_max_execution_time);
|
||||
IniSetting::Bind(IniSetting::CORE, "maximum_execution_time",
|
||||
ini_on_update_max_execution_time,
|
||||
ini_get_max_execution_time);
|
||||
|
||||
Lock lock(s_thread_info_mutex);
|
||||
s_thread_infos.insert(this);
|
||||
}
|
||||
|
||||
@@ -23,7 +23,6 @@
|
||||
|
||||
namespace HPHP {
|
||||
|
||||
IMPLEMENT_OBJECT_ALLOCATION(UrlFile)
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
const StaticString s_http_response_header("http_response_header");
|
||||
@@ -43,6 +42,12 @@ UrlFile::UrlFile(const char *method /* = "GET" */,
|
||||
m_isLocal = false;
|
||||
}
|
||||
|
||||
void UrlFile::sweep() {
|
||||
using std::string;
|
||||
m_error.~string();
|
||||
MemFile::sweep();
|
||||
}
|
||||
|
||||
const StaticString
|
||||
s_remove_user_pass_pattern("#://[^@]+@#"),
|
||||
s_remove_user_pass_replace("://");
|
||||
|
||||
@@ -480,13 +480,13 @@ int string_rfind(const char *input, int len, const char *s, int s_len,
|
||||
if (pos >= 0) {
|
||||
ptr = bstrrstr(input + pos, len - pos, s, s_len);
|
||||
} else {
|
||||
ptr = bstrrstr(input, len + pos + 1, s, s_len);
|
||||
ptr = bstrrstr(input, len + pos + s_len, s, s_len);
|
||||
}
|
||||
} else {
|
||||
if (pos >= 0) {
|
||||
ptr = bstrrcasestr(input + pos, len - pos, s, s_len);
|
||||
} else {
|
||||
ptr = bstrrcasestr(input, len + pos + 1, s, s_len);
|
||||
ptr = bstrrcasestr(input, len + pos + s_len, s, s_len);
|
||||
}
|
||||
}
|
||||
if (ptr != nullptr) {
|
||||
|
||||
@@ -286,18 +286,22 @@ static const int loose_state_transition_table[31][31] = {
|
||||
/*</fb>*/
|
||||
|
||||
|
||||
#define JSON_PARSER_MAX_DEPTH 512
|
||||
#define JSON_PARSER_DEFAULT_DEPTH 512
|
||||
|
||||
/**
|
||||
* A stack maintains the states of nested structures.
|
||||
*/
|
||||
struct json_parser {
|
||||
int the_stack[JSON_PARSER_MAX_DEPTH];
|
||||
Variant the_zstack[JSON_PARSER_MAX_DEPTH];
|
||||
String the_kstack[JSON_PARSER_MAX_DEPTH];
|
||||
std::vector<int> the_stack;
|
||||
std::vector<Variant> the_zstack;
|
||||
std::vector<String> the_kstack;
|
||||
int the_top;
|
||||
int the_mark; // the watermark
|
||||
int depth;
|
||||
json_error_codes error_code;
|
||||
json_parser() : the_stack(JSON_PARSER_DEFAULT_DEPTH),
|
||||
the_zstack(JSON_PARSER_DEFAULT_DEPTH),
|
||||
the_kstack(JSON_PARSER_DEFAULT_DEPTH) {};
|
||||
};
|
||||
|
||||
|
||||
@@ -365,7 +369,7 @@ private:
|
||||
* Push a mode onto the stack. Return false if there is overflow.
|
||||
*/
|
||||
static int push(json_parser *json, int mode) {
|
||||
if (json->the_top + 1 >= JSON_PARSER_MAX_DEPTH) {
|
||||
if (json->the_top + 1 >= json->depth) {
|
||||
return false;
|
||||
}
|
||||
json->the_top += 1;
|
||||
@@ -397,10 +401,12 @@ static int dehexchar(char c) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
static void json_create_zval(Variant &z, StringBuffer &buf, int type) {
|
||||
static void json_create_zval(Variant &z, StringBuffer &buf, int type,
|
||||
int64_t options) {
|
||||
switch (type) {
|
||||
case KindOfInt64:
|
||||
{
|
||||
bool bigint = false;
|
||||
const char *p = buf.data();
|
||||
assert(p);
|
||||
if (p == NULL) {
|
||||
@@ -416,15 +422,22 @@ static void json_create_zval(Variant &z, StringBuffer &buf, int type) {
|
||||
if (len == MAX_LENGTH_OF_LONG - 1) {
|
||||
int cmp = strcmp(p + (neg ? 1 : 0), long_min_digits);
|
||||
if (!(cmp < 0 || (cmp == 0 && neg))) {
|
||||
z = strtod(p, NULL);
|
||||
return;
|
||||
bigint = true;
|
||||
}
|
||||
} else {
|
||||
z = strtod(p, NULL);
|
||||
return;
|
||||
bigint = true;
|
||||
}
|
||||
}
|
||||
z = int64_t(strtoll(buf.data(), NULL, 10));
|
||||
|
||||
if (bigint) {
|
||||
if (options & k_JSON_BIGINT_AS_STRING) {
|
||||
z = buf.detach();
|
||||
} else {
|
||||
z = strtod(p, NULL);
|
||||
}
|
||||
} else {
|
||||
z = int64_t(strtoll(buf.data(), nullptr, 10));
|
||||
}
|
||||
}
|
||||
break;
|
||||
case KindOfDouble:
|
||||
@@ -520,8 +533,8 @@ static void attach_zval(json_parser *json, const String& key,
|
||||
* It is implemented as a Pushdown Automaton; that means it is a finite state
|
||||
* machine with a stack.
|
||||
*/
|
||||
bool JSON_parser(Variant &z, const char *p, int length, bool assoc/*<fb>*/,
|
||||
int64_t options/*</fb>*/) {
|
||||
bool JSON_parser(Variant &z, const char *p, int length, bool assoc,
|
||||
int depth, int64_t options) {
|
||||
int b; /* the next character */
|
||||
int c; /* the next character class */
|
||||
int s; /* the next state */
|
||||
@@ -549,6 +562,16 @@ bool JSON_parser(Variant &z, const char *p, int length, bool assoc/*<fb>*/,
|
||||
int type = -1;
|
||||
unsigned short utf16 = 0;
|
||||
|
||||
JSON(depth) = depth;
|
||||
// Since the stack is maintainined on a per request basis, for performance
|
||||
// reasons, it only makes sense to expand if necessary and cycles are wasted
|
||||
// contracting. Calls with a depth other than default should be rare.
|
||||
if (depth > JSON(the_stack).size()) {
|
||||
JSON(the_stack).resize(depth);
|
||||
JSON(the_zstack).resize(depth);
|
||||
JSON(the_kstack).resize(depth);
|
||||
}
|
||||
|
||||
JSON(the_mark) = JSON(the_top) = -1;
|
||||
push(the_json, MODE_DONE);
|
||||
|
||||
@@ -567,7 +590,7 @@ bool JSON_parser(Variant &z, const char *p, int length, bool assoc/*<fb>*/,
|
||||
c = byte_class[b];
|
||||
/*</fb>*/
|
||||
if (c <= S_ERR) {
|
||||
s_json_parser->error_code = JSON_ERROR_STATE_MISMATCH;
|
||||
s_json_parser->error_code = JSON_ERROR_CTRL_CHAR;
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
@@ -614,6 +637,7 @@ bool JSON_parser(Variant &z, const char *p, int length, bool assoc/*<fb>*/,
|
||||
*/
|
||||
case -8:
|
||||
if (!push(the_json, MODE_KEY)) {
|
||||
s_json_parser->error_code = JSON_ERROR_DEPTH;
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -667,7 +691,7 @@ bool JSON_parser(Variant &z, const char *p, int length, bool assoc/*<fb>*/,
|
||||
if (type != -1 &&
|
||||
JSON(the_stack)[JSON(the_top)] == MODE_OBJECT) {
|
||||
Variant mval;
|
||||
json_create_zval(mval, *buf, type);
|
||||
json_create_zval(mval, *buf, type, options);
|
||||
Variant &top = JSON(the_zstack)[JSON(the_top)];
|
||||
object_set(top, key->detach(), mval, assoc);
|
||||
buf->clear();
|
||||
@@ -677,6 +701,7 @@ bool JSON_parser(Variant &z, const char *p, int length, bool assoc/*<fb>*/,
|
||||
attach_zval(the_json, JSON(the_kstack)[JSON(the_top)], assoc);
|
||||
|
||||
if (!pop(the_json, MODE_OBJECT)) {
|
||||
s_json_parser->error_code = JSON_ERROR_STATE_MISMATCH;
|
||||
return false;
|
||||
}
|
||||
the_state = 9;
|
||||
@@ -686,6 +711,7 @@ bool JSON_parser(Variant &z, const char *p, int length, bool assoc/*<fb>*/,
|
||||
*/
|
||||
case -6:
|
||||
if (!push(the_json, MODE_ARRAY)) {
|
||||
s_json_parser->error_code = JSON_ERROR_DEPTH;
|
||||
return false;
|
||||
}
|
||||
the_state = 2;
|
||||
@@ -716,7 +742,7 @@ bool JSON_parser(Variant &z, const char *p, int length, bool assoc/*<fb>*/,
|
||||
if (type != -1 &&
|
||||
JSON(the_stack)[JSON(the_top)] == MODE_ARRAY) {
|
||||
Variant mval;
|
||||
json_create_zval(mval, *buf, type);
|
||||
json_create_zval(mval, *buf, type, options);
|
||||
JSON(the_zstack)[JSON(the_top)].append(mval);
|
||||
buf->clear();
|
||||
JSON_RESET_TYPE();
|
||||
@@ -725,6 +751,7 @@ bool JSON_parser(Variant &z, const char *p, int length, bool assoc/*<fb>*/,
|
||||
attach_zval(the_json, JSON(the_kstack[JSON(the_top)]), assoc);
|
||||
|
||||
if (!pop(the_json, MODE_ARRAY)) {
|
||||
s_json_parser->error_code = JSON_ERROR_STATE_MISMATCH;
|
||||
return false;
|
||||
}
|
||||
the_state = 9;
|
||||
@@ -765,7 +792,7 @@ bool JSON_parser(Variant &z, const char *p, int length, bool assoc/*<fb>*/,
|
||||
if (type != -1 &&
|
||||
(JSON(the_stack)[JSON(the_top)] == MODE_OBJECT ||
|
||||
JSON(the_stack)[JSON(the_top)] == MODE_ARRAY)) {
|
||||
json_create_zval(mval, *buf, type);
|
||||
json_create_zval(mval, *buf, type, options);
|
||||
}
|
||||
|
||||
switch (JSON(the_stack)[JSON(the_top)]) {
|
||||
|
||||
@@ -25,7 +25,7 @@ namespace HPHP {
|
||||
|
||||
void utf16_to_utf8(HPHP::StringBuffer &buf, unsigned short utf16);
|
||||
bool JSON_parser(HPHP::Variant &z, const char *p, int length,
|
||||
bool assoc/*<fb>*/, int64_t options/*</fb>*/);
|
||||
bool assoc, int depth, int64_t options);
|
||||
|
||||
enum json_error_codes {
|
||||
JSON_ERROR_NONE = 0,
|
||||
|
||||
@@ -235,7 +235,8 @@ class bcmathExtension : public Extension {
|
||||
public:
|
||||
bcmathExtension() : Extension("bcmath", NO_EXTENSION_VERSION_YET) {}
|
||||
virtual void moduleInit() {
|
||||
IniSetting::Bind("bcmath.scale", "0", ini_on_update_long, ini_get_long,
|
||||
IniSetting::Bind(this, "bcmath.scale", "0",
|
||||
ini_on_update_long, ini_get_long,
|
||||
&BCG(bc_precision));
|
||||
|
||||
HHVM_FE(bcscale);
|
||||
|
||||
@@ -26,7 +26,7 @@ static class DateExtension : public Extension {
|
||||
DateExtension() : Extension("date", k_PHP_VERSION.c_str()) { }
|
||||
void moduleInit() {
|
||||
IniSetting::Bind(
|
||||
"date.timezone",
|
||||
this, "date.timezone",
|
||||
g_context->getDefaultTimeZone().c_str(),
|
||||
dateTimezoneIniUpdate, dateTimezoneIniGet,
|
||||
nullptr
|
||||
|
||||
@@ -1035,7 +1035,7 @@ static xmlNodePtr php_dom_free_xinclude_node(xmlNodePtr cur) {
|
||||
xincnode = cur;
|
||||
cur = cur->next;
|
||||
xmlUnlinkNode(xincnode);
|
||||
php_libxml_node_free_resource(xincnode);
|
||||
xmlFreeNode(xincnode);
|
||||
return cur;
|
||||
}
|
||||
|
||||
@@ -1787,7 +1787,14 @@ static Variant domnode_ownerdocument_read(CObjRef obj) {
|
||||
nodep->type == XML_HTML_DOCUMENT_NODE) {
|
||||
return uninit_null();
|
||||
}
|
||||
return create_node_object((xmlNodePtr)nodep->doc, domnode->doc());
|
||||
if ((xmlNodePtr) nodep->doc == domnode->doc()->m_node) {
|
||||
return domnode->doc();
|
||||
} else {
|
||||
// The node wasn't created by this extension, so doesn't already have
|
||||
// a DOMDocument - make one. dom_import_xml() is one way for this to
|
||||
// happen.
|
||||
return create_node_object((xmlNodePtr) nodep->doc, domnode->doc());
|
||||
}
|
||||
}
|
||||
|
||||
static Variant domnode_namespaceuri_read(CObjRef obj) {
|
||||
|
||||
@@ -79,6 +79,8 @@ IMPLEMENT_DEFAULT_EXTENSION_VERSION(xhprof, 0.9.4);
|
||||
using std::vector;
|
||||
using std::string;
|
||||
|
||||
const StaticString s_hotprofiler("hotprofiler");
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// helpers
|
||||
|
||||
@@ -1017,7 +1019,9 @@ class TraceProfiler : public Profiler {
|
||||
} else {
|
||||
char buf[20];
|
||||
sprintf(buf, "%d", RuntimeOption::ProfilerMaxTraceBuffer);
|
||||
IniSetting::Bind("profiler.max_trace_buffer", buf,
|
||||
Extension* ext = Extension::GetExtension(s_hotprofiler);
|
||||
assert(ext);
|
||||
IniSetting::Bind(ext, "profiler.max_trace_buffer", buf,
|
||||
ini_on_update_long, ini_get_long,
|
||||
&m_maxTraceBuffer);
|
||||
}
|
||||
|
||||
@@ -25,6 +25,7 @@ namespace HPHP {
|
||||
IMPLEMENT_DEFAULT_EXTENSION_VERSION(json, 1.2.1);
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// json_encode() options
|
||||
const int64_t k_JSON_HEX_TAG = 1<<0;
|
||||
const int64_t k_JSON_HEX_AMP = 1<<1;
|
||||
const int64_t k_JSON_HEX_APOS = 1<<2;
|
||||
@@ -34,6 +35,11 @@ const int64_t k_JSON_NUMERIC_CHECK = 1<<5;
|
||||
const int64_t k_JSON_UNESCAPED_SLASHES = 1<<6;
|
||||
const int64_t k_JSON_PRETTY_PRINT = 1<<7;
|
||||
const int64_t k_JSON_UNESCAPED_UNICODE = 1<<8;
|
||||
|
||||
// json_decode() options
|
||||
const int64_t k_JSON_BIGINT_AS_STRING = 1<<0;
|
||||
|
||||
// FB json_decode() options
|
||||
// intentionally higher so when PHP adds more options we're fine
|
||||
const int64_t k_JSON_FB_LOOSE = 1<<20;
|
||||
const int64_t k_JSON_FB_UNLIMITED = 1<<21;
|
||||
@@ -77,7 +83,7 @@ String f_json_encode(CVarRef value, CVarRef options /* = 0 */) {
|
||||
}
|
||||
|
||||
Variant f_json_decode(const String& json, bool assoc /* = false */,
|
||||
CVarRef options /* = 0 */) {
|
||||
int depth /* = 512 */, CVarRef options /* = 0 */){
|
||||
|
||||
json_set_last_error_code(json_error_codes::JSON_ERROR_NONE);
|
||||
|
||||
@@ -91,10 +97,13 @@ Variant f_json_decode(const String& json, bool assoc /* = false */,
|
||||
}
|
||||
|
||||
const int64_t supported_options =
|
||||
k_JSON_FB_LOOSE | k_JSON_FB_COLLECTIONS | k_JSON_FB_STABLE_MAPS;
|
||||
k_JSON_FB_LOOSE |
|
||||
k_JSON_FB_COLLECTIONS |
|
||||
k_JSON_FB_STABLE_MAPS |
|
||||
k_JSON_BIGINT_AS_STRING;
|
||||
int64_t parser_options = json_options & supported_options;
|
||||
Variant z;
|
||||
if (JSON_parser(z, json.data(), json.size(), assoc, parser_options)) {
|
||||
if (JSON_parser(z, json.data(), json.size(), assoc, depth, parser_options)) {
|
||||
return z;
|
||||
}
|
||||
|
||||
@@ -133,7 +142,7 @@ Variant f_json_decode(const String& json, bool assoc /* = false */,
|
||||
wrapped += json + "]";
|
||||
// Stick to a normal hhvm array for the wrapper
|
||||
const int64_t mask = ~(k_JSON_FB_COLLECTIONS | k_JSON_FB_STABLE_MAPS);
|
||||
if (JSON_parser(z, wrapped.data(), wrapped.size(), false,
|
||||
if (JSON_parser(z, wrapped.data(), wrapped.size(), false, depth,
|
||||
parser_options & mask) && z.isArray()) {
|
||||
Array arr = z.toArray();
|
||||
if ((arr.size() == 1) && arr.exists(0)) {
|
||||
@@ -151,10 +160,6 @@ Variant f_json_decode(const String& json, bool assoc /* = false */,
|
||||
return json.substr(1, json.size() - 2);
|
||||
}
|
||||
|
||||
if (ch0 == '{' || ch0 == '[') { /* invalid JSON string */
|
||||
json_set_last_error_code(json_error_codes::JSON_ERROR_SYNTAX);
|
||||
}
|
||||
|
||||
assert(json_get_last_error_code() != json_error_codes::JSON_ERROR_NONE);
|
||||
return uninit_null();
|
||||
}
|
||||
|
||||
@@ -27,7 +27,7 @@ namespace HPHP {
|
||||
|
||||
String f_json_encode(CVarRef value, CVarRef options = 0);
|
||||
Variant f_json_decode(const String& json, bool assoc = false,
|
||||
CVarRef options = 0);
|
||||
int depth = 512, CVarRef options = 0);
|
||||
int f_json_last_error();
|
||||
String f_json_last_error_msg();
|
||||
|
||||
@@ -45,6 +45,7 @@ extern const int64_t k_JSON_FB_EXTRA_ESCAPES;
|
||||
extern const int64_t k_JSON_FB_UNLIMITED;
|
||||
extern const int64_t k_JSON_FB_COLLECTIONS;
|
||||
extern const int64_t k_JSON_FB_STABLE_MAPS;
|
||||
extern const int64_t k_JSON_BIGINT_AS_STRING;
|
||||
|
||||
// For json.idl.json registartion to use in PHP-land.
|
||||
// Duplicating values in the JSON_parser.h enum.
|
||||
|
||||
@@ -67,7 +67,10 @@ public:
|
||||
LDAP *link;
|
||||
Variant rebindproc;
|
||||
};
|
||||
IMPLEMENT_OBJECT_ALLOCATION(LdapLink)
|
||||
|
||||
void LdapLink::sweep() {
|
||||
close();
|
||||
}
|
||||
|
||||
class LdapResult : public SweepableResourceData {
|
||||
public:
|
||||
|
||||
@@ -27,8 +27,6 @@
|
||||
|
||||
namespace HPHP {
|
||||
|
||||
IMPLEMENT_DEFAULT_EXTENSION_VERSION(memcache, 3.0.8);
|
||||
|
||||
static bool ini_on_update_hash_strategy(const String& value, void *p);
|
||||
static String ini_get_hash_strategy(void *p);
|
||||
static bool ini_on_update_hash_function(const String& value, void *p);
|
||||
@@ -44,13 +42,6 @@ public:
|
||||
virtual void requestInit() {
|
||||
hash_strategy = "standard";
|
||||
hash_function = "crc32";
|
||||
|
||||
IniSetting::Bind("memcache.hash_strategy", "standard",
|
||||
ini_on_update_hash_strategy, ini_get_hash_strategy,
|
||||
&hash_strategy);
|
||||
IniSetting::Bind("memcache.hash_function", "crc32",
|
||||
ini_on_update_hash_function, ini_get_hash_function,
|
||||
&hash_function);
|
||||
}
|
||||
|
||||
virtual void requestShutdown() {
|
||||
@@ -60,6 +51,19 @@ public:
|
||||
IMPLEMENT_STATIC_REQUEST_LOCAL(MEMCACHEGlobals, s_memcache_globals);
|
||||
#define MEMCACHEG(name) s_memcache_globals->name
|
||||
|
||||
class MemcacheExtension : public Extension {
|
||||
public:
|
||||
MemcacheExtension() : Extension("memcache", "3.0.8") {};
|
||||
void moduleInit() override {
|
||||
IniSetting::Bind(this, "memcache.hash_strategy", "standard",
|
||||
ini_on_update_hash_strategy, ini_get_hash_strategy,
|
||||
&MEMCACHEG(hash_strategy));
|
||||
IniSetting::Bind(this, "memcache.hash_function", "crc32",
|
||||
ini_on_update_hash_function, ini_get_hash_function,
|
||||
&MEMCACHEG(hash_function));
|
||||
}
|
||||
} s_memcache_extension;;
|
||||
|
||||
static bool ini_on_update_hash_strategy(const String& value, void *p) {
|
||||
if (!strncasecmp(value.data(), "standard", sizeof("standard"))) {
|
||||
MEMCACHEG(hash_strategy) = "standard";
|
||||
|
||||
@@ -500,7 +500,7 @@ static unsigned char *php_parserr(unsigned char *cp, querybuf *answer,
|
||||
memcpy(tp + ll , cp + ll + 1, n);
|
||||
ll = ll + n + 1;
|
||||
}
|
||||
s.setSize(dlen);
|
||||
s.setSize(dlen > 0 ? dlen - 1 : 0);
|
||||
cp += dlen;
|
||||
|
||||
subarray.set(s_txt, s);
|
||||
|
||||
@@ -728,6 +728,10 @@ String f_ini_get(const String& varname) {
|
||||
return value;
|
||||
}
|
||||
|
||||
Array f_ini_get_all(const String& extension, bool detailed) {
|
||||
return IniSetting::GetAll(extension, detailed);
|
||||
}
|
||||
|
||||
void f_ini_restore(const String& varname) {
|
||||
}
|
||||
|
||||
|
||||
@@ -54,6 +54,7 @@ bool f_clock_settime(int clk_id, int64_t sec, int64_t nsec);
|
||||
int64_t f_cpu_get_count();
|
||||
String f_cpu_get_model();
|
||||
String f_ini_get(const String& varname);
|
||||
Array f_ini_get_all(const String& extension, bool detailed);
|
||||
void f_ini_restore(const String& varname);
|
||||
String f_ini_set(const String& varname, const String& newvalue);
|
||||
int64_t f_memory_get_allocation();
|
||||
|
||||
@@ -37,6 +37,14 @@ public:
|
||||
Native::registerConstant<KindOfString>(
|
||||
s_PCRE_VERSION.get(), makeStaticString(pcre_version())
|
||||
);
|
||||
IniSetting::Bind(this, "pcre.backtrack_limit",
|
||||
std::to_string(RuntimeOption::PregBacktraceLimit).c_str(),
|
||||
ini_on_update_long, ini_get_long,
|
||||
&g_context->m_preg_backtrace_limit);
|
||||
IniSetting::Bind(this, "pcre.recursion_limit",
|
||||
std::to_string(RuntimeOption::PregRecursionLimit).c_str(),
|
||||
ini_on_update_long, ini_get_long,
|
||||
&g_context->m_preg_recursion_limit);
|
||||
}
|
||||
} s_pcre_extension;
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
@@ -129,6 +129,7 @@ public:
|
||||
const int64_t k_PHP_SESSION_DISABLED = Session::Disabled;
|
||||
const int64_t k_PHP_SESSION_NONE = Session::None;
|
||||
const int64_t k_PHP_SESSION_ACTIVE = Session::Active;
|
||||
const StaticString s_session_ext_name("session");
|
||||
|
||||
class SessionRequestData : public RequestEventHandler, public Session {
|
||||
public:
|
||||
@@ -157,71 +158,73 @@ public:
|
||||
String m_id;
|
||||
|
||||
void threadInit() {
|
||||
IniSetting::Bind("session.save_path", "",
|
||||
ini_on_update_save_dir, ini_get_string,
|
||||
Extension* ext = Extension::GetExtension(s_session_ext_name);
|
||||
assert(ext);
|
||||
IniSetting::Bind(ext, "session.save_path", "",
|
||||
ini_on_update_save_dir, ini_get_stdstring,
|
||||
&m_save_path);
|
||||
IniSetting::Bind("session.name", "PHPSESSID",
|
||||
ini_on_update_string, ini_get_string,
|
||||
IniSetting::Bind(ext, "session.name", "PHPSESSID",
|
||||
ini_on_update_stdstring, ini_get_stdstring,
|
||||
&m_session_name);
|
||||
IniSetting::Bind("session.save_handler", "files",
|
||||
ini_on_update_save_handler, ini_get_save_handler);
|
||||
IniSetting::Bind("session.auto_start", "0",
|
||||
ini_on_update_bool, ini_get_bool,
|
||||
IniSetting::Bind(ext, "session.save_handler", "files",
|
||||
ini_on_update_save_handler, ini_get_save_handler);
|
||||
IniSetting::Bind(ext, "session.auto_start", "0",
|
||||
ini_on_update_bool, ini_get_bool,
|
||||
&m_auto_start);
|
||||
IniSetting::Bind("session.gc_probability", "1",
|
||||
ini_on_update_long, ini_get_long,
|
||||
IniSetting::Bind(ext, "session.gc_probability", "1",
|
||||
ini_on_update_long, ini_get_long,
|
||||
&m_gc_probability);
|
||||
IniSetting::Bind("session.gc_divisor", "100",
|
||||
ini_on_update_long, ini_get_long,
|
||||
IniSetting::Bind(ext, "session.gc_divisor", "100",
|
||||
ini_on_update_long, ini_get_long,
|
||||
&m_gc_divisor);
|
||||
IniSetting::Bind("session.gc_maxlifetime", "1440",
|
||||
ini_on_update_long, ini_get_long,
|
||||
IniSetting::Bind(ext, "session.gc_maxlifetime", "1440",
|
||||
ini_on_update_long, ini_get_long,
|
||||
&m_gc_maxlifetime);
|
||||
IniSetting::Bind("session.serialize_handler", "php",
|
||||
ini_on_update_serializer, ini_get_serializer);
|
||||
IniSetting::Bind("session.cookie_lifetime", "0",
|
||||
ini_on_update_long, ini_get_long,
|
||||
IniSetting::Bind(ext, "session.serialize_handler", "php",
|
||||
ini_on_update_serializer, ini_get_serializer);
|
||||
IniSetting::Bind(ext, "session.cookie_lifetime", "0",
|
||||
ini_on_update_long, ini_get_long,
|
||||
&m_cookie_lifetime);
|
||||
IniSetting::Bind("session.cookie_path", "/",
|
||||
ini_on_update_string, ini_get_string,
|
||||
IniSetting::Bind(ext, "session.cookie_path", "/",
|
||||
ini_on_update_stdstring, ini_get_stdstring,
|
||||
&m_cookie_path);
|
||||
IniSetting::Bind("session.cookie_domain", "",
|
||||
ini_on_update_string, ini_get_string,
|
||||
IniSetting::Bind(ext, "session.cookie_domain", "",
|
||||
ini_on_update_stdstring, ini_get_stdstring,
|
||||
&m_cookie_domain);
|
||||
IniSetting::Bind("session.cookie_secure", "",
|
||||
ini_on_update_bool, ini_get_bool,
|
||||
IniSetting::Bind(ext, "session.cookie_secure", "",
|
||||
ini_on_update_bool, ini_get_bool,
|
||||
&m_cookie_secure);
|
||||
IniSetting::Bind("session.cookie_httponly", "",
|
||||
ini_on_update_bool, ini_get_bool,
|
||||
IniSetting::Bind(ext, "session.cookie_httponly", "",
|
||||
ini_on_update_bool, ini_get_bool,
|
||||
&m_cookie_httponly);
|
||||
IniSetting::Bind("session.use_cookies", "1",
|
||||
ini_on_update_bool, ini_get_bool,
|
||||
IniSetting::Bind(ext, "session.use_cookies", "1",
|
||||
ini_on_update_bool, ini_get_bool,
|
||||
&m_use_cookies);
|
||||
IniSetting::Bind("session.use_only_cookies", "1",
|
||||
ini_on_update_bool, ini_get_bool,
|
||||
IniSetting::Bind(ext, "session.use_only_cookies", "1",
|
||||
ini_on_update_bool, ini_get_bool,
|
||||
&m_use_only_cookies);
|
||||
IniSetting::Bind("session.referer_check", "",
|
||||
ini_on_update_string, ini_get_string,
|
||||
IniSetting::Bind(ext, "session.referer_check", "",
|
||||
ini_on_update_stdstring, ini_get_stdstring,
|
||||
&m_extern_referer_chk);
|
||||
IniSetting::Bind("session.entropy_file", "",
|
||||
ini_on_update_string, ini_get_string,
|
||||
IniSetting::Bind(ext, "session.entropy_file", "",
|
||||
ini_on_update_stdstring, ini_get_stdstring,
|
||||
&m_entropy_file);
|
||||
IniSetting::Bind("session.entropy_length", "0",
|
||||
ini_on_update_long, ini_get_long,
|
||||
IniSetting::Bind(ext, "session.entropy_length", "0",
|
||||
ini_on_update_long, ini_get_long,
|
||||
&m_entropy_length);
|
||||
IniSetting::Bind("session.cache_limiter", "nocache",
|
||||
ini_on_update_string, ini_get_string,
|
||||
IniSetting::Bind(ext, "session.cache_limiter", "nocache",
|
||||
ini_on_update_stdstring, ini_get_stdstring,
|
||||
&m_cache_limiter);
|
||||
IniSetting::Bind("session.cache_expire", "180",
|
||||
ini_on_update_long, ini_get_long,
|
||||
IniSetting::Bind(ext, "session.cache_expire", "180",
|
||||
ini_on_update_long, ini_get_long,
|
||||
&m_cache_expire);
|
||||
IniSetting::Bind("session.use_trans_sid", "0",
|
||||
ini_on_update_trans_sid, ini_get_trans_sid);
|
||||
IniSetting::Bind("session.hash_function", "0",
|
||||
ini_on_update_string, ini_get_string,
|
||||
IniSetting::Bind(ext, "session.use_trans_sid", "0",
|
||||
ini_on_update_trans_sid, ini_get_trans_sid);
|
||||
IniSetting::Bind(ext, "session.hash_function", "0",
|
||||
ini_on_update_stdstring, ini_get_stdstring,
|
||||
&m_hash_func);
|
||||
IniSetting::Bind("session.hash_bits_per_character", "4",
|
||||
ini_on_update_long, ini_get_long,
|
||||
IniSetting::Bind(ext, "session.hash_bits_per_character", "4",
|
||||
ini_on_update_long, ini_get_long,
|
||||
&m_hash_bits_per_character);
|
||||
}
|
||||
};
|
||||
@@ -1201,7 +1204,7 @@ static bool ini_on_update_save_dir(const String& value, void *p) {
|
||||
if (File::TranslatePath(path).empty()) {
|
||||
return false;
|
||||
}
|
||||
return ini_on_update_string(value, p);
|
||||
return ini_on_update_stdstring(value, p);
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
@@ -1045,7 +1045,8 @@ Variant sockopen_impl(const Util::HostURL &hosturl, VRefParam errnum,
|
||||
|
||||
std::string key;
|
||||
if (persistent) {
|
||||
key = hosturl.getHostURL();
|
||||
key = hosturl.getHostURL() + ":" +
|
||||
boost::lexical_cast<std::string>(hosturl.getPort());
|
||||
Socket *sock =
|
||||
dynamic_cast<Socket*>(g_persistentObjects->get("socket", key.c_str()));
|
||||
if (sock) {
|
||||
|
||||
@@ -30,7 +30,7 @@ IMPLEMENT_REQUEST_LOCAL(RequestData, s_intl_request);
|
||||
const StaticString s_resdata("__resdata");
|
||||
|
||||
void IntlExtension::bindIniSettings() {
|
||||
IniSetting::Bind("intl.default_locale", "",
|
||||
IniSetting::Bind(this, "intl.default_locale", "",
|
||||
icu_on_update_default_locale, icu_get_default_locale,
|
||||
nullptr);
|
||||
}
|
||||
|
||||
@@ -244,8 +244,9 @@ bool PDOMySqlConnection::create(CArrRef options) {
|
||||
char *host = NULL, *unix_socket = NULL;
|
||||
unsigned int port = 3306;
|
||||
char *dbname;
|
||||
char *charset = nullptr;
|
||||
struct pdo_data_src_parser vars[] = {
|
||||
{ "charset", NULL, 0 },
|
||||
{ "charset", nullptr, 0 },
|
||||
{ "dbname", "", 0 },
|
||||
{ "host", "localhost", 0 },
|
||||
{ "port", "3306", 0 },
|
||||
@@ -270,6 +271,7 @@ bool PDOMySqlConnection::create(CArrRef options) {
|
||||
|
||||
m_max_buffer_size = 1024*1024;
|
||||
m_buffered = m_emulate_prepare = 1;
|
||||
charset = vars[0].optval;
|
||||
|
||||
/* handle MySQL options */
|
||||
if (!options.empty()) {
|
||||
@@ -350,6 +352,13 @@ bool PDOMySqlConnection::create(CArrRef options) {
|
||||
}
|
||||
}
|
||||
|
||||
if (charset) {
|
||||
if (mysql_options(m_server, MYSQL_SET_CHARSET_NAME, charset)) {
|
||||
handleError(__FILE__, __LINE__);
|
||||
goto cleanup;
|
||||
}
|
||||
}
|
||||
|
||||
dbname = vars[1].optval;
|
||||
host = vars[2].optval;
|
||||
if (vars[3].optval) {
|
||||
|
||||
@@ -686,7 +686,7 @@ static void set_method_prototype_info(Array &ret, const Func *func) {
|
||||
}
|
||||
}
|
||||
|
||||
static void set_method_info(Array &ret, const Func* func) {
|
||||
static void set_method_info(Array &ret, const Func* func, const Class* cls) {
|
||||
if (RuntimeOption::EvalRuntimeTypeProfile && !ret.exists(s_type_profiling)) {
|
||||
ret.set(s_type_profiling, Array());
|
||||
}
|
||||
@@ -702,7 +702,11 @@ static void set_method_info(Array &ret, const Func* func) {
|
||||
set_function_info(ret, func);
|
||||
set_source_info(ret, func->unit()->filepath()->data(),
|
||||
func->line1(), func->line2());
|
||||
set_method_prototype_info(ret, func);
|
||||
// If Func* is from a PreClass, it doesn't know about base classes etc.
|
||||
// Swap it out for the full version if possible.
|
||||
auto resolved_func = cls->lookupMethod(func->name());
|
||||
set_method_prototype_info(ret,
|
||||
resolved_func ? resolved_func : func);
|
||||
}
|
||||
|
||||
static Array get_method_info(const ClassInfo *cls, CVarRef name) {
|
||||
@@ -741,7 +745,7 @@ Array HHVM_FUNCTION(hphp_get_method_info, CVarRef class_or_object,
|
||||
if (!func) return Array();
|
||||
}
|
||||
Array ret;
|
||||
set_method_info(ret, func);
|
||||
set_method_info(ret, func, cls);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -995,18 +999,14 @@ Array HHVM_FUNCTION(hphp_get_class_info, CVarRef name) {
|
||||
Func* const* methods = cls->preClass()->methods();
|
||||
size_t const numMethods = cls->preClass()->numMethods();
|
||||
for (Slot i = 0; i < numMethods; ++i) {
|
||||
const Func* pcm = methods[i];
|
||||
if (pcm->isGenerated()) continue;
|
||||
// ... but the PreClass doesn't have the full base class information
|
||||
// required for a ReflectionMethod::getPrototype()
|
||||
const Func* m = cls->lookupMethod(pcm->name());
|
||||
const Func* m = methods[i];
|
||||
if (m->isGenerated()) continue;
|
||||
|
||||
assert(m != nullptr);
|
||||
Array info = Array::Create();
|
||||
if (RuntimeOption::EvalRuntimeTypeProfile) {
|
||||
set_type_profiling_info(info, cls, pcm);
|
||||
set_type_profiling_info(info, cls, m);
|
||||
}
|
||||
set_method_info(info, m);
|
||||
set_method_info(info, m, cls);
|
||||
arr.set(f_strtolower(m->nameRef()), VarNR(info));
|
||||
}
|
||||
|
||||
@@ -1017,7 +1017,7 @@ Array HHVM_FUNCTION(hphp_get_class_info, CVarRef name) {
|
||||
const Func* m = clsMethods[i];
|
||||
if (m->isGenerated()) continue;
|
||||
Array info = Array::Create();
|
||||
set_method_info(info, m);
|
||||
set_method_info(info, m, cls);
|
||||
arr.set(f_strtolower(m->nameRef()), VarNR(info));
|
||||
}
|
||||
ret.set(s_methods, VarNR(arr));
|
||||
|
||||
@@ -0,0 +1,42 @@
|
||||
/*
|
||||
+----------------------------------------------------------------------+
|
||||
| HipHop for PHP |
|
||||
+----------------------------------------------------------------------+
|
||||
| Copyright (c) 2010-2013 Facebook, Inc. (http://www.facebook.com) |
|
||||
| Copyright (c) 1997-2010 The PHP Group |
|
||||
+----------------------------------------------------------------------+
|
||||
| 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. |
|
||||
+----------------------------------------------------------------------+
|
||||
*/
|
||||
|
||||
#include "folly/AtomicHashMap.h"
|
||||
#include "hphp/runtime/ext_zend_compat/php-src/Zend/zend_modules.h"
|
||||
|
||||
#include <atomic>
|
||||
|
||||
// Initial size of the map
|
||||
#define APPROXIMATE_STATIC_ZEND_MODULES 10
|
||||
static std::atomic_int s_zend_next_module(1);
|
||||
static folly::AtomicHashMap<int, ZendExtension*> s_zend_extensions(
|
||||
APPROXIMATE_STATIC_ZEND_MODULES
|
||||
);
|
||||
|
||||
ZendExtension::ZendExtension(const char* name) : HPHP::Extension(name) {
|
||||
zend_module_entry* module = this->getEntry();
|
||||
module->module_number = s_zend_next_module++;
|
||||
s_zend_extensions.insert(module->module_number, this);
|
||||
}
|
||||
|
||||
ZendExtension* ZendExtension::GetByModuleNumber(int module_number) {
|
||||
auto iter = s_zend_extensions.find(module_number);
|
||||
if (iter != s_zend_extensions.end()) {
|
||||
return iter->second;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
@@ -35,6 +35,9 @@ ZEND_API int zend_register_ini_entries(const zend_ini_entry *ini_entry, int modu
|
||||
{
|
||||
const zend_ini_entry *p = ini_entry;
|
||||
|
||||
auto extension = ZendExtension::GetByModuleNumber(module_number);
|
||||
assert(extension);
|
||||
|
||||
while (p->name) {
|
||||
auto updateCallback = [](const HPHP::String& value, void *p) -> bool {
|
||||
zend_ini_entry *entry = static_cast<zend_ini_entry*>(p);
|
||||
@@ -51,6 +54,7 @@ ZEND_API int zend_register_ini_entries(const zend_ini_entry *ini_entry, int modu
|
||||
return HPHP::String(entry->value, entry->value_length, HPHP::CopyString);
|
||||
};
|
||||
HPHP::IniSetting::Bind(
|
||||
extension,
|
||||
p->name, p->value,
|
||||
updateCallback, getCallback,
|
||||
const_cast<zend_ini_entry*>(p));
|
||||
|
||||
@@ -79,9 +79,10 @@ class ZendExtension : public HPHP::Extension {
|
||||
private:
|
||||
zend_module_entry *getEntry();
|
||||
public:
|
||||
/* implicit */ ZendExtension(const char* name) : HPHP::Extension(name) {}
|
||||
/* implicit */ ZendExtension(const char* name);
|
||||
virtual void moduleInit() override;
|
||||
virtual void moduleShutdown() override;
|
||||
static ZendExtension* GetByModuleNumber(int module_number);
|
||||
};
|
||||
#endif
|
||||
|
||||
@@ -130,7 +131,7 @@ inline void ZendExtension::moduleInit() {
|
||||
entry->globals_ctor(entry->globals_ptr);
|
||||
}
|
||||
if (entry->module_startup_func) {
|
||||
entry->module_startup_func(1, 1);
|
||||
entry->module_startup_func(1, entry->module_number);
|
||||
}
|
||||
}
|
||||
inline void ZendExtension::moduleShutdown() {
|
||||
|
||||
@@ -125,8 +125,13 @@ static PHP_GSHUTDOWN_FUNCTION(pcre) /* {{{ */
|
||||
/* }}} */
|
||||
|
||||
PHP_INI_BEGIN()
|
||||
#ifdef HHVM
|
||||
STD_PHP_INI_ENTRY("pcre_zend_compat.backtrack_limit", "1000000", PHP_INI_ALL, OnUpdateLong, backtrack_limit, zend_pcre_globals, pcre_globals)
|
||||
STD_PHP_INI_ENTRY("pcre_zend_compat.recursion_limit", "100000", PHP_INI_ALL, OnUpdateLong, recursion_limit, zend_pcre_globals, pcre_globals)
|
||||
#else
|
||||
STD_PHP_INI_ENTRY("pcre.backtrack_limit", "1000000", PHP_INI_ALL, OnUpdateLong, backtrack_limit, zend_pcre_globals, pcre_globals)
|
||||
STD_PHP_INI_ENTRY("pcre.recursion_limit", "100000", PHP_INI_ALL, OnUpdateLong, recursion_limit, zend_pcre_globals, pcre_globals)
|
||||
#endif
|
||||
PHP_INI_END()
|
||||
|
||||
|
||||
@@ -1966,10 +1971,10 @@ static const zend_function_entry pcre_functions[] = {
|
||||
PHP_FE_END
|
||||
};
|
||||
|
||||
#ifdef HHVjM
|
||||
#ifdef HHVM
|
||||
zend_module_entry pcre_zend_compat_module_entry = {
|
||||
#else
|
||||
zend_module_entry pcre_zend_compat_module_entry = {
|
||||
zend_module_entry pcre_zend_module_entry = {
|
||||
#endif
|
||||
STANDARD_MODULE_HEADER,
|
||||
#ifdef HHVM
|
||||
|
||||
@@ -25,7 +25,8 @@ public:
|
||||
virtual ServerPtr createServer(const ServerOptions& options) override {
|
||||
return std::make_shared<FastCGIServer>(options.m_address,
|
||||
options.m_port,
|
||||
options.m_numThreads);
|
||||
options.m_numThreads,
|
||||
options.m_useFileSocket);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -137,7 +137,20 @@ FastCGIConnection::newSessionHandler(int transport_id) {
|
||||
}
|
||||
|
||||
void FastCGIConnection::onSessionEgress(std::unique_ptr<IOBuf> chain) {
|
||||
m_sock->writeChain(nullptr, std::move(chain));
|
||||
++m_writeCount;
|
||||
m_sock->writeChain(this, std::move(chain));
|
||||
}
|
||||
|
||||
void FastCGIConnection::writeError(size_t bytes,
|
||||
const apache::thrift::transport::TTransportException& ex) noexcept {
|
||||
writeSuccess();
|
||||
}
|
||||
|
||||
void FastCGIConnection::writeSuccess() noexcept {
|
||||
--m_writeCount;
|
||||
if (m_writeCount == 0 && m_shutdown) {
|
||||
delete this;
|
||||
}
|
||||
}
|
||||
|
||||
void FastCGIConnection::onSessionError() {
|
||||
@@ -146,7 +159,10 @@ void FastCGIConnection::onSessionError() {
|
||||
|
||||
void FastCGIConnection::onSessionClose() {
|
||||
shutdownTransport();
|
||||
delete this;
|
||||
m_shutdown = true;
|
||||
if (m_writeCount == 0) {
|
||||
delete this;
|
||||
}
|
||||
}
|
||||
|
||||
void FastCGIConnection::setMaxConns(int max_conns) {
|
||||
@@ -167,7 +183,8 @@ void FastCGIConnection::handleRequest(int transport_id) {
|
||||
|
||||
FastCGIServer::FastCGIServer(const std::string &address,
|
||||
int port,
|
||||
int workers)
|
||||
int workers,
|
||||
bool useFileSocket)
|
||||
: Server(address, port, workers),
|
||||
m_worker(&m_eventBaseManager),
|
||||
m_dispatcher(workers,
|
||||
@@ -179,7 +196,9 @@ FastCGIServer::FastCGIServer(const std::string &address,
|
||||
RuntimeOption::ServerThreadJobMaxQueuingMilliSeconds,
|
||||
RequestPriority::k_numPriorities) {
|
||||
TSocketAddress sock_addr;
|
||||
if (address.empty()) {
|
||||
if (useFileSocket) {
|
||||
sock_addr.setFromPath(address);
|
||||
} else if (address.empty()) {
|
||||
sock_addr.setFromLocalPort(port);
|
||||
} else {
|
||||
sock_addr.setFromHostPort(address, port);
|
||||
@@ -210,8 +229,12 @@ void FastCGIServer::start() {
|
||||
m_socket->bind(m_socketConfig.getAddress());
|
||||
} catch (const apache::thrift::transport::TTransportException& ex) {
|
||||
LOG(ERROR) << ex.what();
|
||||
throw FailedToListenException(m_socketConfig.getAddress().getAddressStr(),
|
||||
m_socketConfig.getAddress().getPort());
|
||||
if (m_socketConfig.getAddress().getFamily() == AF_UNIX) {
|
||||
throw FailedToListenException(m_socketConfig.getAddress().getPath());
|
||||
} else {
|
||||
throw FailedToListenException(m_socketConfig.getAddress().getAddressStr(),
|
||||
m_socketConfig.getAddress().getPort());
|
||||
}
|
||||
}
|
||||
m_acceptor.reset(new FastCGIAcceptor(m_socketConfig, this));
|
||||
m_acceptor->init(m_socket.get(), m_worker.getEventBase());
|
||||
|
||||
@@ -71,6 +71,7 @@ class FastCGITransport;
|
||||
class FastCGIConnection
|
||||
: public SocketConnection,
|
||||
public apache::thrift::async::TAsyncTransport::ReadCallback,
|
||||
public apache::thrift::async::TAsyncTransport::WriteCallback,
|
||||
public ProtocolSession::Callback {
|
||||
friend class FastCGITransport;
|
||||
public:
|
||||
@@ -91,6 +92,10 @@ public:
|
||||
virtual std::shared_ptr<ProtocolSessionHandler>
|
||||
newSessionHandler(int handler_id) override;
|
||||
virtual void onSessionEgress(std::unique_ptr<folly::IOBuf> chain) override;
|
||||
virtual void writeError(size_t bytes,
|
||||
const apache::thrift::transport::TTransportException& ex)
|
||||
noexcept override;
|
||||
virtual void writeSuccess() noexcept override;
|
||||
virtual void onSessionError() override;
|
||||
virtual void onSessionClose() override;
|
||||
|
||||
@@ -113,6 +118,8 @@ private:
|
||||
FastCGIServer* m_server;
|
||||
FastCGISession m_session;
|
||||
folly::IOBufQueue m_readBuf;
|
||||
bool m_shutdown{false};
|
||||
uint32_t m_writeCount{0};
|
||||
};
|
||||
|
||||
|
||||
@@ -121,7 +128,8 @@ class FastCGIServer : public Server,
|
||||
public:
|
||||
FastCGIServer(const std::string &address,
|
||||
int port,
|
||||
int workers);
|
||||
int workers,
|
||||
bool useFileSocket);
|
||||
~FastCGIServer() {
|
||||
if (!m_done) {
|
||||
waitForEnd();
|
||||
|
||||
@@ -56,6 +56,10 @@ const char *FastCGITransport::getUrl() {
|
||||
return m_requestURI.c_str();
|
||||
}
|
||||
|
||||
const std::string FastCGITransport::getScriptFilename() {
|
||||
return m_scriptFilename;
|
||||
}
|
||||
|
||||
const std::string FastCGITransport::getDocumentRoot() {
|
||||
return m_documentRoot;
|
||||
}
|
||||
@@ -269,20 +273,20 @@ void FastCGITransport::sendImpl(const void *data, int size, int code,
|
||||
chain_wrapper(queue.move());
|
||||
Callback* callback = m_callback;
|
||||
std::function<void()> fn = [callback, chain_wrapper]() mutable {
|
||||
if (callback) {
|
||||
callback->onStdOut(std::move(*chain_wrapper));
|
||||
}
|
||||
};
|
||||
if (callback) {
|
||||
callback->onStdOut(std::move(*chain_wrapper));
|
||||
}
|
||||
};
|
||||
m_connection->getEventBase()->runInEventBaseThread(fn);
|
||||
}
|
||||
|
||||
void FastCGITransport::onSendEndImpl() {
|
||||
Callback* callback = m_callback;
|
||||
std::function<void()> fn = [callback]() mutable {
|
||||
if (callback) {
|
||||
callback->onComplete();
|
||||
}
|
||||
};
|
||||
if (callback) {
|
||||
callback->onComplete();
|
||||
}
|
||||
};
|
||||
m_connection->getEventBase()->runInEventBaseThread(fn);
|
||||
}
|
||||
|
||||
@@ -311,12 +315,16 @@ void FastCGITransport::onHeader(std::unique_ptr<folly::IOBuf> key_chain,
|
||||
std::unique_ptr<folly::IOBuf> value_chain) {
|
||||
Cursor cursor(key_chain.get());
|
||||
std::string key = cursor.readFixedString(key_chain->computeChainDataLength());
|
||||
|
||||
// HTTP has case insensitive header keys
|
||||
boost::to_upper(key);
|
||||
for (auto& c : key) {
|
||||
c = std::toupper(c);
|
||||
}
|
||||
|
||||
cursor = Cursor(value_chain.get());
|
||||
std::string value = cursor.readFixedString(
|
||||
value_chain->computeChainDataLength());
|
||||
m_requestHeaders.insert(std::make_pair(key, value));
|
||||
m_requestHeaders.emplace(key, value);
|
||||
}
|
||||
|
||||
void FastCGITransport::onHeadersComplete() {
|
||||
@@ -327,6 +335,7 @@ void FastCGITransport::onHeadersComplete() {
|
||||
m_serverAddr = getRawHeader("SERVER_ADDR");
|
||||
m_extendedMethod = getRawHeader("REQUEST_METHOD");
|
||||
m_httpVersion = getRawHeader("HTTP_VERSION");
|
||||
m_scriptFilename = getRawHeader("SCRIPT_FILENAME");
|
||||
m_documentRoot = getRawHeader("DOCUMENT_ROOT") + "/";
|
||||
|
||||
try {
|
||||
|
||||
@@ -49,6 +49,7 @@ public:
|
||||
virtual const char *getRemoteHost() override;
|
||||
virtual const char *getRemoteAddr() override;
|
||||
virtual uint16_t getRemotePort() override;
|
||||
virtual const std::string getScriptFilename() override;
|
||||
virtual const std::string getDocumentRoot() override;
|
||||
virtual const char *getServerName() override;
|
||||
virtual const char *getServerAddr() override;
|
||||
@@ -108,6 +109,7 @@ private:
|
||||
folly::IOBufQueue m_bodyQueue;
|
||||
std::unique_ptr<folly::IOBuf> m_currBody;
|
||||
std::unordered_map<std::string, std::string> m_requestHeaders;
|
||||
std::string m_scriptFilename;
|
||||
std::string m_requestURI;
|
||||
std::string m_documentRoot;
|
||||
std::string m_remoteHost;
|
||||
|
||||
@@ -316,17 +316,19 @@ void HttpProtocol::PreparePostVariables(Variant& post,
|
||||
}
|
||||
}
|
||||
|
||||
if (needDelete) {
|
||||
if (RuntimeOption::AlwaysPopulateRawPostData &&
|
||||
uint32_t(size) <= StringData::MaxSize) {
|
||||
raw_post = String((char*)data, size, AttachString);
|
||||
} else {
|
||||
free((void *)data);
|
||||
if (uint32_t(size) > StringData::MaxSize) {
|
||||
// Can't store it anywhere
|
||||
if (needDelete) {
|
||||
free((void*) data);
|
||||
}
|
||||
} else {
|
||||
// For literal we disregard RuntimeOption::AlwaysPopulateRawPostData
|
||||
if (uint32_t(size) <= StringData::MaxSize) {
|
||||
raw_post = String((char*)data, size, CopyString);
|
||||
auto string_data = needDelete ?
|
||||
String((char*)data, size, AttachString) :
|
||||
String((char*)data, size, CopyString);
|
||||
g_context->setRawPostData(string_data);
|
||||
if (RuntimeOption::AlwaysPopulateRawPostData || ! needDelete) {
|
||||
// For literal we disregard RuntimeOption::AlwaysPopulateRawPostData
|
||||
raw_post = string_data;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -76,9 +76,11 @@ HttpServer::HttpServer()
|
||||
|
||||
auto serverFactory = ServerFactoryRegistry::getInstance()->getFactory
|
||||
(RuntimeOption::ServerType);
|
||||
ServerOptions options
|
||||
(RuntimeOption::ServerIP, RuntimeOption::ServerPort,
|
||||
startingThreadCount);
|
||||
const std::string address = RuntimeOption::ServerFileSocket.empty()
|
||||
? RuntimeOption::ServerIP : RuntimeOption::ServerFileSocket;
|
||||
ServerOptions options(
|
||||
address, RuntimeOption::ServerPort, startingThreadCount);
|
||||
options.m_useFileSocket = !RuntimeOption::ServerFileSocket.empty();
|
||||
options.m_serverFD = RuntimeOption::ServerPortFd;
|
||||
options.m_sslFD = RuntimeOption::SSLPortFd;
|
||||
options.m_takeoverFilename = RuntimeOption::TakeoverFilename;
|
||||
@@ -494,7 +496,12 @@ bool HttpServer::startServer(bool pageServer) {
|
||||
}
|
||||
|
||||
if (errno == EACCES) {
|
||||
Logger::Error("Permission denied listening on port %d", port);
|
||||
if (pageServer && !RuntimeOption::ServerFileSocket.empty()) {
|
||||
Logger::Error("Permission denied opening socket at %s",
|
||||
RuntimeOption::ServerFileSocket.c_str());
|
||||
} else {
|
||||
Logger::Error("Permission denied listening on port %d", port);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -507,6 +514,22 @@ bool HttpServer::startServer(bool pageServer) {
|
||||
StringBuffer response;
|
||||
http.get(url.c_str(), response);
|
||||
|
||||
if (pageServer && !RuntimeOption::ServerFileSocket.empty()) {
|
||||
if (i == 0) {
|
||||
Logger::Info("Unlinking unused socket at %s",
|
||||
RuntimeOption::ServerFileSocket.c_str());
|
||||
}
|
||||
struct stat stat_buf;
|
||||
if (stat(RuntimeOption::ServerFileSocket.c_str(), &stat_buf) == 0
|
||||
&& S_ISSOCK(stat_buf.st_mode)) {
|
||||
std::string cmd = "bash -c '! fuser ";
|
||||
cmd += RuntimeOption::ServerFileSocket;
|
||||
cmd += "'";
|
||||
if (Util::ssystem(cmd.c_str()) == 0) {
|
||||
unlink(RuntimeOption::ServerFileSocket.c_str());
|
||||
}
|
||||
}
|
||||
}
|
||||
sleep(1);
|
||||
}
|
||||
}
|
||||
@@ -542,15 +565,27 @@ bool HttpServer::startServer(bool pageServer) {
|
||||
}
|
||||
return true;
|
||||
} catch (FailedToListenException &e) {
|
||||
if (i == 0) {
|
||||
Logger::Info("killing anything listening on port %d", port);
|
||||
if (pageServer && !RuntimeOption::ServerFileSocket.empty()) {
|
||||
if (i == 0) {
|
||||
Logger::Info("unlinking socket at %s",
|
||||
RuntimeOption::ServerFileSocket.c_str());
|
||||
}
|
||||
|
||||
struct stat stat_buf;
|
||||
if (stat(RuntimeOption::ServerFileSocket.c_str(), &stat_buf) == 0
|
||||
&& S_ISSOCK(stat_buf.st_mode)) {
|
||||
unlink(RuntimeOption::ServerFileSocket.c_str());
|
||||
}
|
||||
} else {
|
||||
if (i == 0) {
|
||||
Logger::Info("killing anything listening on port %d", port);
|
||||
}
|
||||
|
||||
std::string cmd = "lsof -t -i :";
|
||||
cmd += lexical_cast<std::string>(port);
|
||||
cmd += " | xargs kill -9";
|
||||
Util::ssystem(cmd.c_str());
|
||||
}
|
||||
|
||||
std::string cmd = "lsof -t -i :";
|
||||
cmd += lexical_cast<std::string>(port);
|
||||
cmd += " | xargs kill -9";
|
||||
Util::ssystem(cmd.c_str());
|
||||
|
||||
sleep(1);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -72,6 +72,14 @@ bool RequestURI::process(const VirtualHost *vhost, Transport *transport,
|
||||
m_originalURL = StringUtil::UrlDecode(m_originalURL, false);
|
||||
m_rewritten = false;
|
||||
|
||||
auto scriptFilename = transport->getScriptFilename();
|
||||
if (!scriptFilename.empty()) {
|
||||
// The transport is overriding everything and just handing us the filename
|
||||
m_path = m_absolutePath = scriptFilename;
|
||||
processExt();
|
||||
return true;
|
||||
}
|
||||
|
||||
// Fast path for files that exist
|
||||
if (vhost->checkExistenceBeforeRewrite()) {
|
||||
String canon(
|
||||
|
||||
@@ -265,7 +265,8 @@ public:
|
||||
m_numThreads(numThreads),
|
||||
m_serverFD(-1),
|
||||
m_sslFD(-1),
|
||||
m_takeoverFilename() {
|
||||
m_takeoverFilename(),
|
||||
m_useFileSocket(false) {
|
||||
}
|
||||
|
||||
std::string m_address;
|
||||
@@ -274,6 +275,7 @@ public:
|
||||
int m_serverFD;
|
||||
int m_sslFD;
|
||||
std::string m_takeoverFilename;
|
||||
bool m_useFileSocket;
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -327,6 +329,9 @@ public:
|
||||
|
||||
class FailedToListenException : public ServerException {
|
||||
public:
|
||||
explicit FailedToListenException(const std::string &addr)
|
||||
: ServerException("Failed to listen to unix socket at %s", addr.c_str()) {
|
||||
}
|
||||
FailedToListenException(const std::string &addr, int port)
|
||||
: ServerException("Failed to listen on %s:%d", addr.c_str(), port) {
|
||||
}
|
||||
|
||||
@@ -116,6 +116,8 @@ public:
|
||||
virtual const char *getRemoteAddr() { return ""; }
|
||||
// The transport can override the virtualhosts' docroot
|
||||
virtual const std::string getDocumentRoot() { return ""; }
|
||||
// The transport can say exactly what script to use
|
||||
virtual const std::string getScriptFilename() { return ""; }
|
||||
|
||||
/**
|
||||
* Server Headers
|
||||
|
||||
@@ -3726,6 +3726,14 @@ OPTBLD_INLINE void VMExecutionContext::iopClsCns(IOP_ARGS) {
|
||||
assert(tv->m_type == KindOfClass);
|
||||
Class* class_ = tv->m_data.pcls;
|
||||
assert(class_ != nullptr);
|
||||
if (clsCnsName->isame(s_class.get())) {
|
||||
// Doesn't decref tv since Classes aren't refcounted
|
||||
auto name = const_cast<StringData*>(class_->name());
|
||||
assert(name->isStatic());
|
||||
tv->m_type = KindOfStaticString;
|
||||
tv->m_data.pstr = name;
|
||||
return;
|
||||
}
|
||||
auto const clsCns = class_->clsCnsGet(clsCnsName);
|
||||
if (clsCns.m_type == KindOfUninit) {
|
||||
raise_error("Couldn't find constant %s::%s",
|
||||
|
||||
@@ -44,7 +44,7 @@ T ProfCounters<T>::get(uint32_t id) const {
|
||||
template<typename T>
|
||||
T* ProfCounters<T>::getAddr(uint32_t id) {
|
||||
// allocate a new chunk of counters if necessary
|
||||
if (id >= m_chunks.size() * kCountersPerChunk) {
|
||||
while (id >= m_chunks.size() * kCountersPerChunk) {
|
||||
uint32_t size = sizeof(T) * kCountersPerChunk;
|
||||
T* chunk = (T*)malloc(size);
|
||||
std::fill_n(chunk, kCountersPerChunk, m_initVal);
|
||||
|
||||
@@ -1290,16 +1290,14 @@ bool TranslatorX64::handleServiceRequest(TReqInfo& info,
|
||||
TRACE(2, "enterTC: bindCall smash %p -> %p\n", toSmash, dest);
|
||||
JIT::smashCall(toSmash, dest);
|
||||
smashed = true;
|
||||
// For functions to be PGO'ed, if their prologues haven't been
|
||||
// regenerated yet, then save toSmash as a caller to the
|
||||
// prologue, so that it can later be smashed to call a new
|
||||
// prologue when it's generated.
|
||||
// For functions to be PGO'ed, if their current prologues
|
||||
// are still profiling ones (living in code.prof()), then
|
||||
// save toSmash as a caller to the prologue, so that it can
|
||||
// later be smashed to call a new prologue when it's generated.
|
||||
int calleeNumParams = func->numParams();
|
||||
int calledPrologNumArgs = (nArgs <= calleeNumParams ?
|
||||
nArgs : calleeNumParams + 1);
|
||||
SrcKey calleeSK = {func,
|
||||
func->getEntryForNumArgs(calledPrologNumArgs)};
|
||||
if (profileSrcKey(calleeSK)) {
|
||||
if (code.prof().contains(dest)) {
|
||||
if (isImmutable) {
|
||||
m_profData->addPrologueMainCaller(func, calledPrologNumArgs,
|
||||
toSmash);
|
||||
|
||||
@@ -1979,6 +1979,10 @@
|
||||
"name": "IMAGETYPE_BMP",
|
||||
"value": 6
|
||||
},
|
||||
{
|
||||
"name": "IMAGETYPE_COUNT",
|
||||
"value": 18
|
||||
},
|
||||
{
|
||||
"name": "IMAGETYPE_GIF",
|
||||
"value": 1
|
||||
@@ -2035,6 +2039,10 @@
|
||||
"name": "IMAGETYPE_TIFF_MM",
|
||||
"value": 8
|
||||
},
|
||||
{
|
||||
"name": "IMAGETYPE_UNKNOWN",
|
||||
"value": 0
|
||||
},
|
||||
{
|
||||
"name": "IMAGETYPE_WBMP",
|
||||
"value": 15
|
||||
|
||||
@@ -49,6 +49,10 @@
|
||||
"name": "JSON_FB_EXTRA_ESCAPES",
|
||||
"type": "Int64"
|
||||
},
|
||||
{
|
||||
"name": "JSON_BIGINT_AS_STRING",
|
||||
"type": "Int64"
|
||||
},
|
||||
{
|
||||
"name": "JSON_FB_COLLECTIONS",
|
||||
"type": "Int64"
|
||||
@@ -147,6 +151,12 @@
|
||||
"value": "false",
|
||||
"desc": "When TRUE, returned objects will be converted into associative arrays."
|
||||
},
|
||||
{
|
||||
"name": "depth",
|
||||
"type": "Int32",
|
||||
"value": "512",
|
||||
"desc": "User specified recursion depth."
|
||||
},
|
||||
{
|
||||
"name": "options",
|
||||
"type": "Variant",
|
||||
|
||||
@@ -492,6 +492,30 @@
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "ini_get_all",
|
||||
"desc": "Gets all configuration options",
|
||||
"flags": [
|
||||
],
|
||||
"return": {
|
||||
"type": "VariantMap",
|
||||
"desc": "Returns an associative array with directive names as the array key."
|
||||
},
|
||||
"args": [
|
||||
{
|
||||
"name": "extension",
|
||||
"type": "String",
|
||||
"desc": "An optional extension name. If set, the function return only options specific for that extension.",
|
||||
"value": "null_string"
|
||||
},
|
||||
{
|
||||
"name": "details",
|
||||
"type": "Boolean",
|
||||
"desc": "Retrieve details settings or only the current value for each setting. Default is TRUE (retrieve details).",
|
||||
"value": "true"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "ini_restore",
|
||||
"desc": "Restores a given configuration option to its original value.",
|
||||
|
||||
@@ -0,0 +1,25 @@
|
||||
<?php
|
||||
|
||||
var_dump(strrpos('123456789', '7', -3));
|
||||
var_dump(strrpos('123456789', '7', -1));
|
||||
var_dump(strrpos('123456789', '7'));
|
||||
var_dump(strrpos('123456789', '7', 1));
|
||||
var_dump(strrpos('123456789', '7', 3));
|
||||
|
||||
var_dump(strrpos('123456789', '78', -3));
|
||||
var_dump(strrpos('123456789', '78', -1));
|
||||
var_dump(strrpos('123456789', '78'));
|
||||
var_dump(strrpos('123456789', '78', 1));
|
||||
var_dump(strrpos('123456789', '78', 3));
|
||||
|
||||
var_dump(strripos('123456789', '7', -3));
|
||||
var_dump(strripos('123456789', '7', -1));
|
||||
var_dump(strripos('123456789', '7'));
|
||||
var_dump(strripos('123456789', '7', 1));
|
||||
var_dump(strripos('123456789', '7', 3));
|
||||
|
||||
var_dump(strripos('123456789', '78', -3));
|
||||
var_dump(strripos('123456789', '78', -1));
|
||||
var_dump(strripos('123456789', '78'));
|
||||
var_dump(strripos('123456789', '78', 1));
|
||||
var_dump(strripos('123456789', '78', 3));
|
||||
@@ -0,0 +1,20 @@
|
||||
int(6)
|
||||
int(6)
|
||||
int(6)
|
||||
int(6)
|
||||
int(6)
|
||||
int(6)
|
||||
int(6)
|
||||
int(6)
|
||||
int(6)
|
||||
int(6)
|
||||
int(6)
|
||||
int(6)
|
||||
int(6)
|
||||
int(6)
|
||||
int(6)
|
||||
int(6)
|
||||
int(6)
|
||||
int(6)
|
||||
int(6)
|
||||
int(6)
|
||||
@@ -0,0 +1,18 @@
|
||||
<?php
|
||||
|
||||
function a($class) {
|
||||
print "a\n";
|
||||
}
|
||||
function b($class) {
|
||||
print "b\n";
|
||||
}
|
||||
|
||||
spl_autoload_register('a');
|
||||
spl_autoload_register('b');
|
||||
var_dump(spl_autoload_functions()); // a and b
|
||||
spl_autoload_unregister('b');
|
||||
var_dump(spl_autoload_functions()); // a only
|
||||
spl_autoload_unregister('b');
|
||||
var_dump(spl_autoload_functions()); // still a
|
||||
spl_autoload_unregister('a');
|
||||
var_dump(spl_autoload_functions() === array());
|
||||
@@ -0,0 +1,15 @@
|
||||
array(2) {
|
||||
[0]=>
|
||||
string(1) "a"
|
||||
[1]=>
|
||||
string(1) "b"
|
||||
}
|
||||
array(1) {
|
||||
[0]=>
|
||||
string(1) "a"
|
||||
}
|
||||
array(1) {
|
||||
[0]=>
|
||||
string(1) "a"
|
||||
}
|
||||
bool(true)
|
||||
@@ -0,0 +1,11 @@
|
||||
<?php
|
||||
|
||||
function main() {
|
||||
$doc = new DOMDocument();
|
||||
$root = $doc->createElement('root');
|
||||
var_dump($doc);
|
||||
var_dump($root->ownerDocument);
|
||||
var_dump($root->ownerDocument === $doc);
|
||||
}
|
||||
|
||||
main();
|
||||
@@ -0,0 +1,5 @@
|
||||
object(DOMDocument)#1 (0) {
|
||||
}
|
||||
object(DOMDocument)#1 (0) {
|
||||
}
|
||||
bool(true)
|
||||
@@ -0,0 +1,8 @@
|
||||
<?xml version="1.0" encoding="utf-8" ?>
|
||||
<root>
|
||||
<xi:include
|
||||
xmlns:xi="http://www.w3.org/2001/XInclude"
|
||||
href="xinclude-2.xml"
|
||||
parse="xml"
|
||||
/>
|
||||
</root>
|
||||
@@ -0,0 +1,2 @@
|
||||
<?xml version="1.0" encoding="utf-8" ?>
|
||||
<child />
|
||||
@@ -0,0 +1,13 @@
|
||||
<?php
|
||||
|
||||
function main() {
|
||||
$uri = realpath(__DIR__.'/xinclude-1.xml');
|
||||
$xml = file_get_contents($uri);
|
||||
$doc = new DOMDocument();
|
||||
$doc->loadXML($xml);
|
||||
$doc->documentURI = $uri;
|
||||
$doc->xinclude();
|
||||
var_dump($doc->saveXML());
|
||||
}
|
||||
|
||||
main();
|
||||
@@ -0,0 +1,5 @@
|
||||
string(65) "<?xml version="1.0" encoding="utf-8"?>
|
||||
<root>
|
||||
<child/>
|
||||
</root>
|
||||
"
|
||||
@@ -17,3 +17,5 @@ var_dump(image_type_to_mime_type(IMAGETYPE_IFF));
|
||||
var_dump(image_type_to_mime_type(IMAGETYPE_WBMP));
|
||||
var_dump(image_type_to_mime_type(IMAGETYPE_XBM));
|
||||
var_dump(image_type_to_mime_type(IMAGETYPE_ICO));
|
||||
var_dump(image_type_to_mime_type(IMAGETYPE_UNKNOWN));
|
||||
var_dump(image_type_to_mime_type(IMAGETYPE_COUNT));
|
||||
|
||||
@@ -15,3 +15,5 @@ string(9) "image/iff"
|
||||
string(18) "image/vnd.wap.wbmp"
|
||||
string(9) "image/xbm"
|
||||
string(24) "image/vnd.microsoft.icon"
|
||||
string(24) "application/octet-stream"
|
||||
string(24) "application/octet-stream"
|
||||
|
||||
@@ -13,23 +13,23 @@ $obj = json_decode("[\"a\",1,true,false,null]");
|
||||
var_dump($obj);
|
||||
|
||||
var_dump(json_decode("{z:1}", true));
|
||||
var_dump(json_decode("{z:1}", true, JSON_FB_LOOSE));
|
||||
var_dump(json_decode("{z:1}", true, 512, JSON_FB_LOOSE));
|
||||
var_dump(json_decode("{z:\"z\"}", true));
|
||||
var_dump(json_decode("{z:\"z\"}", true, JSON_FB_LOOSE));
|
||||
var_dump(json_decode("{z:\"z\"}", true, 512, JSON_FB_LOOSE));
|
||||
var_dump(json_decode("{'x':1}", true));
|
||||
var_dump(json_decode("{'x':1}", true, JSON_FB_LOOSE));
|
||||
var_dump(json_decode("{'x':1}", true, 512, JSON_FB_LOOSE));
|
||||
var_dump(json_decode("{y:1,}", true));
|
||||
var_dump(json_decode("{y:1,}", true, JSON_FB_LOOSE));
|
||||
var_dump(json_decode("{y:1,}", true, 512, JSON_FB_LOOSE));
|
||||
var_dump(json_decode("{,}", true));
|
||||
var_dump(json_decode("{,}", true, JSON_FB_LOOSE));
|
||||
var_dump(json_decode("{,}", true, 512, JSON_FB_LOOSE));
|
||||
var_dump(json_decode("[1,2,3,]", true));
|
||||
var_dump(json_decode("[1,2,3,]", true, JSON_FB_LOOSE));
|
||||
var_dump(json_decode("[1,2,3,]", true, 512, JSON_FB_LOOSE));
|
||||
var_dump(json_decode("[,]", true));
|
||||
var_dump(json_decode("[,]", true, JSON_FB_LOOSE));
|
||||
var_dump(json_decode("[,]", true, 512, JSON_FB_LOOSE));
|
||||
var_dump(json_decode("[]", true));
|
||||
var_dump(json_decode("[]", true, JSON_FB_LOOSE));
|
||||
var_dump(json_decode("[]", true, 512, JSON_FB_LOOSE));
|
||||
var_dump(json_decode("{}", true));
|
||||
var_dump(json_decode("{}", true, JSON_FB_LOOSE));
|
||||
var_dump(json_decode("{}", true, 512, JSON_FB_LOOSE));
|
||||
|
||||
var_dump(json_decode("[{\"a\":\"apple\"},{\"b\":\"banana\"}]", true));
|
||||
|
||||
|
||||
@@ -215,7 +215,7 @@ function is_equal($obj1, $obj2) {
|
||||
}
|
||||
|
||||
foreach ($tests as $test) {
|
||||
$output = json_decode($test['input'], true, $test['options']);
|
||||
$output = json_decode($test['input'], true, 512, $test['options']);
|
||||
if (!is_equal($output, $test['expected'])) {
|
||||
report("", $output, $test['expected']);
|
||||
break;
|
||||
|
||||
@@ -0,0 +1,24 @@
|
||||
<?php
|
||||
|
||||
$all_detailed = ini_get_all();
|
||||
var_dump($all_detailed['hphp.compiler_version']['access']);
|
||||
var_dump($all_detailed['allow_url_fopen']);
|
||||
var_dump($all_detailed['arg_separator.output']);
|
||||
|
||||
$all_short = ini_get_all(null, false);
|
||||
var_dump($all_short['hphp.compiler_version']['access']);
|
||||
var_dump($all_short['allow_url_fopen']);
|
||||
var_dump($all_short['arg_separator.output']);
|
||||
|
||||
var_dump(ini_get_all('pcre'));
|
||||
var_dump(ini_get_all('pcre', false));
|
||||
|
||||
var_dump(ini_get_all('pcre_zend_compat', false));
|
||||
|
||||
$core = ini_get_all('core');
|
||||
var_dump(array(
|
||||
'core: allow_url_fopen' => isset($core['allow_url_fopen']),
|
||||
'core: pcre.backtrack_limit' => isset($core['pcre.backtrack_limit']),
|
||||
));
|
||||
|
||||
ini_get_all("THIS_EXTENSION_SHOULD_NOT_EXIST");
|
||||
@@ -0,0 +1,59 @@
|
||||
int(6)
|
||||
array(3) {
|
||||
["global_value"]=>
|
||||
string(1) "1"
|
||||
["local_value"]=>
|
||||
string(1) "1"
|
||||
["access"]=>
|
||||
int(6)
|
||||
}
|
||||
array(3) {
|
||||
["global_value"]=>
|
||||
string(1) "&"
|
||||
["local_value"]=>
|
||||
string(1) "&"
|
||||
["access"]=>
|
||||
int(7)
|
||||
}
|
||||
string(1) "1"
|
||||
string(1) "1"
|
||||
string(1) "&"
|
||||
array(2) {
|
||||
["pcre.backtrack_limit"]=>
|
||||
array(3) {
|
||||
["global_value"]=>
|
||||
string(7) "1000000"
|
||||
["local_value"]=>
|
||||
string(7) "1000000"
|
||||
["access"]=>
|
||||
int(7)
|
||||
}
|
||||
["pcre.recursion_limit"]=>
|
||||
array(3) {
|
||||
["global_value"]=>
|
||||
string(6) "100000"
|
||||
["local_value"]=>
|
||||
string(6) "100000"
|
||||
["access"]=>
|
||||
int(7)
|
||||
}
|
||||
}
|
||||
array(2) {
|
||||
["pcre.backtrack_limit"]=>
|
||||
string(7) "1000000"
|
||||
["pcre.recursion_limit"]=>
|
||||
string(6) "100000"
|
||||
}
|
||||
array(2) {
|
||||
["pcre_zend_compat.backtrack_limit"]=>
|
||||
string(7) "1000000"
|
||||
["pcre_zend_compat.recursion_limit"]=>
|
||||
string(6) "100000"
|
||||
}
|
||||
array(2) {
|
||||
["core: allow_url_fopen"]=>
|
||||
bool(true)
|
||||
["core: pcre.backtrack_limit"]=>
|
||||
bool(false)
|
||||
}
|
||||
HipHop Warning: Unable to find extension 'THIS_EXTENSION_SHOULD_NOT_EXIST' in %s on line 24
|
||||
@@ -27,6 +27,16 @@ function create_listen_random_port() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
function pfsockopen_random_port(&$fsock, $address) {
|
||||
$fsock = false;
|
||||
for ($i = 0; $i < 100; $i++) {
|
||||
$port = get_random_port();
|
||||
$fsock = @pfsockopen($address, $port);
|
||||
if ($fsock !== false) return $port;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
function get_client_server() {
|
||||
$server = socket_create(AF_INET, SOCK_STREAM, SOL_TCP);
|
||||
$port = bind_random_port($server, "127.0.0.1");
|
||||
@@ -100,3 +110,12 @@ if (socket_last_error($s) == 13) {
|
||||
socket_clear_error($s);
|
||||
}
|
||||
var_dump(socket_last_error($s));
|
||||
|
||||
$fsock = false;
|
||||
$port = pfsockopen_random_port($fsock, "udp://[0:0:0:0:0:0:0:1]");
|
||||
var_dump($port != 0);
|
||||
var_dump(fwrite($fsock, "foo") > 0);
|
||||
|
||||
$fsock2 = pfsockopen("udp://[::1]", $port);
|
||||
var_dump($fsock !== false);
|
||||
var_dump(ftell($fsock) == ftell($fsock2));
|
||||
|
||||
@@ -35,3 +35,7 @@ bool(true)
|
||||
NULL
|
||||
bool(true)
|
||||
int(0)
|
||||
bool(true)
|
||||
bool(true)
|
||||
bool(true)
|
||||
bool(true)
|
||||
|
||||
@@ -0,0 +1,38 @@
|
||||
<?php
|
||||
namespace NS;
|
||||
function main() {
|
||||
class B {}
|
||||
class A extends B {
|
||||
public function b() {
|
||||
var_dump(self::class);
|
||||
var_dump(static::class);
|
||||
var_dump(parent::class);
|
||||
}
|
||||
}
|
||||
var_dump(A::class);
|
||||
A::b();
|
||||
|
||||
function c($c = A::class) {
|
||||
var_dump($c);
|
||||
}
|
||||
c();
|
||||
|
||||
var_dump(Vector::class);
|
||||
|
||||
trait C {
|
||||
public function c() {
|
||||
var_dump(self::class);
|
||||
var_dump(static::class);
|
||||
var_dump(parent::class);
|
||||
}
|
||||
}
|
||||
class D extends B {
|
||||
use C;
|
||||
}
|
||||
D::c();
|
||||
var_dump(C::class);
|
||||
|
||||
interface E {}
|
||||
var_dump(E::class);
|
||||
}
|
||||
main();
|
||||
@@ -0,0 +1,11 @@
|
||||
string(4) "NS\A"
|
||||
string(4) "NS\A"
|
||||
string(4) "NS\A"
|
||||
string(4) "NS\B"
|
||||
string(4) "NS\A"
|
||||
string(9) "NS\Vector"
|
||||
string(4) "NS\C"
|
||||
string(4) "NS\D"
|
||||
string(4) "NS\B"
|
||||
string(4) "NS\C"
|
||||
string(4) "NS\E"
|
||||
@@ -0,0 +1,2 @@
|
||||
<?php
|
||||
echo parent::class;
|
||||
@@ -0,0 +1,6 @@
|
||||
<?php
|
||||
|
||||
class C {
|
||||
function foo() { include 'colon_colon_class_include_parent.inc'; }
|
||||
}
|
||||
C::foo();
|
||||
@@ -0,0 +1 @@
|
||||
HipHop Fatal error: Cannont access parent::class when no class scope is active in %s/test/slow/parser/colon_colon_class_include_parent.inc on line 2
|
||||
@@ -0,0 +1,15 @@
|
||||
<?php
|
||||
namespace Foo\Bar;
|
||||
interface A {
|
||||
const SCOPE_CONTAINER = 'container';
|
||||
public function set($scope = self::SCOPE_CONTAINER);
|
||||
}
|
||||
|
||||
function main() {
|
||||
$rc = new \ReflectionClass("Foo\Bar\A");
|
||||
var_dump($rc->isInterface());
|
||||
var_dump($rc->getMethod('set')->getParameters()[0]->getDefaultValue());
|
||||
var_dump($rc->getMethods()[0]->getParameters()[0]->getDefaultValue());
|
||||
}
|
||||
|
||||
main();
|
||||
@@ -0,0 +1,3 @@
|
||||
bool(true)
|
||||
string(9) "container"
|
||||
string(9) "container"
|
||||
@@ -0,0 +1,177 @@
|
||||
<?php
|
||||
require_once(dirname(__FILE__) . DIRECTORY_SEPARATOR . 'config.inc');
|
||||
require_once(dirname(__FILE__) . '/../../pdo/tests/pdo_test.inc');
|
||||
|
||||
class MySQLPDOTest extends PDOTest {
|
||||
|
||||
static function factory($classname = 'PDO', $drop_test_tables = false, $myattr = null, $mydsn = null) {
|
||||
|
||||
$dsn = self::getDSN($mydsn);
|
||||
$user = PDO_MYSQL_TEST_USER;
|
||||
$pass = PDO_MYSQL_TEST_PASS;
|
||||
$attr = getenv('PDOTEST_ATTR');
|
||||
|
||||
if (is_string($attr) && strlen($attr)) {
|
||||
$attr = unserialize($attr);
|
||||
} else {
|
||||
$attr = null;
|
||||
}
|
||||
if ($user === false)
|
||||
$user = NULL;
|
||||
if ($pass === false)
|
||||
$pass = NULL;
|
||||
|
||||
$db = new $classname($dsn, $user, $pass, $attr);
|
||||
if (!$db) {
|
||||
die("Could not create PDO object (DSN=$dsn, user=$user)\n");
|
||||
}
|
||||
|
||||
$db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_WARNING);
|
||||
$db->setAttribute(PDO::ATTR_CASE, PDO::CASE_LOWER);
|
||||
|
||||
return $db;
|
||||
}
|
||||
|
||||
static function createTestTable($db, $engine = null) {
|
||||
if (!$engine)
|
||||
$engine = PDO_MYSQL_TEST_ENGINE;
|
||||
|
||||
$db->exec('DROP TABLE IF EXISTS test');
|
||||
$db->exec('CREATE TABLE test(id INT, label CHAR(1), PRIMARY KEY(id)) ENGINE=' . $engine);
|
||||
$db->exec("INSERT INTO test(id, label) VALUES (1, 'a'), (2, 'b'), (3, 'c'), (4, 'd'), (5, 'e'), (6, 'f')");
|
||||
}
|
||||
|
||||
static function getTableEngine() {
|
||||
return PDO_MYSQL_TEST_ENGINE;
|
||||
}
|
||||
|
||||
|
||||
static function getDSN($new_options = null, $addition = '') {
|
||||
if (!$new_options)
|
||||
return PDO_MYSQL_TEST_DSN . $addition;
|
||||
|
||||
$old_options = array();
|
||||
$dsn = substr(PDO_MYSQL_TEST_DSN,
|
||||
strpos(PDO_MYSQL_TEST_DSN, ':') + 1,
|
||||
strlen(PDO_MYSQL_TEST_DSN));
|
||||
|
||||
// no real parser - any excotic setting can fool us
|
||||
$parts = explode(';', $dsn);
|
||||
foreach ($parts as $k => $v) {
|
||||
$tmp = explode('=', $v);
|
||||
if (count($tmp) == 2)
|
||||
$old_options[$tmp[0]] = $tmp[1];
|
||||
}
|
||||
|
||||
$options = $old_options;
|
||||
foreach ($new_options as $k => $v)
|
||||
$options[$k] = $v;
|
||||
|
||||
$dsn = 'mysql:';
|
||||
foreach ($options as $k => $v)
|
||||
$dsn .= sprintf('%s=%s;', $k, $v);
|
||||
|
||||
if ($addition)
|
||||
$dsn .= $addition;
|
||||
else
|
||||
$dsn = substr($dsn, 0, strlen($dsn) -1);
|
||||
|
||||
return $dsn;
|
||||
}
|
||||
|
||||
static function getClientVersion($db) {
|
||||
return self::extractVersion($db->getAttribute(PDO::ATTR_CLIENT_VERSION));
|
||||
}
|
||||
|
||||
static function getServerVersion($db) {
|
||||
return self::extractVersion($db->getAttribute(PDO::ATTR_SERVER_VERSION));
|
||||
}
|
||||
|
||||
static function extractVersion($version_string) {
|
||||
/*
|
||||
TODO:
|
||||
We're a bit in trouble: PDO_MYSQL returns version strings.
|
||||
That's wrong according to the manual. According to the manual
|
||||
integers should be returned. However, this code needs to work
|
||||
with stinky PDO_MYSQL and hopefully better PDO_MYSQLND.
|
||||
*/
|
||||
|
||||
// already an int value?
|
||||
if (is_int($version_string))
|
||||
return $version_string;
|
||||
|
||||
// string but int value?
|
||||
$tmp = (int)$version_string;
|
||||
if (((string)$tmp) === $version_string)
|
||||
return $tmp;
|
||||
|
||||
// stinky string which we need to parse
|
||||
$parts = explode('.', $version_string);
|
||||
if (count($parts) != 3)
|
||||
return -1;
|
||||
|
||||
$version = (int)$parts[0] * 10000;
|
||||
$version+= (int)$parts[1] * 100;
|
||||
$version+= (int)$parts[2];
|
||||
|
||||
return $version;
|
||||
}
|
||||
|
||||
static function getTempDir() {
|
||||
|
||||
if (!function_exists('sys_get_temp_dir')) {
|
||||
|
||||
if (!empty($_ENV['TMP']))
|
||||
return realpath( $_ENV['TMP'] );
|
||||
if (!empty($_ENV['TMPDIR']))
|
||||
return realpath( $_ENV['TMPDIR'] );
|
||||
if (!empty($_ENV['TEMP']))
|
||||
return realpath( $_ENV['TEMP'] );
|
||||
|
||||
$temp_file = tempnam(md5(uniqid(rand(), TRUE)), '');
|
||||
if ($temp_file) {
|
||||
$temp_dir = realpath(dirname($temp_file));
|
||||
unlink($temp_file);
|
||||
return $temp_dir;
|
||||
}
|
||||
return FALSE;
|
||||
} else {
|
||||
return sys_get_temp_dir();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static function detect_transactional_mysql_engine($db) {
|
||||
foreach ($db->query("show variables like 'have%'") as $row) {
|
||||
if (!empty($row) && $row[1] == 'YES' && ($row[0] == 'have_innodb' || $row[0] == 'have_bdb')) {
|
||||
return str_replace("have_", "", $row[0]);
|
||||
}
|
||||
}
|
||||
/* MySQL 5.6.1+ */
|
||||
foreach ($db->query("SHOW ENGINES") as $row) {
|
||||
if (isset($row['engine']) && isset($row['support'])) {
|
||||
if ('InnoDB' == $row['engine'] && ('YES' == $row['support'] || 'DEFAULT' == $row['support']))
|
||||
return 'innodb';
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static function isPDOMySQLnd() {
|
||||
ob_start();
|
||||
phpinfo();
|
||||
$tmp = ob_get_contents();
|
||||
ob_end_clean();
|
||||
return (preg_match('/PDO Driver for MySQL.*enabled/', $tmp) &&
|
||||
preg_match('/Client API version.*mysqlnd/', $tmp));
|
||||
}
|
||||
|
||||
static function dropTestTable($db = NULL) {
|
||||
if (is_null($db))
|
||||
$db = self::factory();
|
||||
|
||||
$db->exec('DROP TABLE IF EXISTS test');
|
||||
}
|
||||
|
||||
}
|
||||
?>
|
||||
@@ -0,0 +1,177 @@
|
||||
<?php
|
||||
require_once(dirname(__FILE__) . DIRECTORY_SEPARATOR . 'config.inc');
|
||||
require_once(dirname(__FILE__) . '/../../pdo/tests/pdo_test.inc');
|
||||
|
||||
class MySQLPDOTest extends PDOTest {
|
||||
|
||||
static function factory($classname = 'PDO', $drop_test_tables = false, $myattr = null, $mydsn = null) {
|
||||
|
||||
$dsn = self::getDSN($mydsn);
|
||||
$user = PDO_MYSQL_TEST_USER;
|
||||
$pass = PDO_MYSQL_TEST_PASS;
|
||||
$attr = getenv('PDOTEST_ATTR');
|
||||
|
||||
if (is_string($attr) && strlen($attr)) {
|
||||
$attr = unserialize($attr);
|
||||
} else {
|
||||
$attr = null;
|
||||
}
|
||||
if ($user === false)
|
||||
$user = NULL;
|
||||
if ($pass === false)
|
||||
$pass = NULL;
|
||||
|
||||
$db = new $classname($dsn, $user, $pass, $attr);
|
||||
if (!$db) {
|
||||
die("Could not create PDO object (DSN=$dsn, user=$user)\n");
|
||||
}
|
||||
|
||||
$db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_WARNING);
|
||||
$db->setAttribute(PDO::ATTR_CASE, PDO::CASE_LOWER);
|
||||
|
||||
return $db;
|
||||
}
|
||||
|
||||
static function createTestTable($db, $engine = null) {
|
||||
if (!$engine)
|
||||
$engine = PDO_MYSQL_TEST_ENGINE;
|
||||
|
||||
$db->exec('DROP TABLE IF EXISTS test');
|
||||
$db->exec('CREATE TABLE test(id INT, label CHAR(1), PRIMARY KEY(id)) ENGINE=' . $engine);
|
||||
$db->exec("INSERT INTO test(id, label) VALUES (1, 'a'), (2, 'b'), (3, 'c'), (4, 'd'), (5, 'e'), (6, 'f')");
|
||||
}
|
||||
|
||||
static function getTableEngine() {
|
||||
return PDO_MYSQL_TEST_ENGINE;
|
||||
}
|
||||
|
||||
|
||||
static function getDSN($new_options = null, $addition = '') {
|
||||
if (!$new_options)
|
||||
return PDO_MYSQL_TEST_DSN . $addition;
|
||||
|
||||
$old_options = array();
|
||||
$dsn = substr(PDO_MYSQL_TEST_DSN,
|
||||
strpos(PDO_MYSQL_TEST_DSN, ':') + 1,
|
||||
strlen(PDO_MYSQL_TEST_DSN));
|
||||
|
||||
// no real parser - any excotic setting can fool us
|
||||
$parts = explode(';', $dsn);
|
||||
foreach ($parts as $k => $v) {
|
||||
$tmp = explode('=', $v);
|
||||
if (count($tmp) == 2)
|
||||
$old_options[$tmp[0]] = $tmp[1];
|
||||
}
|
||||
|
||||
$options = $old_options;
|
||||
foreach ($new_options as $k => $v)
|
||||
$options[$k] = $v;
|
||||
|
||||
$dsn = 'mysql:';
|
||||
foreach ($options as $k => $v)
|
||||
$dsn .= sprintf('%s=%s;', $k, $v);
|
||||
|
||||
if ($addition)
|
||||
$dsn .= $addition;
|
||||
else
|
||||
$dsn = substr($dsn, 0, strlen($dsn) -1);
|
||||
|
||||
return $dsn;
|
||||
}
|
||||
|
||||
static function getClientVersion($db) {
|
||||
return self::extractVersion($db->getAttribute(PDO::ATTR_CLIENT_VERSION));
|
||||
}
|
||||
|
||||
static function getServerVersion($db) {
|
||||
return self::extractVersion($db->getAttribute(PDO::ATTR_SERVER_VERSION));
|
||||
}
|
||||
|
||||
static function extractVersion($version_string) {
|
||||
/*
|
||||
TODO:
|
||||
We're a bit in trouble: PDO_MYSQL returns version strings.
|
||||
That's wrong according to the manual. According to the manual
|
||||
integers should be returned. However, this code needs to work
|
||||
with stinky PDO_MYSQL and hopefully better PDO_MYSQLND.
|
||||
*/
|
||||
|
||||
// already an int value?
|
||||
if (is_int($version_string))
|
||||
return $version_string;
|
||||
|
||||
// string but int value?
|
||||
$tmp = (int)$version_string;
|
||||
if (((string)$tmp) === $version_string)
|
||||
return $tmp;
|
||||
|
||||
// stinky string which we need to parse
|
||||
$parts = explode('.', $version_string);
|
||||
if (count($parts) != 3)
|
||||
return -1;
|
||||
|
||||
$version = (int)$parts[0] * 10000;
|
||||
$version+= (int)$parts[1] * 100;
|
||||
$version+= (int)$parts[2];
|
||||
|
||||
return $version;
|
||||
}
|
||||
|
||||
static function getTempDir() {
|
||||
|
||||
if (!function_exists('sys_get_temp_dir')) {
|
||||
|
||||
if (!empty($_ENV['TMP']))
|
||||
return realpath( $_ENV['TMP'] );
|
||||
if (!empty($_ENV['TMPDIR']))
|
||||
return realpath( $_ENV['TMPDIR'] );
|
||||
if (!empty($_ENV['TEMP']))
|
||||
return realpath( $_ENV['TEMP'] );
|
||||
|
||||
$temp_file = tempnam(md5(uniqid(rand(), TRUE)), '');
|
||||
if ($temp_file) {
|
||||
$temp_dir = realpath(dirname($temp_file));
|
||||
unlink($temp_file);
|
||||
return $temp_dir;
|
||||
}
|
||||
return FALSE;
|
||||
} else {
|
||||
return sys_get_temp_dir();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static function detect_transactional_mysql_engine($db) {
|
||||
foreach ($db->query("show variables like 'have%'") as $row) {
|
||||
if (!empty($row) && $row[1] == 'YES' && ($row[0] == 'have_innodb' || $row[0] == 'have_bdb')) {
|
||||
return str_replace("have_", "", $row[0]);
|
||||
}
|
||||
}
|
||||
/* MySQL 5.6.1+ */
|
||||
foreach ($db->query("SHOW ENGINES") as $row) {
|
||||
if (isset($row['engine']) && isset($row['support'])) {
|
||||
if ('InnoDB' == $row['engine'] && ('YES' == $row['support'] || 'DEFAULT' == $row['support']))
|
||||
return 'innodb';
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static function isPDOMySQLnd() {
|
||||
ob_start();
|
||||
phpinfo();
|
||||
$tmp = ob_get_contents();
|
||||
ob_end_clean();
|
||||
return (preg_match('/PDO Driver for MySQL.*enabled/', $tmp) &&
|
||||
preg_match('/Client API version.*mysqlnd/', $tmp));
|
||||
}
|
||||
|
||||
static function dropTestTable($db = NULL) {
|
||||
if (is_null($db))
|
||||
$db = self::factory();
|
||||
|
||||
$db->exec('DROP TABLE IF EXISTS test');
|
||||
}
|
||||
|
||||
}
|
||||
?>
|
||||
+22
-22
@@ -1,22 +1,22 @@
|
||||
<?php
|
||||
require_once(dirname(__FILE__) . DIRECTORY_SEPARATOR . 'mysql_pdo_test.inc');
|
||||
|
||||
/* Connect to mysql to determine the current charset so we can diffinate it */
|
||||
$link = MySQLPDOTest::factory();
|
||||
$charset = $link->query("SHOW VARIABLES LIKE 'character_set_connection'")->fetchObject()->value;
|
||||
|
||||
/* Make sure that we don't attempt to set the current character set to make this case useful */
|
||||
$new_charset = ($charset == 'latin1' ? 'ascii' : 'latin1');
|
||||
|
||||
/* Done with the original connection, create a second link to test the character set being defined */
|
||||
unset($link);
|
||||
|
||||
$link = MySQLPDOTest::factory('PDO', false, null, Array('charset' => $new_charset));
|
||||
$conn_charset = $link->query("SHOW VARIABLES LIKE 'character_set_connection'")->fetchObject()->value;
|
||||
|
||||
if ($charset !== $conn_charset) {
|
||||
echo "done!\n";
|
||||
} else {
|
||||
echo "failed!\n";
|
||||
}
|
||||
?>
|
||||
<?php
|
||||
require_once(dirname(__FILE__) . DIRECTORY_SEPARATOR . 'mysql_pdo_test.inc');
|
||||
|
||||
/* Connect to mysql to determine the current charset so we can diffinate it */
|
||||
$link = MySQLPDOTest::factory();
|
||||
$charset = $link->query("SHOW VARIABLES LIKE 'character_set_connection'")->fetchObject()->value;
|
||||
|
||||
/* Make sure that we don't attempt to set the current character set to make this case useful */
|
||||
$new_charset = ($charset == 'latin1' ? 'ascii' : 'latin1');
|
||||
|
||||
/* Done with the original connection, create a second link to test the character set being defined */
|
||||
unset($link);
|
||||
|
||||
$link = MySQLPDOTest::factory('PDO', false, null, Array('charset' => $new_charset));
|
||||
$conn_charset = $link->query("SHOW VARIABLES LIKE 'character_set_connection'")->fetchObject()->value;
|
||||
|
||||
if ($charset !== $conn_charset) {
|
||||
echo "done!\n";
|
||||
} else {
|
||||
echo "failed!\n";
|
||||
}
|
||||
?>
|
||||
@@ -0,0 +1,7 @@
|
||||
<?php
|
||||
|
||||
if (!extension_loaded("pdo_mysql")) exit("skip pdo_mysql extension not loaded");
|
||||
|
||||
if (false === getenv('PDO_MYSQL_TEST_DSN')) exit("skip PDO_MYSQL_TEST_DSN env variable is not defined");
|
||||
if (false === getenv('PDO_MYSQL_TEST_USER')) exit("skip PDO_MYSQL_TEST_USER env variable is not defined");
|
||||
if (false === getenv('PDO_MYSQL_TEST_PASS')) exit("skip PDO_MYSQL_TEST_PASS env variable is not defined");
|
||||
Alguns arquivos não foram exibidos porque demasiados arquivos foram alterados neste diff Mostrar Mais
Referência em uma Nova Issue
Bloquear um usuário