25 Commits

Autor SHA1 Mensagem Data
Paul Tarjan 14e4d2d21c stop killing the socket until all data is sent
For small responses this was ok, since sending the data didn't take much time. For large requests, they would get truncated without this.

I checked for leaks by printing in the FastCGIConnection constructor and destructor and making sure they match up.

Closes #1631

Reviewed By: @simpkins

Differential Revision: D1147016
2014-01-29 11:24:08 -08:00
Fred Emmott 691535343a Fix incorrect ownerDocument after DOMDocument::createElement
Closes #1551

Fixed while investigating an ASAN failure when running PHPUnit's suite.

Reviewed By: @ptarjan

Differential Revision: D1144627
2014-01-28 16:14:37 -08:00
Fred Emmott 08fa42f2cb Fix memory management for xinclude nodes
Previously: ==580== ERROR: AddressSanitizer: attempting free on address which was not malloc()-ed: 0x604400212103

We were recursively freeing the node, including the attribute nodes - however, libxml2 doesn't malloc them separately - all we needed to do was unlink and free the root.

This fixes a fatal in PHPUnit's test suite.

Reviewed By: @ptarjan

Differential Revision: D1144722
2014-01-28 16:14:21 -08:00
Fred Emmott a25e23a681 Fix spl_autoload_unregister($unused_but_valid_handler)
If a valid handler is passed in, but wasn't registered, we'd just remove the last one:

- find_if() would return ::end()
- erase() treats that to mean erase the last one

Behavior in the new test was:
- correctly remove 'b'
- incorrectly remove 'a' when asked to remove 'b' again
- segfault when asked to remove 'b' a third time

Reviewed By: @ptarjan

Differential Revision: D1145531
2014-01-28 16:13:52 -08:00
Fred Emmott 3504e7accf Fix scoping for evaling default ReflectionParameter values
Closes #1449
Closes #1652

Reviewed By: @ptarjan

Differential Revision: D1141045
2014-01-28 16:13:41 -08:00
Paul Saab 8f9ff8b3a4 Prevent garbage on DNS_TXT records
Bug #64458 fixed an off by one error when decoding TXT records
that resulted with garbage at the end of the string returned.

Reviewed By: @scannell

Differential Revision: D1146140
2014-01-28 16:12:55 -08:00
Camillus Gerard Cai 62c4857595 Define missing IMAGETYPE_ constants
Defined IMAGETYPE_UNKNOWN and IMAGETYPE_COUNT

Closes #1634
Closes #1638

Reviewed By: @ptarjan

Differential Revision: D1144855

Pulled By: @scannell
2014-01-28 16:12:48 -08:00
Stuart Loxton 99cfd7c3c7 Fix Zend strrpos compatibility
Fixes Zend strrpos compatibility and adds test.

Closes #1564
Closes #1632

Reviewed By: @bertmaher

Differential Revision: D1142139

Pulled By: @scannell
2014-01-28 16:12:40 -08:00
Erik 352bcbb504 Support for UNIX sockets
Add a new config param, Server.FileSocket. When
Server.FileSocket
is set it will be used inplace of a network socket for the primary
server. This uses a new parameter to ServerOptions, m_useFileSocket,
to toggle between treating the address as a socket path or a network
address.

To initialize a socket connection thrift expects the socket file to not
exist. To support this the 'something nice' retry in startServer will
unlink an existing socket only if fuser claims it is unused.
Server.EvilShutdown enables unlinking the socket regardless of current
users.

Closes #1594

Reviewed By: @ptarjan

Differential Revision: D1135876

Pulled By: @sgolemon
2014-01-28 16:10:41 -08:00
Paul Tarjan 3af6d9ae90 remove assert for ::class and make it fatal instead
If you do `parent::class` in a pseudomain you end up in this case. Zend gives this message in that case

Reviewed By: @elgenie

Differential Revision: D1140116

Conflicts:
	hphp/compiler/analysis/emitter.cpp
2014-01-28 13:49:40 -08:00
Paul Tarjan b8e48ac92d Implement ::class
Done mostly in the parser. There was one weird thing, traits have `self::CLASS` refer to themselves instead of the class that uses them. I had to do runtime support for `parent::CLASS` and `static::CLASS`.

Closes #1096

Reviewed By: @elgenie

Differential Revision: D1129169
2014-01-28 13:48:50 -08:00
Jim Radford 8561dc79d6 LdapLink::sweep shouldn't free smart allocated objects
LdapLink::sweep, avoid freeing smart allocated objects

Closes #1644

Reviewed By: @ptarjan

Differential Revision: D1144565

Pulled By: @scannell
2014-01-28 13:48:44 -08:00
Jim Radford a4f2211d79 UrlFile::sweep shouldn't free smart allocated objs
UrlFile::sweep shouldn't free smart allocated objs

Closes #1643

Reviewed By: @jdelong

Differential Revision: D1144563

Pulled By: @scannell
2014-01-28 13:48:39 -08:00
Paul Tarjan 6561d14139 support SCRIPT_FILENAME
Some fastcgi documentation doesn't tell you to pass all the params, only a handful. Even the official docs say this http://wiki.nginx.org/HttpFastcgiModule I think we should support the mode where we don't know the document root, jsut the absolute filename. I've already had to help 2 people in github with this issue so I think it is prevelant

Reviewed By: @scannell

Differential Revision: D1125309
2014-01-28 13:39:58 -08:00
Arnaud GRANAL 0772c54bb9 pfsockopen returns incorrect connections
Persistent connections currently return a cached connection for (key = "hostname").
Expected behavior is to return a cached connection for (key = "hostname + port").
As a result, persistent connections write and read from the wrong socket if you have multiple connections to the same hostname but different port.

Redis hhvm implementation is affected by this bug (probably other modules too, but not MySQL at least, who uses its own socket cache handler).

Closes #1599

Reviewed By: ps

Differential Revision: D1135971

Pulled By: @scannell
2014-01-28 13:35:45 -08:00
Sean Cannella 3c6d7674ec Add charset= support to PDO mysql DSN
Adds support for charset= in the PDO mysql DSN.

Closes #1309
Closes #1489

Reviewed By: @ptarjan

Differential Revision: D1137883
2014-01-28 13:35:10 -08:00
Ainsley Escorce-Jones 8cd216c0ab json_decode() parity with PHP 5.4
Added depth as the optional third parameter, there is now no
fixed maximum depth for the JSON parser, default depth is still 512, if
a user specifies a larger depth limit then the various stacks are
resized.

JSON_BIGINT_AS_STRING is now supported alongside the FB collection
options.

Closes #1470
Closes #1496

Reviewed By: @ptarjan

Differential Revision: D1117099

Pulled By: @scannell
2014-01-28 13:35:04 -08:00
Fred Emmott e3b61e5a9d Implement ini_get_all()
Used by PHPUnit, as triggered by Mockery

Reviewed By: @ptarjan

Differential Revision: D1136971
2014-01-28 13:34:50 -08:00
Fred Emmott ccebd2ff11 Move magic ini settings out of IniSettings
Pre-req on implementing ini_get_all() sanely.

Reviewed By: @ptarjan

Differential Revision: D1134579
2014-01-28 13:34:42 -08:00
Paul Tarjan 6087e04bf3 document --php
Closes #1610

Reviewed By: @jdelong

Differential Revision: D1145021
2014-01-28 13:34:06 -08:00
Alex Malyshev 8079b5c58e Don't use boost::to_upper
perf is showing that it's calling dynamic_cast, a lot.

Reviewed By: @jdelong

Differential Revision: D1136788
2014-01-28 13:24:12 -08:00
Paul Tarjan 10ddab3b1d keep around rawPostData just incase someone reads from php://input
What do you think about this? Usually we keep it around anyways in a global variable (`$HTTP_RAW_POST_DATA`) but that is possible to turn off, so we need a fool-proof place to put it to support `php://input`. Before this diff, the code only gave the last packet of the header in libevent and asserted on fastcgi.

Thoughts? I think it is worth supporting as the php docs says

http://www.php.net/manual/en/ini.core.php#ini.always-populate-raw-post-data
... the preferred method for accessing the raw POST data is php://input.

Closes #1557

Reviewed By: afrind

Differential Revision: D1129130
2014-01-28 13:22:41 -08:00
Owen Yamauchi 140fe234fc Fix a sandcastle crash due to PGO mode
I'm only 95% convinced that this is the cause of a sandcastle crash.
We're not calling transCounterAddr with sequential translation ids
anymore (apparently) so it's possible that we need to allocate more than
one chunk of new counters.

I ran a sandcastle with this fix applied and it didn't crash, but the
crash wasn't 100% before, so you never know.

Reviewed By: @ottoni

Differential Revision: D1142512
2014-01-28 12:20:17 -08:00
aravind 9dec860d42 Revert "[hh] autoload: don't swallow fatals when autoloading"
: This reverts commit 78e4c601db4c0b6ce55b44ae201fedaf47b65501.

perf regression

Reviewed By: @jdelong
2014-01-28 12:20:17 -08:00
Guilherme Ottoni 247c911c5f Fix rare race condition keeping track of prologue callers
profileSrcKey() compares the request number with
Eval.JitProfileRequests to decide whether or not the given SrcKey will
be generated in profiling mode.  As a result, using profileSrcKey() to
decide whether a given prologue was generated in profile mode or not
was innaccurate: a caller generated in an older request (<
JitProfileRequests) would expect the prologue to be a Proflogue (since
it was JITed beforehand), but the prologue could have been created by
a concurrent, newer request (> JitProfileRequests), which generated the
prologue in non-profiling mode.

This diff fixes the problem by directly checking if the prologue
address is in the profile code section to determine whether it's a
Proflogue or not.

Reviewed By: aravind

Differential Revision: D1141101
2014-01-28 12:20:06 -08:00
101 arquivos alterados com 4376 adições e 3291 exclusões
+5
Ver Arquivo
@@ -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
+19 -6
Ver Arquivo
@@ -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;
Diferenças do arquivo suprimidas por serem muito extensas Carregar Diff
+24
Ver Arquivo
@@ -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
+1
Ver Arquivo
@@ -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
Ver Arquivo
@@ -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
+4
Ver Arquivo
@@ -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) {
+5 -1
Ver Arquivo
@@ -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) {
+22 -19
Ver Arquivo
@@ -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() {
+78 -2
Ver Arquivo
@@ -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() :
+4 -5
Ver Arquivo
@@ -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
Ver Arquivo
@@ -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;
}
///////////////////////////////////////////////////////////////////////////////
}
+19 -4
Ver Arquivo
@@ -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);
///////////////////////////////////////////////////////////////////////////////
}
+3 -9
Ver Arquivo
@@ -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")) {
-12
Ver Arquivo
@@ -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) {}
+3 -2
Ver Arquivo
@@ -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),
+2
Ver Arquivo
@@ -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);
+1
Ver Arquivo
@@ -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;
+3
Ver Arquivo
@@ -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;
+21
Ver Arquivo
@@ -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);
}
+6 -1
Ver Arquivo
@@ -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("://");
+2 -2
Ver Arquivo
@@ -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) {
+44 -17
Ver Arquivo
@@ -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)]) {
+1 -1
Ver Arquivo
@@ -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,
+2 -1
Ver Arquivo
@@ -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);
+1 -1
Ver Arquivo
@@ -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
+9 -2
Ver Arquivo
@@ -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) {
+5 -1
Ver Arquivo
@@ -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);
}
+13 -8
Ver Arquivo
@@ -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();
}
+2 -1
Ver Arquivo
@@ -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.
+4 -1
Ver Arquivo
@@ -67,7 +67,10 @@ public:
LDAP *link;
Variant rebindproc;
};
IMPLEMENT_OBJECT_ALLOCATION(LdapLink)
void LdapLink::sweep() {
close();
}
class LdapResult : public SweepableResourceData {
public:
+13 -9
Ver Arquivo
@@ -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";
+1 -1
Ver Arquivo
@@ -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);
+4
Ver Arquivo
@@ -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) {
}
+1
Ver Arquivo
@@ -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();
+8
Ver Arquivo
@@ -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;
///////////////////////////////////////////////////////////////////////////////
+50 -47
Ver Arquivo
@@ -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);
}
///////////////////////////////////////////////////////////////////////////////
+2 -1
Ver Arquivo
@@ -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) {
+1 -1
Ver Arquivo
@@ -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);
}
+10 -1
Ver Arquivo
@@ -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) {
+12 -12
Ver Arquivo
@@ -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);
}
};
+29 -6
Ver Arquivo
@@ -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());
+9 -1
Ver Arquivo
@@ -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();
+19 -10
Ver Arquivo
@@ -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;
+11 -9
Ver Arquivo
@@ -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;
}
}
}
+47 -12
Ver Arquivo
@@ -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);
}
}
+8
Ver Arquivo
@@ -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(
+6 -1
Ver Arquivo
@@ -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) {
}
+2
Ver Arquivo
@@ -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
+8
Ver Arquivo
@@ -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",
+1 -1
Ver Arquivo
@@ -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);
+5 -7
Ver Arquivo
@@ -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);
+8
Ver Arquivo
@@ -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
+10
Ver Arquivo
@@ -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",
+24
Ver Arquivo
@@ -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.",
+25
Ver Arquivo
@@ -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));
+20
Ver Arquivo
@@ -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)
+8
Ver Arquivo
@@ -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>
+2
Ver Arquivo
@@ -0,0 +1,2 @@
<?xml version="1.0" encoding="utf-8" ?>
<child />
+13
Ver Arquivo
@@ -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>
"
+2
Ver Arquivo
@@ -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));
+2
Ver Arquivo
@@ -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"
+9 -9
Ver Arquivo
@@ -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;
+24
Ver Arquivo
@@ -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
+19
Ver Arquivo
@@ -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)
+38
Ver Arquivo
@@ -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');
}
}
?>
@@ -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