예제 #1
0
bool f_pcntl_signal(int signo, CVarRef 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 (!f_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;
}
예제 #2
0
ssize_t GlobalArrayWrapper::getIndex(CVarRef k,
                                     int64 prehash /* = -1*/) const {
  if (k.isInteger()) {
    return ((Array*)m_globals)->get()->getIndex(k.toInt64(), prehash) +
      m_globals->size();
  }
  return m_globals->getIndex(k.toString().data(), prehash);
}
예제 #3
0
Variant BaseVector::get(CVarRef key) {
  if (key.isInteger()) {
    TypedValue* tv = get(key.toInt64());
    if (tv) {
      return tvAsCVarRef(tv);
    } else {
      return uninit_null();
    }
  }
  throwBadKeyType();
  return uninit_null();
}
예제 #4
0
void c_DebuggerClientCmdUser::t_addcompletion(CVarRef list) {
  INSTANCE_METHOD_INJECTION_BUILTIN(DebuggerClientCmdUser, DebuggerClientCmdUser::addcompletion);
  if (list.isInteger()) {
    m_client->addCompletion((DebuggerClient::AutoComplete)list.toInt64());
  } else {
    Array arr = list.toArray(); // handles string, array and iterators
    std::vector<std::string> items;
    for (ArrayIter iter(arr); iter; ++iter) {
      items.push_back(iter.second().toString()->toCPPString());
    }
    m_client->addCompletion(items);
  }
}
예제 #5
0
void MapVariant::renumber() {
    const std::vector<Variant> &keys = getKeyVector();

    HphpMapVariantToInt newmap;
    m_nextIndex = 0;
    for (unsigned int i = 0; i < keys.size(); i++) {
        CVarRef key = keys[i];
        if (key.isInteger()) {
            Variant newkey((int64)m_nextIndex++);
            newmap[newkey] = m_map[key];
        } else {
            newmap[key] = m_map[key];
        }
    }
    m_map.swap(newmap);

    resetKeyVector();
}
예제 #6
0
bool BuiltinSymbols::Load(AnalysisResultPtr ar, bool extOnly /* = false */) {
    if (Loaded) return true;
    Loaded = true;

    // load extension functions first, so system/classes may call them
    ParseExtFunctions(ar, ExtensionFunctions, false);
    AnalysisResultPtr ar2 = AnalysisResultPtr(new AnalysisResult());
    s_variables = VariableTablePtr(new VariableTable(*ar2.get()));
    s_constants = ConstantTablePtr(new ConstantTable(*ar2.get()));

    // parse all PHP files under system/classes
    if (!extOnly) {
        ar = AnalysisResultPtr(new AnalysisResult());
        ar->loadBuiltinFunctions();
        string slib = systemlib_path();
        if (slib.empty()) {
            for (const char **cls = SystemClasses; *cls; cls++) {
                string phpBaseName = "/system/classes/";
                phpBaseName += *cls;
                phpBaseName += ".php";
                Parse(ar, phpBaseName, Option::GetSystemRoot() + phpBaseName);
            }
        } else {
            Parse(ar, slib, slib);
        }
        ar->analyzeProgram(true);
        ar->inferTypes();
        const StringToFileScopePtrMap &files = ar->getAllFiles();
        for (StringToFileScopePtrMap::const_iterator iterFile = files.begin();
                iterFile != files.end(); iterFile++) {
            const StringToClassScopePtrVecMap &classes =
                iterFile->second->getClasses();
            for (StringToClassScopePtrVecMap::const_iterator iter = classes.begin();
                    iter != classes.end(); ++iter) {
                assert(iter->second.size() == 1);
                iter->second[0]->setSystem();
                assert(!s_classes[iter->first]);
                s_classes[iter->first] = iter->second[0];
            }
        }
    } else {
        NoSuperGlobals = true;
    }

    // load extension constants, classes and dynamics
    ParseExtConsts(ar, ExtensionConsts, false);
    ParseExtClasses(ar, ExtensionClasses, false);
    for (unsigned int i = 0; i < Option::SepExtensions.size(); i++) {
        Option::SepExtensionOptions &options = Option::SepExtensions[i];
        string soname = options.soname;
        if (soname.empty()) {
            soname = string("lib") + options.name + ".so";
        }
        if (!options.lib_path.empty()) {
            soname = options.lib_path + "/" + soname;
        }
        if (!LoadSepExtensionSymbols(ar, options.name, soname)) {
            return false;
        }
    }

    if (!extOnly) {
        Array constants = ClassInfo::GetSystemConstants();
        LocationPtr loc(new Location);
        for (ArrayIter it = constants.begin(); it; ++it) {
            CVarRef key = it.first();
            if (!key.isString()) continue;
            std::string name = key.toCStrRef().data();
            if (s_constants->getSymbol(name)) continue;
            if (name == "true" || name == "false" || name == "null") continue;
            CVarRef value = it.secondRef();
            if (!value.isInitialized() || value.isObject()) continue;
            ExpressionPtr e = Expression::MakeScalarExpression(ar2, ar2, loc, value);
            TypePtr t =
                value.isNull()    ? Type::Null    :
                value.isBoolean() ? Type::Boolean :
                value.isInteger() ? Type::Int64   :
                value.isDouble()  ? Type::Double  :
                value.isArray()   ? Type::Array   : Type::Variant;

            s_constants->add(key.toCStrRef().data(), t, e, ar2, e);
        }
        s_variables = ar2->getVariables();
        for (int i = 0, n = NumGlobalNames(); i < n; ++i) {
            s_variables->add(GlobalNames[i], Type::Variant, false, ar,
                             ConstructPtr(), ModifierExpressionPtr());
        }
    }
    s_constants->setDynamic(ar, "SID", true);

    return true;
}
예제 #7
0
bool BuiltinSymbols::Load(AnalysisResultPtr ar) {
  if (Loaded) return true;
  Loaded = true;

  if (g_context.isNull()) init_thread_locals();
  ClassInfo::Load();

  // load extension functions first, so system/php may call them
  ImportExtFunctions(ar, ClassInfo::GetSystem());

  ConstantTablePtr cns = ar->getConstants();
  // load extension constants, classes and dynamics
  ImportNativeConstants(ar, cns);
  ImportExtConstants(ar, cns, ClassInfo::GetSystem());
  ImportExtClasses(ar);

  Array constants = ClassInfo::GetSystemConstants();
  LocationPtr loc(new Location);
  for (ArrayIter it = constants.begin(); it; ++it) {
    CVarRef key = it.first();
    if (!key.isString()) continue;
    std::string name = key.toCStrRef().data();
    if (cns->getSymbol(name)) continue;
    if (name == "true" || name == "false" || name == "null") continue;
    CVarRef value = it.secondRef();
    if (!value.isInitialized() || value.isObject()) continue;
    ExpressionPtr e = Expression::MakeScalarExpression(ar, ar, loc, value);
    TypePtr t =
      value.isNull()    ? Type::Null    :
      value.isBoolean() ? Type::Boolean :
      value.isInteger() ? Type::Int64   :
      value.isDouble()  ? Type::Double  :
      value.isArray()   ? Type::Array   : Type::Variant;

    cns->add(key.toCStrRef().data(), t, e, ar, e);
  }
  for (int i = 0, n = NumGlobalNames(); i < n; ++i) {
    ar->getVariables()->add(GlobalNames[i], Type::Variant, false, ar,
                            ConstructPtr(), ModifierExpressionPtr());
  }

  cns->setDynamic(ar, "PHP_BINARY", true);
  cns->setDynamic(ar, "PHP_BINDIR", true);
  cns->setDynamic(ar, "PHP_OS", true);
  cns->setDynamic(ar, "PHP_SAPI", true);
  cns->setDynamic(ar, "SID", true);

  // Systemlib files were all parsed by hphp_process_init

  const StringToFileScopePtrMap &files = ar->getAllFiles();
  for (const auto& file : files) {
    file.second->setSystem();

    const auto& classes = file.second->getClasses();
    for (const auto& clsVec : classes) {
      assert(clsVec.second.size() == 1);
      auto cls = clsVec.second[0];
      cls->setSystem();
      ar->addSystemClass(cls);
      for (const auto& func : cls->getFunctions()) {
        FunctionScope::RecordFunctionInfo(func.first, func.second);
      }
    }

    const auto& functions = file.second->getFunctions();
    for (const auto& func : functions) {
      func.second->setSystem();
      ar->addSystemFunction(func.second);
      FunctionScope::RecordFunctionInfo(func.first, func.second);
    }
  }

  return true;
}
예제 #8
0
std::string CmdPrint::FormatResult(const char *format, CVarRef ret) {
  if (format == nullptr) {
    String sret = DebuggerClient::FormatVariable(ret, -1);
    return string(sret.data(), sret.size());
  }

  if (strcmp(format, "v") == 0) {
    String sret = DebuggerClient::FormatVariable(ret, -1, true);
    return string(sret.data(), sret.size());
  }

  if (strcmp(format, "dec") == 0 ||
      strcmp(format, "unsigned") == 0 ||
      ret.isInteger()) {
    int64 nret = ret.toInt64();
    char buf[64];
    if (strcmp(format, "hex") == 0 || strcmp(format, "x") == 0) {
      snprintf(buf, sizeof(buf), "%" PRIx64, nret);
      return buf;
    }
    if (strcmp(format, "oct") == 0) {
      snprintf(buf, sizeof(buf), "%" PRIo64, nret);
      return buf;
    }
    if (strcmp(format, "dec") == 0) {
      snprintf(buf, sizeof(buf), "%" PRId64, nret);
      return buf;
    }
    if (strcmp(format, "unsigned") == 0) {
      snprintf(buf, sizeof(buf), "%" PRIu64, nret);
      return buf;
    }
    if (strcmp(format, "time") == 0) {
      StringBuffer sb;
      DateTime dt(nret);
      sb.append("RFC822:            ");
      sb.append(dt.toString(DateTime::RFC822));
      sb.append("\nRFC850:            ");
      sb.append(dt.toString(DateTime::RFC850));
      sb.append("\nRFC1036:           ");
      sb.append(dt.toString(DateTime::RFC1036));
      sb.append("\nRFC1123/RSS:       ");
      sb.append(dt.toString(DateTime::RFC1123));
      sb.append("\nRFC2822:           ");
      sb.append(dt.toString(DateTime::RFC2822));
      sb.append("\nRFC3339/ATOM/W3C:  ");
      sb.append(dt.toString(DateTime::RFC3339));
      sb.append("\nISO8601:           ");
      sb.append(dt.toString(DateTime::ISO8601));
      sb.append("\nCookie:            ");
      sb.append(dt.toString(DateTime::Cookie));
      sb.append("\nHttpHeader:        ");
      sb.append(dt.toString(DateTime::HttpHeader));
      return sb.data();
    }

    assert(false);
  }

  String sret = DebuggerClient::FormatVariable(ret, -1);
  if (strcmp(format, "hex") == 0 || strcmp(format, "x") == 0 ||
      strcmp(format, "oct") == 0) {
    StringBuffer sb;
    for (int i = 0; i < sret.size(); i++) {
      char ch = sret[i];
      if (isprint(ch)) {
        sb.append(ch);
      } else {
        char buf[6];
        if (strcmp(format, "oct") == 0) {
          snprintf(buf, sizeof(buf), "\\%03o", ch);
        } else {
          snprintf(buf, sizeof(buf), "\\x%02x", ch);
        }
        sb.append(buf);
      }
    }
    return sb.data() ? sb.data() : "";
  }
  if (strcmp(format, "time") == 0) {
    DateTime dt;
    int64 ts = -1;
    if (dt.fromString(ret.toString(), SmartObject<TimeZone>())) {
      bool err;
      ts = dt.toTimeStamp(err);
    }
    return String(ts).data();
  }

  assert(false);
  return "";
}
예제 #9
0
bool ArrayData::IsValidKey(CVarRef k) {
  return k.isInteger() ||
         (k.isString() && IsValidKey(k.getStringData()));
}
예제 #10
0
파일: ext_curl.cpp 프로젝트: Dx3webs/hhvm
  bool setOption(long option, CVarRef value) {
    if (m_cp == NULL) {
      return false;
    }
    m_error_no = CURLE_OK;

    switch (option) {
    case CURLOPT_INFILESIZE:
    case CURLOPT_VERBOSE:
    case CURLOPT_HEADER:
    case CURLOPT_NOPROGRESS:
    case CURLOPT_NOBODY:
    case CURLOPT_FAILONERROR:
    case CURLOPT_UPLOAD:
    case CURLOPT_POST:
    case CURLOPT_FTPLISTONLY:
    case CURLOPT_FTPAPPEND:
    case CURLOPT_NETRC:
    case CURLOPT_PUT:
    case CURLOPT_TIMEOUT:
#if LIBCURL_VERSION_NUM >= 0x071002
    case CURLOPT_TIMEOUT_MS:
#endif
    case CURLOPT_FTP_USE_EPSV:
    case CURLOPT_LOW_SPEED_LIMIT:
    case CURLOPT_SSLVERSION:
    case CURLOPT_LOW_SPEED_TIME:
    case CURLOPT_RESUME_FROM:
    case CURLOPT_TIMEVALUE:
    case CURLOPT_TIMECONDITION:
    case CURLOPT_TRANSFERTEXT:
    case CURLOPT_HTTPPROXYTUNNEL:
    case CURLOPT_FILETIME:
    case CURLOPT_MAXREDIRS:
    case CURLOPT_MAXCONNECTS:
    case CURLOPT_CLOSEPOLICY:
    case CURLOPT_FRESH_CONNECT:
    case CURLOPT_FORBID_REUSE:
    case CURLOPT_CONNECTTIMEOUT:
#if LIBCURL_VERSION_NUM >= 0x071002
    case CURLOPT_CONNECTTIMEOUT_MS:
#endif
    case CURLOPT_SSL_VERIFYHOST:
    case CURLOPT_SSL_VERIFYPEER:
      //case CURLOPT_DNS_USE_GLOBAL_CACHE: not thread-safe when set to true
    case CURLOPT_NOSIGNAL:
    case CURLOPT_PROXYTYPE:
    case CURLOPT_BUFFERSIZE:
    case CURLOPT_HTTPGET:
    case CURLOPT_HTTP_VERSION:
    case CURLOPT_CRLF:
    case CURLOPT_DNS_CACHE_TIMEOUT:
    case CURLOPT_PROXYPORT:
    case CURLOPT_FTP_USE_EPRT:
    case CURLOPT_HTTPAUTH:
    case CURLOPT_PROXYAUTH:
    case CURLOPT_FTP_CREATE_MISSING_DIRS:
    case CURLOPT_FTPSSLAUTH:
    case CURLOPT_FTP_SSL:
    case CURLOPT_UNRESTRICTED_AUTH:
    case CURLOPT_PORT:
    case CURLOPT_AUTOREFERER:
    case CURLOPT_COOKIESESSION:
    case CURLOPT_TCP_NODELAY:
    case CURLOPT_IPRESOLVE:
    case CURLOPT_FOLLOWLOCATION:
      m_error_no = curl_easy_setopt(m_cp, (CURLoption)option, value.toInt64());
      break;
    case CURLOPT_RETURNTRANSFER:
      m_write.method = value.toBoolean() ? PHP_CURL_RETURN : PHP_CURL_STDOUT;
      break;
    case CURLOPT_BINARYTRANSFER:
      m_write.type = value.toBoolean() ? PHP_CURL_BINARY : PHP_CURL_ASCII;
      break;
    case CURLOPT_PRIVATE:
    case CURLOPT_URL:
    case CURLOPT_PROXY:
    case CURLOPT_USERPWD:
    case CURLOPT_PROXYUSERPWD:
    case CURLOPT_RANGE:
    case CURLOPT_CUSTOMREQUEST:
    case CURLOPT_USERAGENT:
    case CURLOPT_FTPPORT:
    case CURLOPT_COOKIE:
    case CURLOPT_REFERER:
    case CURLOPT_INTERFACE:
    case CURLOPT_KRB4LEVEL:
    case CURLOPT_EGDSOCKET:
    case CURLOPT_CAINFO:
    case CURLOPT_CAPATH:
    case CURLOPT_SSL_CIPHER_LIST:
    case CURLOPT_SSLKEY:
    case CURLOPT_SSLKEYTYPE:
    case CURLOPT_SSLKEYPASSWD:
    case CURLOPT_SSLENGINE:
    case CURLOPT_SSLENGINE_DEFAULT:
    case CURLOPT_SSLCERTTYPE:
    case CURLOPT_ENCODING:
    case CURLOPT_COOKIEJAR:
    case CURLOPT_SSLCERT:
    case CURLOPT_RANDOM_FILE:
    case CURLOPT_COOKIEFILE:
      {
        String svalue = value.toString();
#if LIBCURL_VERSION_NUM >= 0x071100
        /* Strings passed to libcurl as 'char *' arguments, are copied
           by the library... NOTE: before 7.17.0 strings were not copied. */
        m_error_no = curl_easy_setopt(m_cp, (CURLoption)option, svalue.c_str());
#else
        char *copystr = strndup(svalue.data(), svalue.size());
        m_to_free->str.push_back(copystr);
        m_error_no = curl_easy_setopt(m_cp, (CURLoption)option, copystr);
#endif
        if (option == CURLOPT_URL) m_url = value;
      }
      break;
    case CURLOPT_FILE:
    case CURLOPT_INFILE:
    case CURLOPT_WRITEHEADER:
    case CURLOPT_STDERR:
      {
        if (!value.isResource()) {
          return false;
        }

        Resource obj = value.toResource();
        if (obj.isNull() || obj.getTyped<File>(true) == NULL) {
          return false;
        }

        switch (option) {
          case CURLOPT_FILE:
            m_write.fp = obj;
            m_write.method = PHP_CURL_FILE;
            break;
          case CURLOPT_WRITEHEADER:
            m_write_header.fp = obj;
            m_write_header.method = PHP_CURL_FILE;
            break;
          case CURLOPT_INFILE:
            m_read.fp = obj;
            m_emptyPost = false;
            break;
          default: {
            if (obj.getTyped<PlainFile>(true) == NULL) {
              return false;
            }
            FILE *fp = obj.getTyped<PlainFile>()->getStream();
            if (!fp) {
              return false;
            }
            m_error_no = curl_easy_setopt(m_cp, (CURLoption)option, fp);
            break;
          }
        }
      }
      break;
    case CURLOPT_WRITEFUNCTION:
      m_write.callback = value;
      m_write.method = PHP_CURL_USER;
      break;
    case CURLOPT_READFUNCTION:
      m_read.callback = value;
      m_read.method = PHP_CURL_USER;
      m_emptyPost = false;
      break;
    case CURLOPT_HEADERFUNCTION:
      m_write_header.callback = value;
      m_write_header.method = PHP_CURL_USER;
      break;
    case CURLOPT_POSTFIELDS:
      m_emptyPost = false;
      if (value.is(KindOfArray) || value.is(KindOfObject)) {
        Array arr = value.toArray();
        curl_httppost *first = NULL;
        curl_httppost *last  = NULL;
        for (ArrayIter iter(arr); iter; ++iter) {
          String key = iter.first().toString();
          String val = iter.second().toString();
          const char *postval = val.data();

          /* The arguments after _NAMELENGTH and _CONTENTSLENGTH
           * must be explicitly cast to long in curl_formadd
           * use since curl needs a long not an int. */
          if (*postval == '@') {
            ++postval;
            m_error_no = (CURLcode)curl_formadd
              (&first, &last,
               CURLFORM_COPYNAME, key.data(),
               CURLFORM_NAMELENGTH, (long)key.size(),
               CURLFORM_FILE, postval,
               CURLFORM_END);
          } else {
            m_error_no = (CURLcode)curl_formadd
              (&first, &last,
               CURLFORM_COPYNAME, key.data(),
               CURLFORM_NAMELENGTH, (long)key.size(),
               CURLFORM_COPYCONTENTS, postval,
               CURLFORM_CONTENTSLENGTH,(long)val.size(),
               CURLFORM_END);
          }
        }

        if (m_error_no != CURLE_OK) {
          return false;
        }

        m_to_free->post.push_back(first);
        m_error_no = curl_easy_setopt(m_cp, CURLOPT_HTTPPOST, first);

      } else {
        String svalue = value.toString();
#if LIBCURL_VERSION_NUM >= 0x071100
        /* with curl 7.17.0 and later, we can use COPYPOSTFIELDS,
           but we have to provide size before */
        m_error_no = curl_easy_setopt(m_cp, CURLOPT_POSTFIELDSIZE,
                                      svalue.size());
        m_error_no = curl_easy_setopt(m_cp, CURLOPT_COPYPOSTFIELDS,
                                      svalue.c_str());
#else
        char *post = strndup(svalue.data(), svalue.size());
        m_to_free->str.push_back(post);

        m_error_no = curl_easy_setopt(m_cp, CURLOPT_POSTFIELDS, post);
        m_error_no = curl_easy_setopt(m_cp, CURLOPT_POSTFIELDSIZE,
                                      svalue.size());
#endif
      }
      break;
    case CURLOPT_HTTPHEADER:
    case CURLOPT_QUOTE:
    case CURLOPT_HTTP200ALIASES:
    case CURLOPT_POSTQUOTE:
      if (value.is(KindOfArray) || value.is(KindOfObject)) {
        Array arr = value.toArray();
        curl_slist *slist = NULL;
        for (ArrayIter iter(arr); iter; ++iter) {
          String key = iter.first().toString();
          String val = iter.second().toString();

          slist = curl_slist_append(slist, val.c_str());
          if (!slist) {
            raise_warning("Could not build curl_slist");
            return false;
          }
        }

        m_to_free->slist.push_back(slist);
        m_error_no = curl_easy_setopt(m_cp, (CURLoption)option, slist);

      } else {
        raise_warning("You must pass either an object or an array with "
                      "the CURLOPT_HTTPHEADER, CURLOPT_QUOTE, "
                      "CURLOPT_HTTP200ALIASES and CURLOPT_POSTQUOTE "
                      "arguments");
        return false;
      }
      break;

    case CURLINFO_HEADER_OUT:
      if (value.toInt64() == 1) {
        curl_easy_setopt(m_cp, CURLOPT_DEBUGFUNCTION, curl_debug);
        curl_easy_setopt(m_cp, CURLOPT_DEBUGDATA, (void *)this);
        curl_easy_setopt(m_cp, CURLOPT_VERBOSE, 1);
      } else {
        curl_easy_setopt(m_cp, CURLOPT_DEBUGFUNCTION, NULL);
        curl_easy_setopt(m_cp, CURLOPT_DEBUGDATA, NULL);
        curl_easy_setopt(m_cp, CURLOPT_VERBOSE, 0);
      }
      break;

    case CURLOPT_FB_TLS_VER_MAX:
      {
        int64_t val = value.toInt64();
        if (value.isInteger() &&
            (val == CURLOPT_FB_TLS_VER_MAX_1_0 ||
             val == CURLOPT_FB_TLS_VER_MAX_1_1 ||
             val == CURLOPT_FB_TLS_VER_MAX_NONE)) {
            m_opts.set(int64_t(option), value);
        } else {
          raise_warning("You must pass CURLOPT_FB_TLS_VER_MAX_1_0, "
                        "CURLOPT_FB_TLS_VER_MAX_1_1 or "
                        "CURLOPT_FB_TLS_VER_MAX_NONE with "
                        "CURLOPT_FB_TLS_VER_MAX");
        }
      }
      break;
    case CURLOPT_FB_TLS_CIPHER_SPEC:
      if (value.isString() && !value.toString().empty()) {
        m_opts.set(int64_t(option), value);
      } else {
        raise_warning("CURLOPT_FB_TLS_CIPHER_SPEC requires a non-empty string");
      }
      break;

    default:
      m_error_no = CURLE_FAILED_INIT;
      throw_invalid_argument("option: %ld", option);
      break;
    }

    m_opts.set(int64_t(option), value);

    return m_error_no == CURLE_OK;
  }
예제 #11
0
bool BuiltinSymbols::Load(AnalysisResultPtr ar, bool extOnly /* = false */) {
  if (Loaded) return true;
  Loaded = true;

  if (g_context.isNull()) init_thread_locals();
  ClassInfo::Load();

  // load extension functions first, so system/classes may call them
  ImportExtFunctions(ar, s_functions, ClassInfo::GetSystem());
  AnalysisResultPtr ar2 = AnalysisResultPtr(new AnalysisResult());
  s_variables = VariableTablePtr(new VariableTable(*ar2.get()));
  s_constants = ConstantTablePtr(new ConstantTable(*ar2.get()));

  // parse all PHP files under system/classes
  if (!extOnly) {
    ar = AnalysisResultPtr(new AnalysisResult());
    ar->loadBuiltinFunctions();
    string slib = get_systemlib();

    Scanner scanner(slib.c_str(), slib.size(),
                    Option::ScannerType, "systemlib.php");
    Compiler::Parser parser(scanner, "systemlib.php", ar);
    if (!parser.parse()) {
      Logger::Error("Unable to parse systemlib.php: %s",
                    parser.getMessage().c_str());
      assert(false);
    }

    ar->analyzeProgram(true);
    ar->inferTypes();
    const StringToFileScopePtrMap &files = ar->getAllFiles();
    for (StringToFileScopePtrMap::const_iterator iterFile = files.begin();
         iterFile != files.end(); iterFile++) {
      const StringToClassScopePtrVecMap &classes =
        iterFile->second->getClasses();
      for (StringToClassScopePtrVecMap::const_iterator iter = classes.begin();
           iter != classes.end(); ++iter) {
        assert(iter->second.size() == 1);
        iter->second[0]->setSystem();
        assert(!s_classes[iter->first]);
        s_classes[iter->first] = iter->second[0];
      }
    }
  } else {
    NoSuperGlobals = true;
  }

  // load extension constants, classes and dynamics
  ImportExtConstants(ar, s_constants, ClassInfo::GetSystem());
  ImportExtClasses(ar);

  if (!extOnly) {
    Array constants = ClassInfo::GetSystemConstants();
    LocationPtr loc(new Location);
    for (ArrayIter it = constants.begin(); it; ++it) {
      CVarRef key = it.first();
      if (!key.isString()) continue;
      std::string name = key.toCStrRef().data();
      if (s_constants->getSymbol(name)) continue;
      if (name == "true" || name == "false" || name == "null") continue;
      CVarRef value = it.secondRef();
      if (!value.isInitialized() || value.isObject()) continue;
      ExpressionPtr e = Expression::MakeScalarExpression(ar2, ar2, loc, value);
      TypePtr t =
        value.isNull()    ? Type::Null    :
        value.isBoolean() ? Type::Boolean :
        value.isInteger() ? Type::Int64   :
        value.isDouble()  ? Type::Double  :
        value.isArray()   ? Type::Array   : Type::Variant;

      s_constants->add(key.toCStrRef().data(), t, e, ar2, e);
    }
    s_variables = ar2->getVariables();
    for (int i = 0, n = NumGlobalNames(); i < n; ++i) {
      s_variables->add(GlobalNames[i], Type::Variant, false, ar,
                       ConstructPtr(), ModifierExpressionPtr());
    }
  }
  s_constants->setDynamic(ar, "SID", true);

  return true;
}