bool HHVM_FUNCTION(pcntl_signal, int signo, const Variant& handler, bool restart_syscalls /* = true */) { /* Special long value case for SIG_DFL and SIG_IGN */ if (handler.isInteger()) { int64_t handle = handler.toInt64(); if (handle != (long)SIG_DFL && handle != (long)SIG_IGN) { raise_warning("Invalid value for handle argument specified"); } if (php_signal(signo, (Sigfunc *)handle, restart_syscalls) == SIG_ERR) { raise_warning("Error assigning signal"); return false; } return true; } if (!is_callable(handler)) { raise_warning("%s is not a callable function name error", handler.toString().data()); return false; } s_signal_handlers->handlers.set(signo, handler); if (php_signal(signo, pcntl_signal_handler, restart_syscalls) == SIG_ERR) { raise_warning("Error assigning signal"); return false; } return true; }
bool PDOSqliteResource::createFunction(const String& name, const Variant& callback, int argcount) { if (!is_callable(callback)) { raise_warning("function '%s' is not callable", callback.toString().data()); return false; } auto udf = req::make_unique<UDF>(); udf->func = callback; udf->argc = argcount; udf->name = name.toCppString(); auto stat = sqlite3_create_function( conn()->m_db, udf->name.c_str(), argcount, SQLITE_UTF8, static_cast<SQLite3::UserDefinedFunc*>(udf.get()), php_sqlite3_callback_func, nullptr, nullptr ); if (stat != SQLITE_OK) { return false; } m_udfs.emplace_back(std::move(udf)); return true; }
T* try_convert() const { if(!is_callable()) { return NULL; } return dynamic_cast<T*>(mutable_callable()); }
void HHVM_METHOD(ZMQSocket, __construct, const Object& context, int64_t type, const Variant& persistentId, const Variant& newSocketCallback) { auto sock = Native::data<ZMQSocket>(this_); auto ctx = Native::data<ZMQContext>(context); bool isNew = false; auto data = ZMQSocketData::get(ctx->context, type, persistentId, isNew); if (!data) { throwExceptionClassZMQErr(s_ZMQSocketExceptionClass, "Error creating socket: {}", errno); } sock->socket = data; if (!ctx->context->is_persistent) { sock->context_obj = context; } if (isNew) { if (!newSocketCallback.isNull()) { if (!is_callable(newSocketCallback)) { throwExceptionClass(s_ZMQSocketExceptionClass, "Invalid callback", PHP_ZMQ_INTERNAL_ERROR); } vm_call_user_func(newSocketCallback, make_packed_array(Object(this_), persistentId)); } } if (data->is_persistent) { sock->persistent_id = persistentId; ZMQSocketData::set(data, type, persistentId); } }
bool PDOSqliteConnection::createFunction(const String& name, const Variant& callback, int argcount) { if (!is_callable(callback)) { raise_warning("function '%s' is not callable", callback.toString().data()); return false; } auto udf = std::make_shared<UDF>(); udf->func = callback; udf->argc = argcount; udf->name = name.toCppString(); auto stat = sqlite3_create_function(m_db, udf->name.c_str(), argcount, SQLITE_UTF8, udf.get(), php_sqlite3_callback_func, nullptr, nullptr); if (stat != SQLITE_OK) { return false; } m_udfs.push_back(udf); return true; }
bool HHVM_METHOD(SQLite3, createfunction, const String& name, const Variant& callback, int64_t argcount /* = -1 */) { auto *data = Native::data<SQLite3>(this_); data->validate(); if (name.empty()) { return false; } if (!is_callable(callback)) { raise_warning("Not a valid callback function %s", callback.toString().data()); return false; } auto udf = std::make_shared<SQLite3::UserDefinedFunc>(); if (sqlite3_create_function(data->m_raw_db, name.data(), argcount, SQLITE_UTF8, udf.get(), php_sqlite3_callback_func, nullptr, nullptr) == SQLITE_OK) { udf->func = callback; udf->argc = argcount; data->m_udfs.push_back(udf); return true; } return false; }
variant variant::get_member(const std::string& str) const { if(is_callable()) { return callable_->query_value(str); } if(str == "self") { return *this; } else { return variant(); } }
static bool HHVM_FUNCTION( readline_completion_function, const Variant& function) { if (!is_callable(function)) { raise_warning( "readline_completion_function(): %s is not callable", function.toString().data()); return false; } s_readline->completion = function; rl_attempted_completion_function = readline_completion_cb; return true; }
Variant HHVM_FUNCTION(preg_replace_callback, const Variant& pattern, const Variant& callback, const Variant& subject, int limit /* = -1 */, VRefParam count /* = null */) { if (!is_callable(callback)) { raise_warning("Not a valid callback function %s", callback.toString().data()); return empty_string_variant(); } return preg_replace_impl(pattern, callback, subject, limit, count.getVariantOrNull(), true, false); }
bool TypeConstraint::checkTypeAliasNonObj(const TypedValue* tv) const { assert(tv->m_type != KindOfObject); assert(isObject()); auto p = getTypeAliasOrClassWithAutoload(m_namedEntity, m_typeName); auto td = p.first; auto c = p.second; // Common case is that we actually find the alias: if (td) { if (td->nullable && tv->m_type == KindOfNull) return true; auto result = annotCompat(tv->m_type, td->type, td->klass ? td->klass->name() : nullptr); switch (result) { case AnnotAction::Pass: return true; case AnnotAction::Fail: return false; case AnnotAction::CallableCheck: return is_callable(tvAsCVarRef(tv)); case AnnotAction::DictCheck: return tv->m_data.parr->isDict(); case AnnotAction::VecCheck: return tv->m_data.parr->isVecArray(); case AnnotAction::ObjectCheck: break; } assert(result == AnnotAction::ObjectCheck); assert(td->type == AnnotType::Object); // Fall through to the check below, since this could be a type // alias to an enum type c = td->klass; } // Otherwise, this isn't a proper type alias, but it *might* be a // first-class enum. Check if the type is an enum and check the // constraint if it is. We only need to do this when the underlying // type is not an object, since only int and string can be enums. if (c && isEnum(c)) { auto dt = c->enumBaseTy(); // For an enum, if the underlying type is mixed, we still require // it is either an int or a string! if (dt) { return equivDataTypes(*dt, tv->m_type); } else { return isIntType(tv->m_type) || isStringType(tv->m_type); } } return false; }
Variant HHVM_FUNCTION(header_register_callback, const Variant& callback) { if (!is_callable(callback)) { raise_warning("First argument is expected to be a valid callback"); return init_null(); } auto transport = g_context->getTransport(); if (!transport) { // fail if there is no transport return false; } if (transport->headersSent()) { // fail if headers have already been sent return false; } return g_context->setHeaderCallback(callback); }
Variant HHVM_FUNCTION(preg_replace_callback_array, const Variant& patterns_and_callbacks, const Variant& subject, int limit /* = -1 */, VRefParam count /* = uninit_null() */) { if (!patterns_and_callbacks.isArray()) { raise_warning( "%s() expects parameter 1 to be an array, %s given", __FUNCTION__+2 /* +2 removes the "f_" prefix */, getDataTypeString(patterns_and_callbacks.getType()).c_str() ); return init_null(); } // Now see if we need to raise any warnings because of not having a // valid callback function for (ArrayIter iter(patterns_and_callbacks.toArray()); iter; ++iter) { if (!is_callable(iter.second())) { raise_warning("Not a valid callback function %s", iter.second().toString().data()); return subject.isString() ? empty_string_variant() : Variant(empty_array()); } } if (subject.isString()) { Array subject_arr = Array::Create(); subject_arr.add(0, subject.toString()); Variant ret = preg_replace_callback_array_impl( patterns_and_callbacks, subject_arr, limit, count ); // ret[0] could be an empty string return ret.isArray() ? ret.toArray()[0] : init_null(); } else if (subject.isArray()) { return preg_replace_callback_array_impl( patterns_and_callbacks, subject.toArray(), limit, count ); } else { // No warning is given here, just return null return init_null(); } }
static Variant xml_call_handler(const req::ptr<XmlParser>& parser, const Variant& handler, const Array& args) { if (parser && handler.toBoolean()) { Variant retval; if (handler.isString() && !name_contains_class(handler.toString())) { if (!parser->object.isObject()) { retval = invoke(handler.toString().c_str(), args, -1); } else { retval = parser->object.toObject()-> o_invoke(handler.toString(), args); } } else if (is_callable(handler)) { vm_call_user_func(handler, args); } else { raise_warning("Handler is invalid"); } return retval; } return init_null(); }
/* ECMA-262 5.1 Edition 15.12.3 (abstract operation Str) */ static HRESULT stringify(stringify_ctx_t *ctx, jsval_t val) { jsval_t value; HRESULT hres; if(is_object_instance(val) && get_object(val)) { jsdisp_t *obj; DISPID id; obj = iface_to_jsdisp((IUnknown*)get_object(val)); if(!obj) return S_FALSE; hres = jsdisp_get_id(obj, toJSONW, 0, &id); jsdisp_release(obj); if(hres == S_OK) FIXME("Use toJSON.\n"); } /* FIXME: Support replacer replacer. */ hres = maybe_to_primitive(ctx->ctx, val, &value); if(FAILED(hres)) return hres; switch(jsval_type(value)) { case JSV_NULL: if(!append_string(ctx, nullW)) hres = E_OUTOFMEMORY; break; case JSV_BOOL: if(!append_string(ctx, get_bool(value) ? trueW : falseW)) hres = E_OUTOFMEMORY; break; case JSV_STRING: { jsstr_t *str = get_string(value); const WCHAR *ptr = jsstr_flatten(str); if(ptr) hres = json_quote(ctx, ptr, jsstr_length(str)); else hres = E_OUTOFMEMORY; break; } case JSV_NUMBER: { double n = get_number(value); if(is_finite(n)) { const WCHAR *ptr; jsstr_t *str; /* FIXME: Optimize. There is no need for jsstr_t here. */ hres = double_to_string(n, &str); if(FAILED(hres)) break; ptr = jsstr_flatten(str); assert(ptr != NULL); hres = ptr && !append_string_len(ctx, ptr, jsstr_length(str)) ? E_OUTOFMEMORY : S_OK; jsstr_release(str); }else { if(!append_string(ctx, nullW)) hres = E_OUTOFMEMORY; } break; } case JSV_OBJECT: { jsdisp_t *obj; obj = iface_to_jsdisp((IUnknown*)get_object(value)); if(!obj) { hres = S_FALSE; break; } if(!is_callable(obj)) hres = is_class(obj, JSCLASS_ARRAY) ? stringify_array(ctx, obj) : stringify_object(ctx, obj); else hres = S_FALSE; jsdisp_release(obj); break; } case JSV_UNDEFINED: hres = S_FALSE; break; case JSV_VARIANT: FIXME("VARIANT\n"); hres = E_NOTIMPL; break; } jsval_release(value); return hres; }
bool TypeConstraint::check(TypedValue* tv, const Func* func) const { assert(hasConstraint() && !isTypeVar() && !isMixed() && !isTypeConstant()); // This is part of the interpreter runtime; perf matters. if (tv->m_type == KindOfRef) { tv = tv->m_data.pref->tv(); } if (isNullable() && tv->m_type == KindOfNull) { return true; } if (tv->m_type == KindOfObject) { // Perfect match seems common enough to be worth skipping the hash // table lookup. const Class *c = nullptr; if (isObject()) { if (m_typeName->isame(tv->m_data.pobj->getVMClass()->name())) { if (isProfileRequest()) InstanceBits::profile(m_typeName); return true; } // We can't save the Class* since it moves around from request // to request. assert(m_namedEntity); c = Unit::lookupClass(m_namedEntity); } else { switch (metaType()) { case MetaType::Self: selfToClass(func, &c); break; case MetaType::Parent: parentToClass(func, &c); break; case MetaType::Callable: return is_callable(tvAsCVarRef(tv)); case MetaType::Precise: case MetaType::Number: case MetaType::ArrayKey: case MetaType::Dict: case MetaType::Vec: return false; case MetaType::Mixed: // We assert'd at the top of this function that the // metatype cannot be Mixed not_reached(); } } if (isProfileRequest() && c) { InstanceBits::profile(c->preClass()->name()); } if (c && tv->m_data.pobj->instanceof(c)) { return true; } return isObject() && checkTypeAliasObj(tv->m_data.pobj->getVMClass()); } auto const result = annotCompat(tv->m_type, m_type, m_typeName); switch (result) { case AnnotAction::Pass: return true; case AnnotAction::Fail: return false; case AnnotAction::CallableCheck: return is_callable(tvAsCVarRef(tv)); case AnnotAction::DictCheck: return tv->m_data.parr->isDict(); case AnnotAction::VecCheck: return tv->m_data.parr->isVecArray(); case AnnotAction::ObjectCheck: assert(isObject()); return checkTypeAliasNonObj(tv); } not_reached(); }
static void xslt_ext_function_php(xmlXPathParserContextPtr ctxt, int nargs, int type) { XSLTProcessorData *intern = nullptr; int error = 0; xsltTransformContextPtr tctxt = xsltXPathGetTransformContext (ctxt); if (tctxt == nullptr) { xsltGenericError(xsltGenericErrorContext, "xsltExtFunctionTest: failed to get the transformation context\n" ); error = 1; } else { intern = (XSLTProcessorData*)tctxt->_private; if (intern == nullptr) { xsltGenericError(xsltGenericErrorContext, "xsltExtFunctionTest: failed to get the internal object\n" ); error = 1; } else { if (intern->m_registerPhpFunctions == 0) { xsltGenericError(xsltGenericErrorContext, "xsltExtFunctionTest: PHP Object did not register PHP functions\n" ); error = 1; } } } xmlXPathObjectPtr obj; if (error == 1) { for (int i = nargs - 1; i >= 0; i--) { obj = valuePop(ctxt); xmlXPathFreeObject(obj); } return; } Array args; // Reverse order to pop values off ctxt stack for (int i = nargs - 2; i >= 0; i--) { Variant arg; obj = valuePop(ctxt); switch (obj->type) { case XPATH_STRING: arg = String((char*)obj->stringval, CopyString); break; case XPATH_BOOLEAN: arg = (bool)obj->boolval; break; case XPATH_NUMBER: arg = (double)obj->floatval; break; case XPATH_NODESET: if (type == 1) { char *str = (char*)xmlXPathCastToString(obj); arg = String(str, CopyString); xmlFree(str); } else if (type == 2) { arg = Array::Create(); if (obj->nodesetval && obj->nodesetval->nodeNr > 0) { for (int j = 0; j < obj->nodesetval->nodeNr; j++) { // TODO: not sure this is the right thing to do. xmlNodePtr node = obj->nodesetval->nodeTab[j]; if (node->type == XML_ELEMENT_NODE) { Object element = newNode(s_DOMElement, xmlCopyNode(node, /*extended*/ 1)); arg.toArrRef().append(element); } else if (node->type == XML_ATTRIBUTE_NODE) { Object attribute = newNode(s_DOMAttr, (xmlNodePtr)xmlCopyProp(nullptr, (xmlAttrPtr)node)); arg.toArrRef().append(attribute); } else if (node->type == XML_TEXT_NODE) { Object text = newNode(s_DOMText, (xmlNodePtr)xmlNewText(xmlNodeGetContent(node))); arg.toArrRef().append(text); } else { raise_warning("Unhandled node type '%d'", node->type); // Use a generic DOMNode as fallback for now. Object nodeobj = newNode(s_DOMNode, xmlCopyNode(node, /*extended*/ 1)); arg.toArrRef().append(nodeobj); } } } } break; default: arg = String((char*)xmlXPathCastToString(obj), CopyString); } xmlXPathFreeObject(obj); args.prepend(arg); } obj = valuePop(ctxt); if (obj->stringval == nullptr) { raise_warning("Handler name must be a string"); xmlXPathFreeObject(obj); // Push an empty string to get an xslt result. valuePush(ctxt, xmlXPathNewString((xmlChar*)"")); return; } String handler((char*)obj->stringval, CopyString); xmlXPathFreeObject(obj); if (!is_callable(handler)) { raise_warning("Unable to call handler %s()", handler.data()); // Push an empty string to get an xslt result. valuePush(ctxt, xmlXPathNewString((xmlChar*)"")); } else if (intern->m_registerPhpFunctions == 2 && !intern->m_registered_phpfunctions.exists(handler)) { raise_warning("Not allowed to call handler '%s()'", handler.data()); // Push an empty string to get an xslt result. valuePush(ctxt, xmlXPathNewString((xmlChar*)"")); } else { Variant retval = vm_call_user_func(handler, args); if (retval.isObject() && retval.getObjectData()->instanceof(s_DOMNode)) { ObjectData *retval_data = retval.asCObjRef().get(); xmlNode* nodep = Native::data<DOMNode>(retval_data)->nodep(); valuePush(ctxt, xmlXPathNewNodeSet(nodep)); intern->m_usedElements.prepend(retval); } else if (retval.is(KindOfBoolean)) { valuePush(ctxt, xmlXPathNewBoolean(retval.toBoolean())); } else if (retval.isObject()) { raise_warning("A PHP Object cannot be converted to an XPath-string"); // Push an empty string to get an xslt result. valuePush(ctxt, xmlXPathNewString((xmlChar*)"")); } else { String sretval = retval.toString(); valuePush(ctxt, xmlXPathNewString((xmlChar*)sretval.data())); } } }