/* * Copyright (c) 1998-2011 Caucho Technology -- all rights reserved * * This file is part of Resin(R) Open Source * * Each copy or derived work must preserve the copyright notice and this * notice unmodified. * * Resin Open Source is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * Resin Open Source is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, or any warranty * of NON-INFRINGEMENT. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License * along with Resin Open Source; if not, write to the * * Free Software Foundation, Inc. * 59 Temple Place, Suite 330 * Boston, MA 02111-1307 USA * * @author Scott Ferguson */ package com.caucho.quercus.env; import com.caucho.java.WorkDir; import com.caucho.quercus.*; import com.caucho.quercus.expr.Expr; import com.caucho.quercus.lib.ErrorModule; import com.caucho.quercus.lib.VariableModule; import com.caucho.quercus.lib.OptionsModule; import com.caucho.quercus.lib.file.FileModule; import com.caucho.quercus.lib.file.PhpStderr; import com.caucho.quercus.lib.file.PhpStdin; import com.caucho.quercus.lib.file.PhpStdout; import com.caucho.quercus.lib.regexp.RegexpState; import com.caucho.quercus.lib.string.StringModule; import com.caucho.quercus.lib.string.StringUtility; import com.caucho.quercus.module.ModuleContext; import com.caucho.quercus.module.ModuleStartupListener; import com.caucho.quercus.module.IniDefinition; import com.caucho.quercus.page.QuercusPage; import com.caucho.quercus.program.*; import com.caucho.quercus.function.AbstractFunction; import com.caucho.quercus.resources.StreamContextResource; import com.caucho.util.*; import com.caucho.vfs.*; import com.caucho.vfs.i18n.EncodingReader; import javax.script.Bindings; import javax.script.ScriptContext; import javax.servlet.ServletContext; import javax.servlet.http.Cookie; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpSession; import javax.sql.DataSource; import java.io.IOException; import java.io.InputStream; import java.lang.ref.WeakReference; import java.net.URL; import java.util.*; import java.util.logging.Level; import java.util.logging.Logger; /** * Represents the Quercus environment. */ public class Env { private static final L10N L = new L10N(Env.class); private static final Logger log = Logger.getLogger(Env.class.getName()); public static final int B_ERROR = 0; public static final int B_WARNING = 1; public static final int B_PARSE = 2; public static final int B_NOTICE = 3; public static final int B_CORE_ERROR = 4; public static final int B_CORE_WARNING = 5; public static final int B_COMPILE_ERROR = 6; public static final int B_COMPILE_WARNING = 7; public static final int B_USER_ERROR = 8; public static final int B_USER_WARNING = 9; public static final int B_USER_NOTICE = 10; public static final int B_STRICT = 11; public static final int B_RECOVERABLE_ERROR = 12; public static final int B_LAST = B_RECOVERABLE_ERROR; public static final int E_ERROR = 1 << B_ERROR; public static final int E_WARNING = 1 << B_WARNING; public static final int E_PARSE = 1 << B_PARSE; public static final int E_NOTICE = 1 << B_NOTICE; public static final int E_CORE_ERROR = 1 << B_CORE_ERROR; public static final int E_CORE_WARNING = 1 << B_CORE_WARNING; public static final int E_COMPILE_ERROR = 1 << B_COMPILE_ERROR; public static final int E_COMPILE_WARNING = 1 << B_COMPILE_WARNING; public static final int E_USER_ERROR = 1 << B_USER_ERROR; public static final int E_USER_WARNING = 1 << B_USER_WARNING; public static final int E_USER_NOTICE = 1 << B_USER_NOTICE; public static final int E_ALL = 6143; //(4096 + 2048 - 1) public static final int E_STRICT = 1 << B_STRICT; public static final int E_RECOVERABLE_ERROR = 1 << B_RECOVERABLE_ERROR; public static final int E_DEFAULT = E_ALL & ~E_NOTICE; private static final int _SERVER = 1; private static final int _GET = 2; private static final int _POST = 3; private static final int _COOKIE = 4; private static final int _GLOBAL = 5; private static final int _REQUEST = 6; private static final int _SESSION = 7; private static final int HTTP_GET_VARS = 8; private static final int HTTP_POST_VARS = 9; private static final int HTTP_COOKIE_VARS = 10; private static final int PHP_SELF = 11; private static final int _FILES = 12; private static final int HTTP_POST_FILES = 13; private static final int _ENV = 14; private static final int HTTP_SERVER_VARS = 15; private static final int HTTP_RAW_POST_DATA = 16; private static final IntMap SPECIAL_VARS = new IntMap(); private static final StringValue PHP_SELF_STRING = new ConstStringValue("PHP_SELF"); private static final StringValue UTF8_STRING = new ConstStringValue("utf-8"); private static final StringValue S_GET = new ConstStringValue("_GET"); private static final StringValue S_POST = new ConstStringValue("_POST"); private static final StringValue S_SESSION = new ConstStringValue("_SESSION"); private static final StringValue S_SERVER = new ConstStringValue("_SERVER"); private static final StringValue S_COOKIE = new ConstStringValue("_COOKIE"); private static final StringValue S_FILES = new ConstStringValue("_FILES"); public static final Value []EMPTY_VALUE = new Value[0]; private static ThreadLocal<Env> _threadEnv = new ThreadLocal<Env>(); private static final FreeList<AbstractFunction[]> _freeFunList = new FreeList<AbstractFunction[]>(256); private static final FreeList<ClassDef[]> _freeClassDefList = new FreeList<ClassDef[]>(256); private static final FreeList<QuercusClass[]> _freeClassList = new FreeList<QuercusClass[]>(256); private static final FreeList<Value[]> _freeConstList = new FreeList<Value[]>(256); private static final FreeList<QDate> _freeGmtDateList = new FreeList<QDate>(256); private static final FreeList<QDate> _freeLocalDateList = new FreeList<QDate>(256); private static final LruCache<String,StringValue> _internStringMap = new LruCache<String,StringValue>(4096); protected final QuercusContext _quercus; private QuercusPage _page; private HashMap<String,Value> _scriptGlobalMap = new HashMap<String,Value>(16); // Function map public AbstractFunction []_fun; // anonymous functions created by create_function() public HashMap<String, AbstractFunction> _anonymousFunMap; // Class map public ClassDef []_classDef; public QuercusClass []_qClass; // Constant map public Value []_const; // Globals private Map<StringValue, EnvVar> _globalMap = new HashMap<StringValue, EnvVar>(); private EnvVar []_globalList; // Statics private Map<StringValue, Var> _staticMap = new HashMap<StringValue, Var>(); // Current env private Map<StringValue, EnvVar> _map = _globalMap; private HashMap<String, Value> _iniMap; // specialMap is used for implicit resources like the mysql link private HashMap<String, Object> _specialMap = new HashMap<String, Object>(); private HashSet<String> _initializedClassSet = new HashSet<String>(); // include_path ini private int _iniCount = 1; private ArrayList<EnvCleanup> _cleanupList; private ArrayList<ObjectExtValue> _objCleanupList; private ArrayList<Shutdown> _shutdownList; private String _defaultIncludePath; private String _includePath; private int _includePathIniCount; private ArrayList<String> _includePathList; private HashMap<Path,ArrayList<Path>> _includePathMap; // XXX: may require a LinkedHashMap for ordering? private HashMap<Path,QuercusPage> _includeMap = new HashMap<Path,QuercusPage>(); private Value _this = NullThisValue.NULL; private final boolean _isUnicodeSemantics; private boolean _isAllowUrlInclude; private boolean _isAllowUrlFopen; private HashMap<StringValue,Path> _lookupCache = new HashMap<StringValue,Path>(); private HashMap<ConnectionEntry,ConnectionEntry> _connMap = new HashMap<ConnectionEntry,ConnectionEntry>(); private AbstractFunction _autoload; private HashSet<String> _autoloadClasses = new HashSet<String>(); private ArrayList<Callable> _autoloadList; private InternalAutoloadCallback _internalAutoload; private Location _location; private long _startTime; private long _timeLimit = 600000L; private long _endTime; private Expr [] _callStack; private Value [] _callThisStack; private Value [][] _callArgStack; private int _callStackTop; private QuercusClass _callingClass; private Value [] _functionArgs; private LinkedList<FieldGetEntry> _fieldGetList = new LinkedList<FieldGetEntry>(); private LinkedList<FieldGetEntry> _fieldSetList = new LinkedList<FieldGetEntry>(); private LinkedList<FieldGetEntry> _issetList = new LinkedList<FieldGetEntry>(); private LinkedList<FieldGetEntry> _unsetList = new LinkedList<FieldGetEntry>(); public enum OVERLOADING_TYPES {INVALID_FIRST, FIELDGET, FIELDSET, ISSET, UNSET, INVALID_LAST}; private Path _selfPath; private Path _selfDirectory; private Path _pwd; private Path _uploadPath; private Path _tmpPath; private ArrayList<Path> _removePaths; private final boolean _isStrict; private HttpServletRequest _request; private HttpServletResponse _response; private ArrayValue _postArray = new ArrayValueImpl(); private ArrayValue _files = new ArrayValueImpl(); private StringValue _inputData; private SessionArrayValue _session; private HttpSession _javaSession; private ScriptContext _scriptContext; private WriteStream _originalOut; private OutputBuffer _outputBuffer; private WriteStream _out; private LocaleInfo _locale; private Callable [] _prevErrorHandlers = new Callback[B_LAST + 1]; private Callable [] _errorHandlers = new Callback[B_LAST + 1]; private Callable _prevExceptionHandler; private Callable _exceptionHandler; private SessionCallback _sessionCallback; private StreamContextResource _defaultStreamContext; private int _objectId = 0; private Logger _logger; // hold special Quercus php import statements private ImportMap _importMap; private TimeZone _defaultTimeZone; private QDate _localDate; private QDate _gmtDate; private Object _gzStream; private Env _oldThreadEnv; private boolean _isTimeout; private long _firstMicroTime; private long _firstNanoTime; private RegexpState _freeRegexpState; private Object _duplex; private StringValue _variablesOrder; private int []_querySeparatorMap; public static final int []DEFAULT_QUERY_SEPARATOR_MAP; private CharBuffer _cb = new CharBuffer(); public Env(QuercusContext quercus, QuercusPage page, WriteStream out, HttpServletRequest request, HttpServletResponse response) { _quercus = quercus; _isStrict = quercus.isStrict(); _isUnicodeSemantics = quercus.isUnicodeSemantics(); _isAllowUrlInclude = quercus.isAllowUrlInclude(); _isAllowUrlFopen = quercus.isAllowUrlFopen(); _variablesOrder = _quercus.getIniValue("variables_order").toStringValue(this); StringValue querySeparators = _quercus.getIniValue("arg_separator.input").toStringValue(this); int len = querySeparators.length(); if (len == 0) _querySeparatorMap = DEFAULT_QUERY_SEPARATOR_MAP; else { _querySeparatorMap = new int[128]; for (int i = 0; i < len; i++) { char ch = querySeparators.charAt(i); _querySeparatorMap[ch] = 1; } } _page = page; // XXX: grab initial from page // _defState = new DefinitionState(quercus); AbstractFunction []defFuns = getDefaultFunctionMap(); _fun = _freeFunList.allocate(); if (_fun == null || _fun.length < defFuns.length) _fun = new AbstractFunction[defFuns.length]; System.arraycopy(defFuns, 0, _fun, 0, defFuns.length); ClassDef []defClasses = quercus.getClassDefMap(); _classDef = _freeClassDefList.allocate(); if (_classDef == null || _classDef.length < defClasses.length) _classDef = new ClassDef[defClasses.length]; else { // list should have been zeroed on call to free } _qClass = _freeClassList.allocate(); if (_qClass == null || _qClass.length < defClasses.length) _qClass = new QuercusClass[defClasses.length]; else { // list should have been zeroed on call to free } Value []defConst = quercus.getConstantMap(); _const = _freeConstList.allocate(); if (_const == null || _const.length < defConst.length) _const = new Value[defConst.length]; else { // list should have been zeroed on call to free } System.arraycopy(defConst, 0, _const, 0, defConst.length); _originalOut = out; _out = out; _request = request; _response = response; if (_page != null) { pageInit(_page); } setPwd(_quercus.getPwd()); if (_page != null) { setSelfPath(_page.getSelfPath(null)); // php/0b32 _includeMap.put(_selfPath, _page); } _internalAutoload = new InternalAutoloadCallback("com/caucho/quercus/php/"); // Define the constant string PHP_VERSION addConstant("PHP_VERSION", OptionsModule.phpversion(this, null), true); // STDIN, STDOUT, STDERR // php://stdin, php://stdout, php://stderr if (response == null) { addConstant("STDOUT", wrapJava(new PhpStdout()), false); addConstant("STDERR", wrapJava(new PhpStderr()), false); addConstant("STDIN", wrapJava(new PhpStdin(this)), false); } } public Env(QuercusContext quercus) { this(quercus, null, null, null, null); } public static Env getCurrent() { return _threadEnv.get(); } public static Env getInstance() { return getCurrent(); } private void fillGet(ArrayValue array, boolean isMagicQuotes) { String queryString = getQueryString(); if (queryString == null || queryString.length() == 0) return; StringUtility.parseStr(this, queryString, array, true, getHttpInputEncoding(), isMagicQuotes, _querySeparatorMap); /* try { String encoding = getHttpInputEncoding(); if (encoding == null) encoding = "iso-8859-1"; _request.setCharacterEncoding(encoding); } catch (Exception e) { log.log(Level.FINE, e.toString(), e); } ArrayList<String> keys = new ArrayList<String>(); keys.addAll(_request.getParameterMap().keySet()); Collections.sort(keys); for (String key : keys) { String []value = _request.getParameterValues(key); Post.addFormValue(this, array, key, value, isMagicQuotes); } */ } private void fillPost(ArrayValue array, ArrayValue postArray) { for (Map.Entry<Value, Value> entry : postArray.entrySet()) { Value key = entry.getKey(); Value value = entry.getValue(); Value existingValue = array.get(key); if (existingValue.isArray() && value.isArray()) existingValue.toArrayValue(this).putAll(value.toArrayValue(this)); else array.put(entry.getKey(), entry.getValue().copy()); } } private void fillCookies(ArrayValue array, Cookie []cookies, boolean isMagicQuotes) { for (int i = 0; cookies != null && i < cookies.length; i++) { Cookie cookie = cookies[i]; String decodedValue = decodeValue(cookie.getValue()); Post.addFormValue(this, array, cookie.getName(), new String[] { decodedValue }, isMagicQuotes); } } protected void fillPost(ArrayValue postArray, ArrayValue files, HttpServletRequest request, boolean isMagicQuotes) { if (request != null && request.getMethod().equals("POST")) { Post.fillPost(this, postArray, files, request, isMagicQuotes, getIniBoolean("file_uploads")); } else if (request != null && ! request.getMethod().equals("GET")) { InputStream is = null; try { is = request.getInputStream(); } catch (IOException e) { warning(e); } StringValue bb = createBinaryBuilder(); bb.appendReadAll(is, Integer.MAX_VALUE); setInputData(bb); } } protected AbstractFunction []getDefaultFunctionMap() { return getQuercus().getFunctionMap(); } /** * Initialize the page, loading any functions and classes */ protected QuercusPage pageInit(QuercusPage page) { if (page.getCompiledPage() != null) page = page.getCompiledPage(); page.init(this); page.importDefinitions(this); return page; } // // script accessible methods // /** * External calls to set a global value. */ public Value setScriptGlobal(String name, Object object) { Value value; if (object instanceof Value) value = (Value) object; else if (object == null) value = NullValue.NULL; else value = wrapJava(object); _scriptGlobalMap.put(name, value); return value; } // // i18n // /** * Returns true if unicode.semantics is on. */ public boolean isUnicodeSemantics() { return _isUnicodeSemantics; } /** * Returns the encoding used for scripts. */ public String getScriptEncoding() { StringValue encoding = getIni("unicode.script_encoding"); if (encoding.length() == 0) { encoding = getIni("unicode.fallback_encoding"); if (encoding.length() == 0) return getQuercus().getScriptEncoding(); } return encoding.toString(); } /** * Returns the encoding used for runtime conversions, e.g. files * XXX: ISO-8859-1 when unicode.semantics is OFF */ public String getRuntimeEncoding() { if (! _isUnicodeSemantics) return "iso-8859-1"; StringValue encoding = getIni("unicode.runtime_encoding"); if (encoding.length() == 0) { encoding = getIni("unicode.fallback_encoding"); if (encoding.length() == 0) encoding = UTF8_STRING; } return encoding.toString(); } /** * Sets the encoding used for runtime conversions. */ public Value setRuntimeEncoding(String encoding) { return setIni("unicode.runtime_encoding", encoding); } /** * Returns the encoding used for runtime conversions, e.g. files */ public EncodingReader getRuntimeEncodingFactory() throws IOException { return Encoding.getReadFactory(getRuntimeEncoding()); } /** * Returns the encoding used for input, i.e. post, * null if unicode.semantics is off. */ public String getHttpInputEncoding() { if (! _isUnicodeSemantics) return null; StringValue encoding = getIni("unicode.http_input_encoding"); if (encoding.length() == 0) { encoding = getIni("unicode.fallback_encoding"); if (encoding.length() == 0) encoding = UTF8_STRING; } return encoding.toString(); } /** * Returns the encoding used for output, null if unicode.semantics is off. */ public String getOutputEncoding() { if (! _isUnicodeSemantics) return null; String encoding = QuercusContext.INI_UNICODE_OUTPUT_ENCODING .getAsString(this); if (encoding == null) encoding = QuercusContext.INI_UNICODE_FALLBACK_ENCODING.getAsString(this); if (encoding == null) encoding = "utf-8"; return encoding; } /** * Creates a binary builder. */ public StringValue createBinaryBuilder() { if (_isUnicodeSemantics) return new BinaryBuilderValue(); else return new StringBuilderValue(); } /** * Creates a binary builder for large things like files. */ public StringValue createLargeBinaryBuilder() { if (_isUnicodeSemantics) return new BinaryBuilderValue(); else return new LargeStringBuilderValue(); } /** * Creates a binary builder. */ public StringValue createBinaryBuilder(int length) { if (_isUnicodeSemantics) return new BinaryBuilderValue(length); else return new StringBuilderValue(length); } /** * Creates a binary builder. */ public StringValue createBinaryBuilder(byte []buffer, int offset, int length) { if (_isUnicodeSemantics) return new BinaryBuilderValue(buffer, offset, length); else return new StringBuilderValue(buffer, offset, length); } /** * Creates a binary builder. */ public StringValue createBinaryBuilder(byte []buffer) { if (_isUnicodeSemantics) return new BinaryBuilderValue(buffer, 0, buffer.length); else return new StringBuilderValue(buffer, 0, buffer.length); } /** * Creates a unicode builder. */ public StringValue createUnicodeBuilder() { if (_isUnicodeSemantics) return new UnicodeBuilderValue(); else return new StringBuilderValue(); } public TimeZone getDefaultTimeZone() { if (_defaultTimeZone != null) return _defaultTimeZone; String timeZone = getIniString("date.timezone"); if (timeZone != null) return TimeZone.getTimeZone(timeZone); else return TimeZone.getDefault(); } public QDate getGmtDate() { if (_gmtDate == null) { _gmtDate = _freeGmtDateList.allocate(); if (_gmtDate == null) _gmtDate = new QDate(); } return _gmtDate; } public QDate getLocalDate() { if (_localDate == null) { _localDate = _freeLocalDateList.allocate(); if (_localDate == null) _localDate = QDate.createLocal(); } return _localDate; } public QDate getDate() { TimeZone zone = getDefaultTimeZone(); if (zone.getID().equals("GMT")) return getGmtDate(); else if (zone.equals(TimeZone.getDefault())) return getLocalDate(); else return new QDate(zone); } public void setDefaultTimeZone(String id) { _defaultTimeZone = TimeZone.getTimeZone(id); } public void setDefaultTimeZone(TimeZone zone) { _defaultTimeZone = zone; } /* * Returns the ServletContext. */ public ServletContext getServletContext() { return _quercus.getServletContext(); } /* * Sets the ScriptContext. */ public void setScriptContext(ScriptContext context) { _scriptContext = context; } /* * Returns the input (POST, PUT) data. */ public StringValue getInputData() { return _inputData; } /* * Sets the post data. */ public void setInputData(StringValue data) { _inputData = data; } /** * Returns true for strict mode. */ public final boolean isStrict() { return _isStrict; } /* * Returns true if allowed to include urls. */ public boolean isAllowUrlInclude() { return _isAllowUrlInclude; } /* * Returns true if allowed to fopen urls. */ public boolean isAllowUrlFopen() { return _isAllowUrlFopen; } /** * Returns the connection status */ public int getConnectionStatus() { // always returns a valid value for now return 0; } public void start() { _oldThreadEnv = _threadEnv.get(); _startTime = _quercus.getCurrentTime(); _timeLimit = getIniLong("max_execution_time") * 1000; if (_timeLimit > 0) _endTime = _startTime + _timeLimit; else _endTime = Long.MAX_VALUE / 2; _threadEnv.set(this); fillPost(_postArray, _files, _request, getIniBoolean("magic_quotes_gpc")); // quercus/1b06 String encoding = getOutputEncoding(); String type = getIniString("default_mimetype"); if ("".equals(type) || _response == null) { } else if (encoding != null) _response.setContentType(type + "; charset=" + encoding); else _response.setContentType(type); if (_out != null && encoding != null) { try { _out.setEncoding(encoding); } catch (Exception e) { log.log(Level.WARNING, e.toString(), e); } } HashSet<ModuleStartupListener> listeners = _quercus.getModuleStartupListeners(); for (ModuleStartupListener listener : listeners) listener.startup(this); _quercus.startEnv(this); } /** * Returns the current time (may be cached). */ public long getCurrentTime() { return getQuercus().getCurrentTime(); } /** * Returns the current time (not cached). */ public long getExactTime() { return getQuercus().getExactTime(); } /** * add resource to the list of refrences that are * cleaned up when finished with this environment. */ public void addCleanup(EnvCleanup envCleanup) { if (_cleanupList == null) _cleanupList = new ArrayList<EnvCleanup>(); _cleanupList.add(envCleanup); } /** * add an object with a destructor to the list of references that are * cleaned up when finished with this environment. */ public void addObjectCleanup(ObjectExtValue objCleanup) { if (_objCleanupList == null) _objCleanupList = new ArrayList<ObjectExtValue>(); _objCleanupList.add(objCleanup); } /** * remove resource from the list of references that are * cleaned up when finished with this environment. * * @param resource */ public void removeCleanup(EnvCleanup envCleanup) { if (_cleanupList == null) return; for (int i = _cleanupList.size() - 1; i >= 0; i--) { EnvCleanup res = _cleanupList.get(i); if (envCleanup.equals(res)) { _cleanupList.remove(i); break; } } } /** * Returns the owning PHP engine. */ public QuercusContext getQuercus() { return _quercus; } /** * Returns the owning PHP engine. */ public ModuleContext getModuleContext() { return _quercus.getModuleContext(); } /** * Returns the configured database. */ public DataSource getDatabase() { return _quercus.getDatabase(); } protected final DataSource findDatabase(String driver, String url) throws Exception { return _quercus.findDatabase(driver, url); } /** * Returns a connection to the given database. If there is * already a connection to this specific database, then * return the connection from the pool. Otherwise, create * a new connection and add it to the pool. */ public ConnectionEntry getConnection(String driver, String url, String userName, String password, boolean isReuse) throws Exception { // XXX: connections might not be reusable (see gallery2), because // of case with two reuses and one closes because of CREATE or // catalog isReuse = false; DataSource database = _quercus.getDatabase(); if (database != null) { userName = null; password = null; } else { database = findDatabase(driver, url); if (database == null) return null; } ConnectionEntry entry = new ConnectionEntry(this); entry.init(database, userName, password); ConnectionEntry oldEntry = null; if (isReuse) oldEntry = _connMap.get(entry); if (oldEntry != null && oldEntry.isReusable()) return oldEntry; entry.connect(isReuse); if (isReuse) _connMap.put(entry, entry); return entry; } /** * Returns the configured database. */ public DataSource getDataSource(String driver, String url) throws Exception { DataSource database = _quercus.getDatabase(); if (database != null) return database; else return findDatabase(driver, url); } /** * Sets the time limit. */ public void setTimeLimit(long ms) { if (ms <= 0) ms = Long.MAX_VALUE / 2; _timeLimit = ms; } /** * Checks for the program timeout. */ public void checkTimeout() { /* long now = Alarm.getCurrentTime(); if (_endTime < now) throw new QuercusRuntimeException(L.l("script timed out")); */ if (_isTimeout) throw new QuercusRuntimeException(L.l("script timed out")); } public void updateTimeout() { long now = _quercus.getCurrentTime(); if (_endTime < now) _isTimeout = true; } public void resetTimeout() { _startTime = _quercus.getCurrentTime(); _endTime = _startTime + _timeLimit; _isTimeout = false; } public long getStartTime() { return _startTime; } /** * Returns the writer. */ public WriteStream getOut() { return _out; } /** * Returns the writer. */ public WriteStream getOriginalOut() { return _originalOut; } /** * Flushes the output buffer. */ public final void flush() { try { getOut().flush(); } catch (IOException e) { throw new QuercusModuleException(e); } } /** * Prints a string */ public final void print(String v) { try { getOut().print(v); } catch (IOException e) { throw new QuercusModuleException(e); } } /** * Prints a character buffer. */ public final void print(char []buffer, int offset, int length) { try { getOut().print(buffer, offset, length); } catch (IOException e) { throw new QuercusModuleException(e); } } /** * Prints a char */ public final void print(char v) { try { getOut().print(v); } catch (IOException e) { throw new QuercusModuleException(e); } } /** * Prints a long */ public final void print(long v) { try { getOut().print(v); } catch (IOException e) { throw new QuercusModuleException(e); } } /** * Prints a double */ public final void print(double v) { try { long longV = (long) v; if (v == longV) getOut().print(longV); else getOut().print(v); } catch (IOException e) { throw new QuercusModuleException(e); } } /** * Prints an object */ public final void print(Object v) { try { getOut().print(v); } catch (IOException e) { throw new QuercusModuleException(e); } } /** * Prints a value */ public final void print(Value v) { v.print(this); } /** * Prints a string */ public final void println() { try { getOut().println(); } catch (IOException e) { throw new QuercusModuleException(e); } } /** * Prints a string */ public final void println(String v) { try { getOut().println(v); } catch (IOException e) { throw new QuercusModuleException(e); } } /** * Prints a string */ public final void println(Value v) { try { v.print(this); getOut().println(); } catch (IOException e) { throw new QuercusModuleException(e); } } /** * Prints and object. */ public final void println(Object v) { try { getOut().println(v); } catch (IOException e) { throw new QuercusModuleException(e); } } /** * Prints a byte buffer. */ public final void write(byte []buffer, int offset, int length) { try { getOut().write(buffer, offset, length); } catch (IOException e) { throw new QuercusModuleException(e); } } /** * Returns the current output buffer. */ public OutputBuffer getOutputBuffer() { return _outputBuffer; } /** * Returns the writer. */ public void pushOutputBuffer(Callable callback, int chunkSize, boolean erase) { if (_outputBuffer == null) { _outputBuffer = new OutputBuffer(_outputBuffer, this, callback, chunkSize, erase); } else _outputBuffer = new OutputBuffer(_outputBuffer, this, callback, chunkSize, erase); _out = _outputBuffer.getOut(); } /** * Pops the output buffer */ public boolean popOutputBuffer() { OutputBuffer outputBuffer = _outputBuffer; if (outputBuffer == null) return false; outputBuffer.close(); _outputBuffer = outputBuffer.getNext(); if (_outputBuffer != null) _out = _outputBuffer.getOut(); else { _out = _originalOut; } return true; } /** * Returns the current directory. */ public Path getPwd() { return _pwd; } public String getShellPwd() { if (_pwd instanceof MemoryPath) return System.getProperty("user.dir"); else return _pwd.getNativePath(); } /** * Returns the current directory. */ public Path getWorkDir() { return _quercus.getWorkDir(); } /** * Sets the current directory. */ public void setPwd(Path path) { _pwd = path; _lookupCache.clear(); } /** * Returns the initial directory. */ public Path getSelfPath() { return _selfPath; } /** * Returns the initial directory. */ public Path getSelfDirectory() { return _selfDirectory; } /** * Sets the initial directory. */ public void setSelfPath(Path path) { _selfPath = path; _selfDirectory = _selfPath.getParent(); } /** * Returns the upload directory. */ public Path getUploadDirectory() { if (_uploadPath == null) { String realPath = getIniString("upload_tmp_dir"); if (realPath != null) { } else if (getRequest() != null) realPath = "WEB-INF/upload"; else realPath = WorkDir.getTmpWorkDir().lookup("upload").getNativePath(); _uploadPath = _quercus.getPwd().lookup(realPath); try { if (! _uploadPath.isDirectory()) _uploadPath.mkdirs(); } catch (IOException e) { log.log(Level.FINE, e.toString(), e); } _uploadPath = _uploadPath.createRoot(); } return _uploadPath; } /** * Returns the real path. */ public String getRealPath(String path) { String realPath; if (getRequest() != null) realPath = getRequest().getRealPath(path); else realPath = getSelfDirectory().lookup(path).getNativePath(); return realPath; } /** * Returns the temp directory (used by tmpfile()). */ public Path getTempDirectory() { String realPath; if (_tmpPath == null) { if (getRequest() != null) realPath = getRequest().getRealPath("/WEB-INF/tmp"); else realPath = "file:/tmp"; _tmpPath = getPwd().lookup(realPath); try { if (! _tmpPath.isDirectory()) _tmpPath.mkdirs(); } catch (IOException e) { log.log(Level.FINE, e.toString(), e); } } return _tmpPath; } /** * Adds an auto-remove path. */ public void addRemovePath(Path path) { if (_removePaths == null) _removePaths = new ArrayList<Path>(); _removePaths.add(path); } /** * Returns the request. */ public HttpServletRequest getRequest() { return _request; } /** * Returns the most recently modified time of all of the {@link Path}'s that * have been used for this Env, or 0 if that cannot be determined. */ /* public long getLastModified() { long lastModified = 0; if (_page != null) { Path pagePath = _page.getSelfPath(this); if (pagePath != null) lastModified = pagePath.getLastModified(); } for (Path includePath : _includeSet) { long includeLastModified = includePath.getLastModified(); if (lastModified < includeLastModified) lastModified = includeLastModified; } return lastModified; } */ /** * Returns the response. */ public HttpServletResponse getResponse() { return _response; } /** * Sets the session callback. */ public void setSessionCallback(SessionCallback callback) { _sessionCallback = callback; } /** * Gets the session callback. */ public SessionCallback getSessionCallback() { return _sessionCallback; } /** * Returns the session. */ public SessionArrayValue getSession() { return _session; } /** * Returns the Java Http session. */ public HttpSession getJavaSession() { return _javaSession; } /** * Sets the session. */ public void setSession(SessionArrayValue session) { _session = session; if (session != null) { Value var = getGlobalVar(S_SESSION); if (! (var instanceof SessionVar)) { var = new SessionVar(); setGlobalValue(S_SESSION, var); } var.set(session); setGlobalValue("HTTP_SESSION_VARS", session); session.addUse(); } else { // php/1k0v Value v = getGlobalVar(S_SESSION); if (v != null) v.set(UnsetValue.UNSET); v = getGlobalVar("HTTP_SESSION_VARS"); if (v != null) v.set(UnsetValue.UNSET); } } /** * Returns a new session id. */ public String generateSessionId() { String sessionId = _quercus.getQuercusSessionManager().createSessionId(this); if (_javaSession != null) sessionId = _javaSession.getId().substring(0, 3) + sessionId.substring(3); return sessionId; } /** * Create the session. */ public SessionArrayValue createSession(String sessionId, boolean create) { long now = _quercus.getCurrentTime(); SessionCallback callback = getSessionCallback(); _javaSession = _request.getSession(true); if (create && _javaSession.getId().length() >= 3 && sessionId.length() >= 3) sessionId = _javaSession.getId().substring(0, 3) + sessionId.substring(3); SessionArrayValue session = _quercus.loadSession(this, sessionId); if (callback != null) { StringValue value = callback.read(this, sessionId); if (value != null && value.length() != 0) { Value unserialize = VariableModule.unserialize(this, value); if (unserialize instanceof ArrayValue) { ArrayValue arrayValue = (ArrayValue) unserialize; session.reset(now); session.putAll(arrayValue); } } } setSession(session); return session; } /** * Destroy the session. */ public void destroySession(String sessionId) { SessionCallback callback = getSessionCallback(); if (callback != null) { callback.destroy(this, sessionId); } else { _quercus.destroySession(sessionId); } setSession(null); } /** * Returns the logger used for syslog. */ public Logger getLogger() { if (_logger == null) _logger = Logger.getLogger("quercus.quercus"); return _logger; } /** * Returns the configuration value of an init var. */ public Value getConfigVar(String name) { return getIniDefinition(name).getValue(_quercus); } /** * Returns a map of the ini values that have been explicitly set. */ public HashMap<String, Value> getIniMap(boolean create) { if (_iniMap == null && create) _iniMap = new HashMap<String,Value>(); return _iniMap; } /** * Sets an ini value. */ public StringValue setIni(String name, Value value) { _iniCount++; StringValue oldValue = getIni(name); getIniDefinition(name).set(this, value); return oldValue; } /** * Sets an ini value. */ public StringValue setIni(String name, String value) { _iniCount++; StringValue oldValue = getIni(name); getIniDefinition(name).set(this, value); return oldValue; } /** * Returns an ini value. */ public StringValue getIni(String name) { return getIniDefinition(name).getAsStringValue(this); } private IniDefinition getIniDefinition(String name) { return _quercus.getIniDefinitions().get(name); } /** * Returns an ini value. */ public boolean getIniBoolean(String name) { return getIniDefinition(name).getAsBoolean(this); } /** * Returns an ini value as a long. */ public long getIniLong(String name) { return getIniDefinition(name).getAsLong(this); } /** * Returns an ini value as a string, null for missing or empty string */ public String getIniString(String name) { return getIniDefinition(name).getAsString(this); } /** * Returns an ini value. */ public long getIniBytes(String name, long deflt) { return getIniDefinition(name).getAsLongBytes(this, deflt); } /** * Returns the ByteToChar converter. */ public ByteToChar getByteToChar() { return ByteToChar.create(); } /** * Returns the 'this' value. */ public Value getThis() { return _this; } /** * Sets the 'this' value, returning the old value. */ public Value setThis(Value value) { Value oldThis = _this; _this = value.toValue(); return oldThis; } /** * Gets a value. */ public Value getValue(StringValue name) { return getValue(name, true, false); } /** * Gets a value. */ public Value getValue(StringValue name, boolean isAutoCreate, boolean isOutputNotice) { EnvVar var = getEnvVar(name, isAutoCreate, isOutputNotice); if (var != null) return var.get(); else return NullValue.NULL; } /** * Gets a special value, a special value is used to store and retrieve module * specific values in the env using a unique name. */ public Object getSpecialValue(String name) { return _specialMap.get(name); } /** * Sets a special value, a special value is used to store and retrieve module * specific values in the env using a unique name. */ public Object setSpecialValue(String name, Object value) { _specialMap.put(name, value); return value; } public Value getGlobalValue(String name) { return getGlobalValue(createString(name)); } /** * Gets a global */ public Value getGlobalValue(StringValue name) { EnvVar var = getGlobalEnvVar(name); // XXX: don't allocate? return var.get(); /* if (var != null) return var.toValue(); else return NullValue.NULL; */ } /** * Gets a variable * * @param name the variable name * @param var the current value of the variable */ public final Var getVar(StringValue name, Value value) { if (value != null) return (Var) value; return getRef(name); } /** * Gets a variable * * @param name the variable name * @param value the current value of the variable */ public final Var getGlobalVar(StringValue name, Value value) { if (value != null) return (Var) value; return getGlobalRef(name); } /** * Gets a value. */ public Var getRef(StringValue name) { EnvVar envVar = getEnvVar(name); // XXX: can return null? return envVar.getVar(); /* Var var = _map.get(name); // required for $$ref where $ref is the name of a superglobal if (var == null) { // php/0809 if (Quercus.isSuperGlobal(name)) return getGlobalRef(name); } return var; */ } /** * Gets a value. */ public Var getRef(StringValue name, boolean isAutoCreate) { EnvVar envVar = getEnvVar(name, isAutoCreate, true); if (envVar != null) return envVar.getVar(); else return null; } /** * Returns the raw global lookup. */ public EnvVar getGlobalRaw(String name) { return _globalMap.get(name); } /** * Gets a global value. */ public Var getGlobalRef(StringValue name) { EnvVar envVar = getGlobalEnvVar(name); // XXX: not create? return envVar.getVar(); } public final EnvVar getEnvVar(StringValue name) { return getEnvVar(name, true, false); } /** * Gets a variable * * @param name the variable name * @param var the current value of the variable */ public final EnvVar getEnvVar(StringValue name, boolean isAutoCreate, boolean isOutputNotice) { EnvVar envVar = _map.get(name); if (envVar != null) return envVar; if (_map == _globalMap) return getGlobalEnvVar(name, isAutoCreate, isOutputNotice); envVar = getSuperGlobalRef(name, true, false); // php/0809 if (envVar != null) _globalMap.put(name, envVar); else { if (! isAutoCreate) { // php/0206 if (isOutputNotice) notice(L.l("${0} is an undefined variable", name)); return null; } else envVar = new EnvVarImpl(new Var()); } _map.put(name, envVar); return envVar; } /** * Gets a variable * * @param name the variable name */ public final EnvVar getGlobalEnvVar(StringValue name) { return getGlobalEnvVar(name, true, false); } /** * Gets a variable * * @param name the variable name * @param isAutoCreate */ public final EnvVar getGlobalEnvVar(StringValue name, boolean isAutoCreate, boolean isOutputNotice) { EnvVar envVar = _globalMap.get(name); if (envVar != null) return envVar; envVar = getSuperGlobalRef(name, true); if (envVar == null) { // variables set by the caller, e.g. the servlet Value value = _scriptGlobalMap.get(name); if (value != null) { envVar = new EnvVarImpl(new Var()); envVar.setRef(value); } } if (envVar == null) envVar = getGlobalScriptContextRef(name); if (envVar == null) { if (! isAutoCreate) { if (isOutputNotice) notice(L.l("${0} is an undefined variable", name)); return null; } Var var = new Var(); // var.setGlobal(); envVar = new EnvVarImpl(var); } _globalMap.put(name, envVar); return envVar; } /** * Pushes a new environment. */ public Map<StringValue,EnvVar> pushEnv(Map<StringValue,EnvVar> map) { Map<StringValue,EnvVar> oldEnv = _map; _map = map; return oldEnv; } /** * Restores the old environment. */ public void popEnv(Map<StringValue,EnvVar> oldEnv) { _map = oldEnv; } /** * Returns the current environment. */ public Map<StringValue,EnvVar> getEnv() { return _map; } /** * Returns the current environment. */ public Map<StringValue,EnvVar> getGlobalEnv() { return _globalMap; } public boolean isGlobalEnv() { return _map == _globalMap; } /** * Gets a static variable name. */ public final StringValue createStaticName() { return _quercus.createStaticName(); } /** * Gets a static variable * * @param name the variable name */ public final Var getStaticVar(StringValue name) { Var var = _staticMap.get(name); if (var == null) { var = new Var(); _staticMap.put(name, var); } return var; } /** * Gets a static variable * * @param name the variable name */ public final Value getStaticValue(StringValue name) { Var var = _staticMap.get(name); if (var != null) { return var.toValue(); } else return NullValue.NULL; } /** * Gets a static variable * * @param name the variable name */ public final Var setStaticRef(StringValue name, Value value) { if (value.isVar()) { Var var = (Var) value; _staticMap.put(name, var); return var; } Var var = _staticMap.get(name); if (var == null) { var = new Var(); _staticMap.put(name, var); } var.set(value); return var; } /** * Gets a static variable * * @param name the variable name */ /* public final Var getStaticClassVar(Value qThis, String className, String name) { // php/3248 // php/324a // php/324b QuercusClass callingClass = getCallingClass(qThis); if (callingClass.isA(className)) className = callingClass.getName(); StringValue varName = createString(className).append("::").append(name); return getStaticVar(varName); } */ /** * Unsets variable * * @param name the variable name */ public final Var unsetVar(StringValue name) { EnvVar envVar = _map.get(name); if (envVar != null) envVar.setVar(new Var()); return null; } /** * Gets a variable * * @param name the variable name * @param value the current value of the variable */ public final Var setVar(String name, Value value) { throw new UnsupportedOperationException(); /* Var var; if (value instanceof Var) { var = (Var) value; if (_map == _globalMap) var.setGlobal(); } else var = new Var(value.toValue()); _map.put(name, var); return var; */ } /** * Unsets variable * * @param name the variable name */ public final Var unsetLocalVar(StringValue name) { EnvVar envVar = _map.get(name); if (envVar != null) envVar.setVar(new Var()); return null; } /** * Unsets variable * * @param name the variable name */ public final Var unsetGlobalVar(StringValue name) { EnvVar envVar = _globalMap.get(name); if (envVar != null) envVar.setVar(new Var()); return null; } /** * Gets a local * * @param var the current value of the variable */ public static final Value getLocalVar(Value var) { if (var == null) var = new Var(); return var; } /** * Gets a local value * * @param var the current value of the variable */ public static final Value getLocalValue(Value var) { if (var != null) return var; else return NullValue.NULL; } /** * Gets a local * * @param var the current value of the variable */ public static final Value setLocalVar(Value var, Value value) { value = value.toValue(); if (var instanceof Var) var.set(value); return value; } private EnvVar getSuperGlobalRef(StringValue name, boolean isGlobal) { return getSuperGlobalRef(name, false, isGlobal); } /** * Returns a superglobal. */ private EnvVar getSuperGlobalRef(StringValue name, boolean isCheckGlobal, boolean isGlobal) { Var var; EnvVar envVar; int specialVarId = SPECIAL_VARS.get(name); if (isCheckGlobal) { if (specialVarId != IntMap.NULL) { envVar = _globalMap.get(name); if (envVar != null) return envVar; } } switch (specialVarId) { case _ENV: { var = new Var(); envVar = new EnvVarImpl(var); _globalMap.put(name, envVar); envVar.set(new ArrayValueImpl()); return envVar; } case HTTP_POST_VARS: if (! QuercusContext.INI_REGISTER_LONG_ARRAYS.getAsBoolean(this)) return null; else return getGlobalEnvVar(S_POST); case _POST: { var = new Var(); envVar = new EnvVarImpl(var); _globalMap.put(name, envVar); ArrayValue post = new ArrayValueImpl(); envVar.set(post); if (_variablesOrder.indexOf('P') >= 0 && _postArray.getSize() > 0) { for (Map.Entry<Value, Value> entry : _postArray.entrySet()) { post.put(entry.getKey(), entry.getValue()); } } return envVar; } case HTTP_POST_FILES: if (! QuercusContext.INI_REGISTER_LONG_ARRAYS.getAsBoolean(this)) return null; else return getGlobalEnvVar(S_FILES); case _FILES: { var = new Var(); envVar = new EnvVarImpl(var); _globalMap.put(name, envVar); ArrayValue files = new ArrayValueImpl(); if (_files != null) { for (Map.Entry<Value, Value> entry : _files.entrySet()) { files.put(entry.getKey(), entry.getValue()); } } envVar.set(files); return envVar; } case HTTP_GET_VARS: if (! QuercusContext.INI_REGISTER_LONG_ARRAYS.getAsBoolean(this)) return null; else if (! isGlobal) return null; else return getGlobalEnvVar(S_GET); case _GET: { if (isCheckGlobal) { EnvVar e = _globalMap.get(name); if (e != null) return e; } var = new Var(); envVar = new EnvVarImpl(var); _globalMap.put(name, envVar); ArrayValue array = new ArrayValueImpl(); envVar.set(array); if (_variablesOrder.indexOf('G') >= 0) { fillGet(array, getIniBoolean("magic_quotes_gpc")); } return envVar; } case _REQUEST: { var = new Var(); envVar = new EnvVarImpl(var); ArrayValue array = new ArrayValueImpl(); envVar.set(array); _globalMap.put(name, envVar); if (_request == null) return envVar; boolean isMagicQuotes = getIniBoolean("magic_quotes_gpc"); int orderLen = _variablesOrder.length(); for (int i = 0; i < orderLen; i++) { switch (_variablesOrder.charAt(i)) { case 'G': fillGet(array, isMagicQuotes); break; case 'P': if (_postArray.getSize() > 0) fillPost(array, _postArray); break; case 'C': fillCookies(array, _request.getCookies(), isMagicQuotes); break; } } return envVar; } case HTTP_RAW_POST_DATA: { if (!QuercusContext.INI_ALWAYS_POPULATE_RAW_POST_DATA .getAsBoolean(this)) { String contentType = getContentType(); if (contentType == null || ! contentType.startsWith("unknown/type")) return null; } if (_inputData == null) return null; var = new Var(); envVar = new EnvVarImpl(var); _globalMap.put(name, envVar); var.set(_inputData); return envVar; } case HTTP_SERVER_VARS: if (! QuercusContext.INI_REGISTER_LONG_ARRAYS.getAsBoolean(this)) return null; else return getGlobalEnvVar(S_SERVER); case _SERVER: { var = new Var(); envVar = new EnvVarImpl(var); _globalMap.put(name, envVar); Value serverEnv; if (_variablesOrder.indexOf('S') >= 0) { serverEnv = new ServerArrayValue(this); String query = getQueryString(); if (_quercus.getIniBoolean("register_argc_argv") && query != null) { ArrayValue argv = new ArrayValueImpl(); int i = 0; int j = 0; while ((j = query.indexOf('+', i)) >= 0) { String sub = query.substring(i, j); argv.put(sub); i = j + 1; } if (i < query.length()) argv.put(query.substring(i)); serverEnv.put(createString("argc"), LongValue.create(argv.getSize())); serverEnv.put(createString("argv"), argv); } } else serverEnv = new ArrayValueImpl(); var.set(serverEnv); return envVar; } case _GLOBAL: { var = new Var(); envVar = new EnvVarImpl(var); _globalMap.put(name, envVar); var.set(new GlobalArrayValue(this)); return envVar; } case HTTP_COOKIE_VARS: if (! QuercusContext.INI_REGISTER_LONG_ARRAYS.getAsBoolean(this)) return null; else return getGlobalEnvVar(S_COOKIE); case _COOKIE: { var = new Var(); envVar = new EnvVarImpl(var); _globalMap.put(name, envVar); if (_variablesOrder.indexOf('C') >= 0) var.set(getCookies()); else var.set(new ArrayValueImpl()); return envVar; } case _SESSION: { return _globalMap.get("_SESSION"); } case PHP_SELF: { var = new Var(); envVar = new EnvVarImpl(var); _globalMap.put(name, envVar); var.set(getGlobalVar("_SERVER").get(PHP_SELF_STRING)); return envVar; } default: return null; } } protected String getQueryString() { if (_request != null) return _request.getQueryString(); else return null; } protected String getContentType() { if (_request != null) return _request.getContentType(); else return null; } protected ArrayValue getCookies() { ArrayValue array = new ArrayValueImpl(); boolean isMagicQuotes = getIniBoolean("magic_quotes_gpc"); Cookie []cookies = _request.getCookies(); if (cookies != null) { for (int i = 0; i < cookies.length; i++) { Cookie cookie = cookies[i]; String value = decodeValue(cookie.getValue()); StringValue valueAsValue = createString(value); if (isMagicQuotes) // php/0876 valueAsValue = StringModule.addslashes(valueAsValue); array.append(createString(cookie.getName()), valueAsValue); } } return array; } public void setArgs(String []args) { if (_quercus.getIniBoolean("register_argc_argv")) { ArrayValue argv = new ArrayValueImpl(); for (String arg : args) { argv.put(arg); } Value serverEnv = getGlobalValue("_SERVER"); serverEnv.put(createString("argc"), LongValue.create(args.length)); serverEnv.put(createString("argv"), argv); } } /** * Gets a value. */ protected EnvVar getGlobalSpecialRef(StringValue name) { if (QuercusContext.isSuperGlobal(name)) return _globalMap.get(name); else return null; } protected EnvVar getGlobalScriptContextRef(StringValue name) { if (_scriptContext == null) return null; EnvVar envVar = _globalMap.get(name); if (envVar != null) return envVar; Object value = _scriptContext.getAttribute(name.toString()); if (value == null) { Bindings bindings = _scriptContext.getBindings(ScriptContext.ENGINE_SCOPE); if (bindings != null) value = bindings.get(name.toString()); } if (value == null) { Bindings bindings = _scriptContext.getBindings(ScriptContext.GLOBAL_SCOPE); if (bindings != null) value = bindings.get(name.toString()); } if (value != null) { envVar = new EnvVarImpl(new Var()); _globalMap.put(name, envVar); envVar.set(wrapJava(value)); } return envVar; } protected static String decodeValue(String s) { int len = s.length(); StringBuilder sb = new StringBuilder(); for (int i = 0; i < len; i++) { char ch = s.charAt(i); if (ch == '%' && i + 2 < len) { int d1 = s.charAt(i + 1); int d2 = s.charAt(i + 2); int v = 0; if ('0' <= d1 && d1 <= '9') v = 16 * (d1 - '0'); else if ('a' <= d1 && d1 <= 'f') v = 16 * (d1 - 'a' + 10); else if ('A' <= d1 && d1 <= 'F') v = 16 * (d1 - 'A' + 10); else { sb.append('%'); continue; } if ('0' <= d2 && d2 <= '9') v += (d2 - '0'); else if ('a' <= d2 && d2 <= 'f') v += (d2 - 'a' + 10); else if ('A' <= d2 && d2 <= 'F') v += (d2 - 'A' + 10); else { sb.append('%'); continue; } i += 2; sb.append((char) v); } else if (ch == '+') sb.append(' '); else sb.append(ch); } return sb.toString(); } public Var getVar(String name) { return getVar(createString(name)); } /** * Gets a value. */ public Var getVar(StringValue name) { EnvVar envVar = getEnvVar(name); return envVar.getVar(); } /** * Gets a value. */ public Var getGlobalVar(String name) { EnvVar envVar = getGlobalEnvVar(createString(name)); return envVar.getVar(); } /** * Gets a value. */ public Var getGlobalVar(StringValue name) { EnvVar envVar = getGlobalEnvVar(name); return envVar.getVar(); } public void setValue(String name, Value value) { // XXX: update to Quercus setValue(createString(name), value); } /** * Sets a value. value must not be a Var. */ public Value setValue(StringValue name, Value value) { EnvVar envVar = getEnvVar(name); envVar.set(value); return value; } /** * Sets a variable. */ public Var setVar(StringValue name, Var var) { EnvVar envVar = getEnvVar(name); envVar.setVar(var); return var; } /** * Sets a value. */ public Var setRef(StringValue name, Value value) { EnvVar envVar = getEnvVar(name); return envVar.setRef(value); } /** * Sets a value. */ /* public static Var toRef(Value value) { // php/3243 if (value instanceof Var) return (Var) value; else return new Var(value); } */ /** * Convert to a reference argument. It's a PHP error to convert anything * but a var or null to a ref arg. */ /* public Value toRefArgument(Value value) { // php/33lg if (value instanceof Var) return (Var) value; else if (value instanceof NullValue) return NullValue.NULL; else { warning(L.l("'{0}' is an invalid reference, " + "because only variables may be passed by reference.", value)); return NullValue.NULL; } } */ /** * External calls to set a global value. */ public Value setGlobalValue(String name, Value value) { return setGlobalValue(createString(name), value); } /** * External calls to set a global value. */ public Value setGlobalValue(StringValue name, Value value) { EnvVar envVar = getGlobalEnvVar(name); envVar.setRef(value); return value; } /** * Sets the calling function expression. */ public void pushCall(Expr call, Value obj, Value []args) { if (_callStack == null) { _callStack = new Expr[256]; _callThisStack = new Value[256]; _callArgStack = new Value[256][]; } if (_callStack.length <= _callStackTop) { Expr []newStack = new Expr[2 * _callStack.length]; System.arraycopy(_callStack, 0, newStack, 0, _callStack.length); _callStack = newStack; Value []newThisStack = new Value[2 * _callThisStack.length]; System.arraycopy(_callThisStack, 0, newThisStack, 0, _callThisStack.length); _callThisStack = newThisStack; Value [][]newArgStack = new Value[2 * _callArgStack.length][]; System.arraycopy(_callArgStack, 0, newArgStack, 0, _callArgStack.length); _callArgStack = newArgStack; } _callStack[_callStackTop] = call; _callThisStack[_callStackTop] = obj; _callArgStack[_callStackTop] = args; _callStackTop++; } /** * Pops the top call. */ public Expr popCall() { if (_callStack == null) throw new IllegalStateException(); return _callStack[--_callStackTop]; } /** * Returns the stack depth. */ public int getCallDepth() { return _callStackTop; } /** * Peeks at the the top call. */ public Expr peekCall(int depth) { if (_callStackTop - depth > 0) return _callStack[_callStackTop - depth - 1]; else return null; } /** * Peeks at the "this" top call. */ public Value peekCallThis(int depth) { if (_callStackTop - depth > 0) return _callThisStack[_callStackTop - depth - 1]; else return null; } /** * Peeks at the the top call. */ public Value []peekArgs(int depth) { if (_callStackTop - depth > 0) return _callArgStack[_callStackTop - depth - 1]; else return null; } // // allocations // /** * Allocate the free regexp */ public RegexpState allocateRegexpState() { RegexpState state = _freeRegexpState; _freeRegexpState = null; return state; } /** * Free the free regexp */ public void freeRegexpState(RegexpState state) { _freeRegexpState = state; } // // profiling // public void pushProfile(int id) { } public void popProfile(long nanos) { } /* * Returns true if <code>name</code> doesn't already exist on the * field __get() stack. */ public boolean pushFieldGet(Env.OVERLOADING_TYPES type, String className, StringValue fieldName) { FieldGetEntry entry = new FieldGetEntry(className, fieldName); LinkedList<FieldGetEntry> list = null; switch (type) { case FIELDGET: list = _fieldGetList; break; case FIELDSET: list = _fieldSetList; break; case ISSET: list = _issetList; break; case UNSET: list = _unsetList; break; case INVALID_FIRST: case INVALID_LAST: // defensive programming according to "Code Complete 2nd Edition, MS Press" throw new IllegalStateException("IllegalState: pushFieldGet with FIRST/LAST Element"); } if(list == null) return false; if (list.contains(entry)) return false; else { list.push(entry); return true; } } public void popFieldGet(Env.OVERLOADING_TYPES type) { switch (type) { case FIELDGET: _fieldGetList.pop(); break; case FIELDSET: _fieldSetList.pop(); break; case ISSET: _issetList.pop(); break; case UNSET: _unsetList.pop(); break; case INVALID_FIRST: case INVALID_LAST: // defensive programming according to "Code Complete 2nd Edition, MS Press" throw new IllegalStateException("IllegalState: popFieldGet with FIRST/LAST Element"); } } /* * Returns the calling class. */ public QuercusClass getCallingClass() { return _callingClass; } public Value getCallingClassName() { QuercusClass qClass = _callingClass; if (qClass != null) return createString(qClass.getName()); else { warning(L.l("get_called_class() must be called from a class-context.")); return NullValue.NULL; } } /* * Returns the calling class. */ public QuercusClass getCallingClass(Value qThis) { QuercusClass cls = qThis.getQuercusClass(); if (cls == null) cls = _callingClass; return cls; } /* * Sets the calling class. */ public QuercusClass setCallingClass(QuercusClass cls) { QuercusClass oldCallingClass = _callingClass; _callingClass = cls; return oldCallingClass; } public ArrayList<String> getStackTrace() { ArrayList<String> trace = new ArrayList<String>(); for (int i = _callStackTop - 1; i >= 0; i--) { String entry; Location location = _callStack[i].getLocation(); String loc; if (location != null && location.getFileName() != null) { loc = (" (at " + location.getFileName() + ":" + location.getLineNumber() + ")"); } else loc = ""; if (_callThisStack[i] != null && ! "".equals(_callThisStack[i].toString())) { entry = _callThisStack[i] + "." + _callStack[i].toString() + loc; } else entry = _callStack[i].toString() + loc; trace.add(entry); } return trace; } /** * Pushes a new environment. */ public final Value []setFunctionArgs(Value []args) { Value []oldArgs = _functionArgs; Value []newArgs = new Value[args.length]; for (int i = 0; args != null && i < args.length; i++) { // php/3715, 3768 newArgs[i] = args[i].toValue().copySaveFunArg(); } _functionArgs = newArgs; return oldArgs; } /** * Pushes a new environment. */ public final Value []setFunctionArgsNoCopy(Value []args) { Value []oldArgs = _functionArgs; for (int i = 0; args != null && i < args.length; i++) args[i] = args[i].toValue(); _functionArgs = args; return oldArgs; } /** * Pushes a new environment. */ public final void restoreFunctionArgs(Value []args) { _functionArgs = args; } /** * Returns the function args. */ public final Value []getFunctionArgs() { return _functionArgs; } /** * Removes a specialValue */ public Object removeSpecialValue(String name) { return _specialMap.remove(name); } /** * Returns a constant. */ public Value getConstant(String name) { return getConstant(name, true); } /** * Returns a constant. */ public Value getConstant(String name, boolean isAutoCreateString) { Value value = getConstantImpl(name); if (value != null) return value; int ns = name.lastIndexOf('\\'); if (ns >= 0) { name = name.substring(ns + 1); value = getConstantImpl(name); if (value != null) return value; } /* XXX: notice(L.l("Converting undefined constant '{0}' to string.", name)); */ if (isAutoCreateString) return createString(name); else return null; } /** * Returns true if the constant is defined. */ public boolean isDefined(String name) { return getConstantImpl(name) != null; } /** * Returns a constant. */ private Value getConstantImpl(String name) { int id = _quercus.getConstantId(name); if (id < _const.length) { Value value = _const[id]; if (value != null) return value; } id = _quercus.getConstantLowerId(name); if (id > 0 && id < _const.length) { Value value = _const[id]; if (value != null) return value; } /* id = _quercus.getConstantLower(id); if (id > 0 && id < _const.length) { Value value = _const[id]; if (value != null) return value; } */ return null; /* value = _quercus.getConstant(name); if (value != null) return value; if (_lowerConstMap != null) { value = _lowerConstMap.get(name.toLowerCase(Locale.ENGLISH)); if (value != null) return value; } return null; */ } /** * Returns a constant. */ public Value getConstant(int id) { if (_const.length <= id) return _quercus.getConstantName(id); Value value = _const[id]; if (value != null) return value; int lowerId = _quercus.getConstantLower(id); value = _const[lowerId]; if (value != null) { _const[id] = value; return value; } Value nameValue = _quercus.getConstantName(id); String name = nameValue.toString(); int ns = name.lastIndexOf('\\'); if (ns >= 0) { name = name.substring(ns + 1); value = getConstantImpl(name); if (value != null) { _const[id] = value; return value; } } return nameValue; /* value = _quercus.getConstant(name); if (value != null) return value; if (_lowerConstMap != null) { value = _lowerConstMap.get(name.toLowerCase(Locale.ENGLISH)); if (value != null) return value; } return null; */ } /** * Removes a constant. */ public Value removeConstant(String name) { int id = _quercus.getConstantId(name); Value value = _const[id]; _const[id] = null; return value; } /** * Sets a constant. */ public Value addConstant(String name, Value value, boolean isCaseInsensitive) { int id; if (isCaseInsensitive) id = _quercus.addLowerConstantId(new ConstStringValue(name)); else id = _quercus.getConstantId(name); return addConstant(id, value, isCaseInsensitive); } /** * Sets a constant. */ public Value addConstant(StringValue name, Value value, boolean isCaseInsensitive) { int id; if (isCaseInsensitive) id = _quercus.addLowerConstantId(name); else id = _quercus.getConstantId(name); return addConstant(id, value, isCaseInsensitive); } /** * Sets a constant. */ public Value addConstant(int id, Value value, boolean isCaseInsensitive) { if (_const.length <= id) { Value []newConst = new Value[id + 256]; System.arraycopy(_const, 0, newConst, 0, _const.length); _const = newConst; } if (_const[id] != null) { return notice(L.l("cannot redefine constant {0}", _quercus.getConstantName(id))); } _const[id] = value; if (isCaseInsensitive) { int lowerId = _quercus.getConstantLower(id); if (_const.length <= lowerId) { Value []newConst = new Value[lowerId + 256]; System.arraycopy(_const, 0, newConst, 0, _const.length); _const = newConst; } _const[lowerId] = value; } return value; } /** * Returns an array of the defined functions. */ public ArrayValue getDefinedConstants() { ArrayValue result = new ArrayValueImpl(); for (int i = 0; i < _const.length; i++) { if (_const[i] != null) { result.append(_quercus.getConstantName(i), _const[i]); } } return result; } /** * Returns true if an extension is loaded. */ public boolean isExtensionLoaded(String name) { return getQuercus().isExtensionLoaded(name); } /** * Returns true if an extension is loaded. */ public HashSet<String> getLoadedExtensions() { return getQuercus().getLoadedExtensions(); } /** * Returns true if an extension is loaded. */ public Value getExtensionFuncs(String name) { return getQuercus().getExtensionFuncs(name); } /** * Returns the default stream resource. */ public StreamContextResource getDefaultStreamContext() { if (_defaultStreamContext == null) _defaultStreamContext = new StreamContextResource(); return _defaultStreamContext; } // // function handling // public ArrayValue getDefinedFunctions() { ArrayValueImpl funs = new ArrayValueImpl(); ArrayValueImpl system = new ArrayValueImpl(); ArrayValueImpl user = new ArrayValueImpl(); AbstractFunction []systemFuns = _quercus.getFunctionMap(); AbstractFunction []envFuns = _fun; for (int i = 0; i < envFuns.length; i++) { if (i < systemFuns.length && systemFuns[i] != null && ! (systemFuns[i] instanceof UndefinedFunction)) { system.append(createString(systemFuns[i].getName())); } else if (envFuns[i] != null && ! (envFuns[i] instanceof UndefinedFunction)) { user.append(createString(envFuns[i].getName())); } } funs.append(createString("internal"), system); funs.append(createString("user"), user); return funs; } /** * Returns the function with a given name. * * Compiled mode normally uses the _fun array directly, so this call * is rare. */ public int findFunctionId(String name) { return _quercus.findFunctionId(name); } /** * Returns the function with a given name. * * Compiled mode normally uses the _fun array directly, so this call * is rare. */ public AbstractFunction findFunction(String name) { int id = _quercus.findFunctionId(name); if (id >= 0) { if (id < _fun.length && ! (_fun[id] instanceof UndefinedFunction)) { return _fun[id]; } else { return null; } } /* AbstractFunction fun = _quercus.findFunctionImpl(name); if (fun != null) return fun; if (isStrict()) return null; name = name.toLowerCase(Locale.ENGLISH); id = _quercus.findFunctionId(name); if (id >= 0) { if (id < _fun.length && ! (_fun[id] instanceof UndefinedFunction)) return _fun[id]; else return null; } fun = _quercus.findLowerFunctionImpl(name); if (fun != null) return fun; */ if (_anonymousFunMap != null) return _anonymousFunMap.get(name); else return null; } /** * Returns the function with a given name. * * Compiled mode normally uses the _fun array directly, so this call * is rare. */ public AbstractFunction findFunction(int id) { if (id >= 0) { if (id < _fun.length && ! (_fun[id] instanceof UndefinedFunction)) { return _fun[id]; } else { return null; } } return null; } public AbstractFunction getFunction(String name) { AbstractFunction fun = findFunction(name); if (fun != null) return fun; else throw createErrorException(L.l("'{0}' is an unknown function.", name)); } public void updateFunction(int id, AbstractFunction fun) { if (_fun.length <= id) { AbstractFunction []oldFun = _fun; _fun = new AbstractFunction[id + 256]; System.arraycopy(oldFun, 0, _fun, 0, oldFun.length); } if (_fun[id] == null) _fun[id] = fun; } /* public int getFunctionId(String name) { int id = _quercus.getFunctionId(name); if (_fun.length <= id) { AbstractFunction []oldFun = _fun; _fun = new AbstractFunction[id + 256]; System.arraycopy(oldFun, 0, _fun, 0, oldFun.length); } AbstractFunction []defFuns = _quercus.getFunctionMap(); if (_fun[id] == null) _fun[id] = defFuns[id]; return id; } public int getFunctionIdCount() { return _quercus.getFunctionIdCount(); } */ /** * Finds the java reflection method for the function with the given name. * * @param name the method name * @return the found method or null if no method found. */ public AbstractFunction getFunction(Value name) { name = name.toValue(); if (name instanceof CallbackFunction) return ((CallbackFunction) name).getFunction(this); return getFunction(name.toString()); } /* public DefinitionState getDefinitionState() { return _defState; } */ public Value addFunction(String name, AbstractFunction fun) { AbstractFunction staticFun = _quercus.findLowerFunctionImpl(name.toLowerCase(Locale.ENGLISH)); if (staticFun != null) throw new QuercusException(L.l("can't redefine function {0}", name)); int id = _quercus.getFunctionId(name); // XXX: anonymous/generated functions(?), e.g. like foo2431 if (_fun.length <= id) { AbstractFunction []funMap = new AbstractFunction[id + 256]; System.arraycopy(_fun, 0, funMap, 0, _fun.length); _fun = funMap; } if (_fun[id] != null && ! (_fun[id] instanceof UndefinedFunction)) throw new QuercusException(L.l("can't redefine function {0}", name)); _fun[id] = fun; return BooleanValue.TRUE; } public AbstractFunction createAnonymousFunction(String args, String code) throws IOException { if (_anonymousFunMap == null) _anonymousFunMap = new HashMap<String, AbstractFunction>(); // PHP naming style for anonymous functions String name = "\u0000lambda_" + (_anonymousFunMap.size() + 1); AbstractFunction fun = getQuercus().parseFunction(name, args, code); _anonymousFunMap.put(name, fun); return fun; } /** * Adds a function from a compiled include * * @param name the function name, must be an intern() string * @param lowerName the function name, must be an intern() string */ public Value addFunctionFromPage(String name, String lowerName, AbstractFunction fun) { // XXX: skip the old function check since the include for compiled // pages is already verified. Might have a switch here? /* AbstractFunction oldFun = _lowerFunMap.get(lowerName); if (oldFun == null) oldFun = _quercus.findLowerFunctionImpl(lowerName); if (oldFun != null) { throw new QuercusException(L.l("can't redefine function {0}", name)); } _funMap.put(name, fun); if (! isStrict()) _lowerFunMap.put(lowerName, fun); */ return BooleanValue.TRUE; } // // method handling // /** * Finds the java reflection method for the function with the given name. * * @param className the class name * @param methodName the method name * @return the found method or null if no method found. */ public AbstractFunction findMethod(String className, String methodName) { QuercusClass cl = findClass(className); if (cl == null) { error(L.l("'{0}' is an unknown class.", className)); return null; } AbstractFunction fun = cl.findFunction(methodName); if (fun == null) { error(L.l("'{0}::{1}' is an unknown method.", className, methodName)); return null; } return fun; } // // evaluation // /** * Compiles and evalutes the given code * * @param code the code to evalute * @return the result */ public Value evalCode(String code) throws IOException { if (log.isLoggable(Level.FINER)) log.finer(code); QuercusContext quercus = getQuercus(); QuercusProgram program = quercus.parseEvalExpr(code); Value value = program.execute(this); if (value == null) return NullValue.NULL; else return value; } /** * Evaluates the top-level code and prepend and append code. */ public void execute() throws IOException { StringValue prepend = _quercus.getIniValue("auto_prepend_file").toStringValue(this); if (prepend.length() > 0) { Path prependPath = lookup(prepend); if (prependPath == null) error(L.l("auto_prepend_file '{0}' not found.", prepend)); else { QuercusPage prependPage = _quercus.parse(prependPath); prependPage.executeTop(this); } } executeTop(); StringValue append = _quercus.getIniValue("auto_append_file").toStringValue(this); if (append.length() > 0) { Path appendPath = lookup(append); if (appendPath == null) error(L.l("auto_append_file '{0}' not found.", append)); else { QuercusPage appendPage = getQuercus().parse(appendPath); appendPage.executeTop(this); } } } /** * Evaluates the top-level code * * @return the result */ public Value executeTop() { Path oldPwd = getPwd(); Path pwd = _page.getPwd(this); setPwd(pwd); try { return executePageTop(_page); } catch (QuercusLanguageException e) { log.log(Level.FINER, e.toString(), e); if (getExceptionHandler() != null) { try { getExceptionHandler().call(this, e.getValue()); } catch (QuercusLanguageException e2) { uncaughtExceptionError(e2); } } else { uncaughtExceptionError(e); } return NullValue.NULL; } finally { setPwd(oldPwd); } } /* * Throws an error for this uncaught exception. */ private void uncaughtExceptionError(QuercusLanguageException e) { Location location = e.getLocation(this); String type = e.getValue().getClassName(); String message = e.getMessage(this); error(location, L.l("Uncaught exception of type '{0}' with message '{1}'", type, message)); } /** * Executes the given page */ protected Value executePage(QuercusPage page) { if (log.isLoggable(Level.FINEST)) log.finest(this + " executePage " + page); if (page.getCompiledPage() != null) return page.getCompiledPage().execute(this); else return page.execute(this); } /** * Executes the given page */ protected Value executePageTop(QuercusPage page) { if (page.getCompiledPage() != null) return page.getCompiledPage().execute(this); else return page.execute(this); } /** * Evaluates the named function. * * @param name the function name * @return the function value */ public Value call(String name) { AbstractFunction fun = findFunction(name); if (fun == null) return error(L.l("'{0}' is an unknown function.", name)); return fun.call(this); } // // function calls (obsolete?) // /** * Evaluates the named function. * * @param name the function name * @param a0 the first argument * @return the function value */ public Value call(String name, Value a0) { AbstractFunction fun = findFunction(name); if (fun == null) return error(L.l("'{0}' is an unknown function.", name)); return fun.call(this, a0); } /** * Evaluates the named function. * * @param name the function name * @param a0 the first argument * @param a1 the second argument * @return the function value */ public Value call(String name, Value a0, Value a1) { return getFunction(name).call(this, a0, a1); } /** * Evaluates the named function. * * @param name the function name * @param a0 the first argument * @param a1 the second argument * @param a2 the third argument * @return the function value */ public Value call(String name, Value a0, Value a1, Value a2) { return getFunction(name).call(this, a0, a1, a2); } /** * Evaluates the named function. * * @param name the function name * @param a0 the first argument * @param a1 the second argument * @param a2 the third argument * @param a3 the fourth argument * @return the function value */ public Value call(String name, Value a0, Value a1, Value a2, Value a3) { return getFunction(name).call(this, a0, a1, a2, a3); } /** * Evaluates the named function. * * @param name the function name * @param a0 the first argument * @param a1 the second argument * @param a2 the third argument * @param a3 the fourth argument * @param a4 the fifth argument * @return the function value */ public Value call(String name, Value a0, Value a1, Value a2, Value a3, Value a4) { return getFunction(name).call(this, a0, a1, a2, a3, a4); } /** * Evaluates the named function. * * @param name the function name * @param args the arguments * @return the function value */ public Value call(String name, Value []args) { return getFunction(name).call(this, args); } /** * Evaluates the named function. * * @param name the function name * @return the function value */ public Value callRef(String name) { AbstractFunction fun = findFunction(name); if (fun == null) return error(L.l("'{0}' is an unknown function.", name)); return fun.callRef(this); } /** * EvalRefuates the named function. * * @param name the function name * @param a0 the first argument * @return the function value */ public Value callRef(String name, Value a0) { AbstractFunction fun = findFunction(name); if (fun == null) return error(L.l("'{0}' is an unknown function.", name)); return fun.callRef(this, a0); } /** * EvalRefuates the named function. * * @param name the function name * @param a0 the first argument * @param a1 the second argument * @return the function value */ public Value callRef(String name, Value a0, Value a1) { AbstractFunction fun = findFunction(name); if (fun == null) return error(L.l("'{0}' is an unknown function.", name)); return fun.callRef(this, a0, a1); } /** * EvalRefuates the named function. * * @param name the function name * @param a0 the first argument * @param a1 the second argument * @param a2 the third argument * @return the function value */ public Value callRef(String name, Value a0, Value a1, Value a2) { AbstractFunction fun = findFunction(name); if (fun == null) return error(L.l("'{0}' is an unknown function.", name)); return fun.callRef(this, a0, a1, a2); } /** * Evaluates the named function. * * @param name the function name * @param a0 the first argument * @param a1 the second argument * @param a2 the third argument * @param a3 the fourth argument * @return the function value */ public Value callRef(String name, Value a0, Value a1, Value a2, Value a3) { AbstractFunction fun = findFunction(name); if (fun == null) return error(L.l("'{0}' is an unknown function.", name)); return fun.callRef(this, a0, a1, a2, a3); } /** * Evaluates the named function. * * @param name the function name * @param a0 the first argument * @param a1 the second argument * @param a2 the third argument * @param a3 the fourth argument * @param a4 the fifth argument * @return the function value */ public Value callRef(String name, Value a0, Value a1, Value a2, Value a3, Value a4) { AbstractFunction fun = findFunction(name); if (fun == null) return error(L.l("'{0}' is an unknown function.", name)); return fun.callRef(this, a0, a1, a2, a3, a4); } /** * Evaluates the named function. * * @param name the function name * @param args the arguments * @return the function value */ public Value callRef(String name, Value []args) { AbstractFunction fun = findFunction(name); if (fun == null) return error(L.l("'{0}' is an unknown function.", name)); return fun.callRef(this, args); } /** * Adds a class, e.g. from an include. */ public void addClassDef(String name, ClassDef cl) { int id = _quercus.getClassId(name); if (_classDef.length <= id) { ClassDef []def = new ClassDef[id + 256]; System.arraycopy(_classDef, 0, def, 0, _classDef.length); _classDef = def; } if (_classDef[id] == null) _classDef[id] = cl; } public ClassDef findClassDef(String name) { int id = _quercus.getClassId(name); if (id < _classDef.length) return _classDef[id]; else return null; } /** * Saves the current state */ public SaveState saveState() { if (_globalMap != _map) throw new QuercusException( L.l("Env.saveState() only allowed at top level")); return new SaveState(this, _fun, _classDef, _qClass, _const, _staticMap, _globalMap, _includeMap, _importMap); } EnvVar []getGlobalList() { return _globalList; } /** * Returns true for any special variables, i.e. which should not be * saved */ boolean isSpecialVar(StringValue name) { if (_quercus.isSuperGlobal(name)) return true; else if (_scriptGlobalMap.get(name) != null) return true; return false; } /** * Restores to a given state */ public void restoreState(SaveState saveState) { AbstractFunction []fun = saveState.getFunctionList(); if (_fun.length < fun.length) _fun = new AbstractFunction[fun.length]; System.arraycopy(fun, 0, _fun, 0, fun.length); ClassDef []classDef = saveState.getClassDefList(); if (_classDef.length < classDef.length) _classDef = new ClassDef[classDef.length]; System.arraycopy(classDef, 0, _classDef, 0, classDef.length); QuercusClass []qClass = saveState.getQuercusClassList(); if (_qClass.length < qClass.length) _qClass = new QuercusClass[qClass.length]; System.arraycopy(qClass, 0, _qClass, 0, qClass.length); Value []constList = saveState.getConstantList(); if (_const.length < constList.length) _const = new Value[constList.length]; System.arraycopy(constList, 0, _const, 0, constList.length); IntMap staticNameMap = saveState.getStaticNameMap(); Value []staticList = saveState.getStaticList(); _staticMap = new LazyStaticMap(staticNameMap, staticList); IntMap globalNameMap = saveState.getGlobalNameMap(); Value []globalList = saveState.getGlobalList(); Map<StringValue,EnvVar> oldGlobal = _globalMap; _globalMap = new LazySymbolMap(globalNameMap, globalList); _map = _globalMap; // php/4045 - set the vars for any active EnvVar entries for (Map.Entry<StringValue,EnvVar> oldEntry : oldGlobal.entrySet()) { EnvVar oldEnvVar = oldEntry.getValue(); EnvVar newEnvVar = _globalMap.get(oldEntry.getKey()); if (newEnvVar != null) oldEnvVar.setVar(newEnvVar.getVar()); } // php/404j - include_once Map<Path,QuercusPage> includeMap = saveState.getIncludeMap(); _includeMap = new HashMap<Path,QuercusPage>(includeMap); // php/404l // XXX: import and namespaces ImportMap importMap = saveState.getImportMap(); if (importMap != null) _importMap = importMap.copy(); } /** * Creates a stdClass object. */ public ObjectValue createObject() { try { return (ObjectValue) _quercus.getStdClass().createObject(this); } catch (Exception e) { throw new QuercusModuleException(e); } } /** * Creates a stdClass object. */ public ObjectValue createIncompleteObject(String name) { try { ObjectValue obj = (ObjectValue) _quercus.getStdClass().createObject(this); obj.setIncompleteObjectName(name); return obj; } catch (Exception e) { throw new QuercusModuleException(e); } } /* * Creates an empty string. */ public StringValue getEmptyString() { if (_isUnicodeSemantics) return UnicodeBuilderValue.EMPTY; else return ConstStringValue.EMPTY; } /* * Creates an empty string builder. */ public StringValue createStringBuilder() { if (_isUnicodeSemantics) return new UnicodeBuilderValue(); else return new StringBuilderValue(); } /** * Creates a PHP string from a byte buffer. */ public StringValue createString(byte []buffer, int offset, int length) { if (_isUnicodeSemantics) return new UnicodeValueImpl(new String(buffer, offset, length)); else return new ConstStringValue(buffer, offset, length); } /** * Creates a PHP string from a byte buffer. */ public StringValue createString(char []buffer, int length) { if (_isUnicodeSemantics) return new UnicodeBuilderValue(buffer, length); else return new ConstStringValue(buffer, length); } /** * Creates a PHP string from a char buffer. */ public StringValue createString(char []buffer, int offset, int length) { if (_isUnicodeSemantics) return new UnicodeBuilderValue(buffer, offset, length); else return new ConstStringValue(buffer, offset, length); } /** * Creates a PHP string from a java String. */ public StringValue createString(String s) { if (s == null || s.length() == 0) { return (_isUnicodeSemantics ? UnicodeBuilderValue.EMPTY : ConstStringValue.EMPTY); } else if (s.length() == 1) { if (_isUnicodeSemantics) return UnicodeBuilderValue.create(s.charAt(0)); else return ConstStringValue.create(s.charAt(0)); } else if (_isUnicodeSemantics) return new UnicodeBuilderValue(s); else if (s.length() < 256) { StringValue stringValue = _internStringMap.get(s); if (stringValue == null) { stringValue = new ConstStringValue(s); _internStringMap.put(s, stringValue); } return stringValue; // return new ConstStringValue(s); } else { return new ConstStringValue(s); } } /** * Creates a string from a byte. */ public StringValue createString(char ch) { if (_isUnicodeSemantics) return UnicodeValueImpl.create(ch); else return ConstStringValue.create(ch); } /** * Creates a PHP string from a buffer. */ public StringValue createBinaryString(TempBuffer head) { StringValue string; if (_isUnicodeSemantics) string = new BinaryBuilderValue(); else string = new StringBuilderValue(); for (; head != null; head = head.getNext()) { string.append(head.getBuffer(), 0, head.getLength()); } return string; } public Value createException(String exceptionClass, String message) { QuercusClass cls = getClass(exceptionClass); StringValue messageV = createString(message); Value []args = { messageV }; Value value = cls.callNew(this, args); Location location = getLocation(); value.putField(this, "file", createString(location.getFileName())); value.putField(this, "line", LongValue.create(location.getLineNumber())); value.putField(this, "trace", ErrorModule.debug_backtrace(this)); return value; } /** * Creates a PHP Exception. */ public Value createException(Throwable e) { QuercusClass cls = findClass("Exception"); StringValue message = createString(e.getMessage()); Value []args = { message }; Value value = cls.callNew(this, args); StackTraceElement elt = e.getStackTrace()[0]; value.putField(this, "file", createString(elt.getFileName())); value.putField(this, "line", LongValue.create(elt.getLineNumber())); value.putField(this, "trace", ErrorModule.debug_backtrace(this)); if ((e instanceof QuercusException) && e.getCause() != null) e = e.getCause(); value.putField(this, "__javaException", wrapJava(e)); return value; } /** * Generate an object id. */ public int generateId() { return ++_objectId; } /** * Returns an introspected Java class definition. */ public JavaClassDef getJavaClassDefinition(String className) { JavaClassDef def = getJavaClassDefinition(className, true); if (def != null) return def; else throw createErrorException(L.l("'{0}' class definition not found", className)); } /** * Returns an introspected Java class definition. */ public JavaClassDef getJavaClassDefinition(Class<?> type) { JavaClassDef def = _quercus.getJavaClassDefinition(type, type.getName()); return def; } private JavaClassDef getJavaClassDefinition(String className, boolean useImport) { JavaClassDef def = null; try { def = _quercus.getJavaClassDefinition(className); if (def == null && useImport) { useImport = false; def = importJavaClass(className); } } catch (Throwable e) { if (log.isLoggable(Level.FINEST)) log.log(Level.FINEST, e.toString(), e); if (useImport) { def = importJavaClass(className); if (def != null) return def; } /* else throw createErrorException(e); */ } return def; } /** * Imports a Java class. * * @param className name of class to import * @return class definition of imported class, null if class not found */ public JavaClassDef importJavaClass(String className) { if (_importMap == null) return null; String fullName = _importMap.getQualified(className); if (fullName != null) { return getJavaClassDefinition(fullName, false); } else { ArrayList<String> wildcardList = _importMap.getWildcardList(); for (String entry : wildcardList) { fullName = entry + '.' + className; JavaClassDef def; try { def = getJavaClassDefinition(fullName, false); if (def != null) { _importMap.putQualified(className, fullName); return def; } } catch (Exception e) { log.log(Level.ALL, e.toString(), e); } } } return null; } /** * Adds a Quercus class import. * * @param javaName fully qualified class import string */ public void putQualifiedImport(String javaName) { if (_importMap == null) _importMap = new ImportMap(); String phpName = _importMap.putQualified(javaName); } /** * Adds a Quercus class import. * * @param name wildcard class import string * minus '*' at the end (i.e. java.util.) */ public void addWildcardImport(String name) { if (_importMap == null) _importMap = new ImportMap(); _importMap.addWildcardImport(name); } /** * Returns a PHP value for a Java object * * @param isNullAsFalse what to return if <i>obj</i> is null, if true return * {@link BooleanValue.FALSE} otherwise return {@link NullValue.NULL) */ public Value wrapJava(Object obj, boolean isNullAsFalse) { if (obj == null) { if (isNullAsFalse) return BooleanValue.FALSE; else return NullValue.NULL; } return wrapJava(obj); } /** * Returns a PHP value for a Java object * * @param isNullAsFalse what to return if <i>obj</i> is null, if true return * {@link BooleanValue.FALSE} otherwise return {@link NullValue.NULL) */ public Value wrapJava(Object obj, JavaClassDef def, boolean isNullAsFalse) { if (obj == null) { if (isNullAsFalse) return BooleanValue.FALSE; else return NullValue.NULL; } return wrapJava(obj, def); } /** * Returns a PHP value for a Java object */ public Value wrapJava(Object obj) { if (obj == null) return NullValue.NULL; if (obj instanceof Value) return (Value) obj; JavaClassDef def = getJavaClassDefinition(obj.getClass()); return def.wrap(this, obj); } /** * Returns a PHP value for a Java object * * @param isNullAsFalse what to return if <i>obj</i> is null, if true return * {@link BooleanValue.FALSE} otherwise return {@link NullValue.NULL) */ public Value wrapJava(Object obj, JavaClassDef def) { if (obj == null) return NullValue.NULL; if (obj instanceof Value) return (Value) obj; // XXX: why is this logic here? The def should be correct on the call // logic is for JavaMarshal, where can avoid the lookup call if (def.getType() != obj.getClass()) { // php/0ceg // XXX: what if types are incompatible, does it matter? // if it doesn't matter, simplify this to one if with no else def = getJavaClassDefinition(obj.getClass()); } return def.wrap(this, obj); } /** * Finds the class with the given name. * * @param name the class name * @return the found class or null if no class found. */ public QuercusClass findClass(String name) { return findClass(name, true, true); } /** * Finds the class with the given name. * * @param name the class name * @param useAutoload use autoload to locate the class if necessary * @return the found class or null if no class found. */ public QuercusClass findClass(String name, boolean useAutoload, boolean useImport) { int id = _quercus.getClassId(name); return findClass(id, useAutoload, useImport); } public QuercusClass findClass(int id, boolean useAutoload, boolean useImport) { if (id < _qClass.length && _qClass[id] != null) return _qClass[id]; QuercusClass cl = createClassFromCache(id, useAutoload, useImport); if (cl != null) { _qClass[id] = cl; // php/09b7 cl.init(this); return cl; } else { String name = _quercus.getClassName(id); QuercusClass qcl = findClassExt(name, useAutoload, useImport); if (qcl != null) _qClass[id] = qcl; else return null; return qcl; } } private QuercusClass findClassExt(String name, boolean useAutoload, boolean useImport) { int id = _quercus.getClassId(name); if (useAutoload) { StringValue nameString = createString(name); if (! _autoloadClasses.contains(name)) { try { _autoloadClasses.add(name); int size = _autoloadList != null ? _autoloadList.size() : 0; for (int i = 0; i < size; i++) { Callable cb = _autoloadList.get(i); cb.call(this, nameString); // php/0977 QuercusClass cls = findClass(name, false, useImport); if (cls != null) return cls; } if (size == 0) { if (_autoload == null) _autoload = findFunction("__autoload"); if (_autoload != null) { _autoload.call(this, nameString); // php/0976 QuercusClass cls = findClass(name, false, useImport); if (cls != null) return cls; } } } finally { _autoloadClasses.remove(name); } } } if (useImport) { if (importPhpClass(name)) { return findClass(name, false, false); } else { try { JavaClassDef javaClassDef = getJavaClassDefinition(name, true); if (javaClassDef != null) { QuercusClass cls = createQuercusClass(id, javaClassDef, null); _qClass[id] = cls; cls.init(this); return cls; } } catch (Exception e) { log.log(Level.FINER, e.toString(), e); } } } return _internalAutoload.loadClass(this, name); } /** * Returns the class with the given id */ public QuercusClass getClass(int classId) { if (_qClass.length <= classId) { QuercusClass []oldClassList = _qClass; _qClass = new QuercusClass[classId + 256]; System.arraycopy(oldClassList, 0, _qClass, 0, oldClassList.length); } QuercusClass qClass = _qClass[classId]; if (qClass != null) return qClass; if (_classDef.length <= classId) { ClassDef []oldClassDefList = _classDef; _classDef = new ClassDef[classId + 256]; System.arraycopy(oldClassDefList, 0, _classDef, 0, oldClassDefList.length); } ClassDef def = _classDef[classId]; if (def == null) { QuercusClass cl = findClass(classId, true, true); if (cl != null) return cl; else { error(L.l("'{0}' is an unknown class.", _quercus.getClassName(classId))); throw new QuercusException(L.l("'{0}' is an unknown class.", _quercus.getClassName(classId))); } } int parentId = -1; if (def.getParentName() != null) parentId = _quercus.getClassId(def.getParentName()); addClass(def, classId, parentId); return _qClass[classId]; } /** * Adds the class with the given name * * @param def the class definition * @param classId the identifier for the class name * @param parentId the identifier for the parent class name */ public void addClass(ClassDef def, int classId, int parentId) { def = def.loadClassDef(); // php/0cn2 - make sure interfaces have a QuercusClass /* XXX: temp, needs to be argument for (String iface : def.getInterfaces()) { QuercusClass cl = findClass(iface); } */ QuercusClass parentClass = null; if (parentId >= 0) parentClass = getClass(parentId); QuercusClass qClass = _quercus.getCachedClass(classId); if (qClass == null || qClass.isModified() || qClass.getClassDef() != def || qClass.getParent() != parentClass) { qClass = createQuercusClass(classId, def, parentClass); _quercus.setCachedClass(classId, qClass); } if (_qClass.length <= classId) { QuercusClass []oldClassList = _qClass; _qClass = new QuercusClass[classId + 256]; System.arraycopy(oldClassList, 0, _qClass, 0, oldClassList.length); } _qClass[classId] = qClass; qClass.init(this); } public void addClass(String name, ClassDef def) { int id = _quercus.getClassId(name); int parentId = -1; if (def.getParentName() != null) parentId = _quercus.getClassId(def.getParentName()); addClass(def, id, parentId); } /** * Finds the class with the given name. * * @param name the class name * @param useAutoload use autoload to locate the class if necessary * @param useImport import the class if necessary * * @return the found class or null if no class found. */ private QuercusClass createClassFromCache(int id, boolean useAutoload, boolean useImport) { if (id < _classDef.length && _classDef[id] != null) { ClassDef classDef = _classDef[id]; String parentName = classDef.getParentName(); QuercusClass parent = null; if (parentName != null) parent = findClass(parentName); if (parentName == null || parent != null) return createQuercusClass(id, classDef, parent); else return null; // php/ } ClassDef staticClass = _quercus.getClassDef(id); if (staticClass != null) return createQuercusClass(id, staticClass, null); // XXX: cache else return null; } /* * Registers an SPL autoload function. */ public void addAutoloadFunction(Callable fun) { if (fun == null) throw new NullPointerException(); if (_autoloadList == null) _autoloadList = new ArrayList<Callable>(); _autoloadList.add(fun); } /* * Unregisters an SPL autoload function. */ public void removeAutoloadFunction(Callable fun) { if (_autoloadList != null) { _autoloadList.remove(fun); //restore original __autoload functionality if (_autoloadList.size() == 0) _autoloadList = null; } } /* * Returns the registered SPL autoload functions. */ public ArrayList<Callable> getAutoloadFunctions() { return _autoloadList; } /** * Imports a PHP class. * * @param name of the PHP class * * @return true if matching php file was found and included. */ public boolean importPhpClass(String name) { if (_importMap == null) return false; String fullName = _importMap.getQualifiedPhp(name); URL url = null; ClassLoader loader = Thread.currentThread().getContextClassLoader(); if (fullName != null) { url = loader.getResource(fullName); } else { for (String entry : _importMap.getWildcardPhpList()) { url = loader.getResource(entry + '/' + name + ".php"); if (url != null) break; } } if (url != null) { includeOnce(new StringBuilderValue(url.toString())); return true; } else { return false; } } /** * Returns the declared classes. * * @return an array of the declared classes() */ public Value getDeclaredClasses() { ArrayList<String> list = new ArrayList<String>(); for (int i = 0; i < _classDef.length; i++) { if (_classDef[i] != null) list.add(_classDef[i].getName()); } HashMap<String, ClassDef> classMap = getModuleContext().getClassMap(); for (Map.Entry<String, ClassDef> entry : classMap.entrySet()) { list.add(entry.getKey()); } Collections.sort(list); ArrayValue array = new ArrayValueImpl(); Iterator<String> iter = list.iterator(); while (iter.hasNext()) { array.put(iter.next()); } return array; } /** * Finds the class with the given name. * * @param name the class name * @return the found class or null if no class found. */ public QuercusClass findAbstractClass(String name) { QuercusClass cl = findClass(name, true, true); if (cl != null) return cl; throw createErrorException(L.l("'{0}' is an unknown class name.", name)); /* // return _quercus.findJavaClassWrapper(name); return null; */ } /** * Finds the class with the given name. * * @param name the class name * @return the found class * @throws QuercusRuntimeException if the class is not found */ public QuercusClass getClass(String name) { QuercusClass cl = findClass(name); if (cl != null) return cl; else throw createErrorException(L.l("'{0}' is an unknown class.", name)); } public void clearClassCache() { // _classCache.clear(); } QuercusClass createJavaQuercusClass(JavaClassDef def) { int id = getQuercus().getClassId(def.getName()); if (_qClass.length <= id) { QuercusClass []oldClassList = _qClass; _qClass = new QuercusClass[id + 256]; System.arraycopy(oldClassList, 0, _qClass, 0, oldClassList.length); } if (_qClass[id] == null) _qClass[id] = def.getQuercusClass(); return _qClass[id]; } QuercusClass createQuercusClass(int id, ClassDef def, QuercusClass parent) { QuercusClass qClass = _quercus.getCachedClass(id); // php/0ac0 if (_qClass.length <= id) { QuercusClass []oldClassList = _qClass; _qClass = new QuercusClass[id + 256]; System.arraycopy(oldClassList, 0, _qClass, 0, oldClassList.length); } if (qClass == null || qClass.isModified() || qClass.getClassDef() != def || qClass.getParent() != parent) { qClass = new QuercusClass(getModuleContext(), def, parent); _qClass[id] = qClass; qClass.validate(this); _quercus.setCachedClass(id, qClass); } _qClass[id] = qClass; return qClass; } /** * Returns true if class has already been initialized. */ public boolean isInitializedClass(String name) { return _initializedClassSet.contains(name); } /** * Mark this class as being initialized. */ public void addInitializedClass(String name) { _initializedClassSet.add(name); } /** * Finds the class and method. * * @param className the class name * @param methodName the method name * @return the found method or null if no method found. */ public AbstractFunction findFunction(String className, String methodName) { QuercusClass cl = findClass(className); if (cl == null) throw new QuercusRuntimeException(L.l("'{0}' is an unknown class", className)); return cl.findFunction(methodName); } /** * Returns the appropriate callback. */ /* public Callback createCallback(Value value) { if (value == null || value.isNull()) return null; value = value.toValue(); if (value instanceof Callback) { return (Callback) value; } else if (value instanceof StringValue) { // php/1h0o if (value.isEmpty()) return null; String s = value.toString(); int p = s.indexOf("::"); if (p < 0) return new CallbackFunction(this, s); else { String className = s.substring(0, p); String methodName = s.substring(p + 2); QuercusClass cl = findClass(className); if (cl == null) throw new IllegalStateException(L.l("can't find class {0}", className)); return new CallbackFunction(cl.getFunction(createString(methodName))); } } else if (value.isArray()) { Value obj = value.get(LongValue.ZERO); Value nameV = value.get(LongValue.ONE); if (! nameV.isString()) throw new IllegalStateException( L.l("'{0}' ({1}) is an unknown callback name", nameV, nameV.getClass().getSimpleName())); String name = nameV.toString(); if (obj.isObject()) { AbstractFunction fun; int p = name.indexOf("::"); // php/09lf if (p > 0) { String clsName = name.substring(0, p); name = name.substring(p + 2); QuercusClass cls = findClass(clsName); if (cls == null) { warning(L.l("Callback: '{0}' is not a valid callback class for {1}", clsName, name)); return null; } if (cls == null) throw new IllegalStateException(L.l("can't find class '{0}'", obj.toString())); // fun = cls.getFunction(name); } return new CallbackObjectMethod(this, obj, createString(name)); } else { QuercusClass cl = findClass(obj.toString()); if (cl == null) { warning(L.l("Callback: '{0}' is not a valid callback string for {1}", obj.toString(), obj)); return null; } return new CallbackObjectMethod(this, cl, createString(name)); } } else return null; } */ /** * Evaluates an included file. */ public Value requireOnce(StringValue include) { return include(getSelfDirectory(), include, true, true); } /** * Evaluates an included file. */ public Value require(StringValue include) { return include(getSelfDirectory(), include, true, false); } /** * Evaluates an included file. */ public Value include(StringValue include) { return include(getSelfDirectory(), include, false, false); } /** * Evaluates an included file. */ public Value includeOnce(StringValue include) { return include(getSelfDirectory(), include, false, true); } /** * Evaluates an included file. */ public Value includeOnce(Path scriptPwd, StringValue include, boolean isRequire) { return include(scriptPwd, include, isRequire, true); } /** * Evaluates an included file. */ public Value include(Path scriptPwd, StringValue include, boolean isRequire, boolean isOnce) { try { Path pwd = getPwd(); Path path = lookupInclude(include, pwd, scriptPwd); if (path != null) { } else if (isRequire) { error(L.l("'{0}' is not a valid include path", include)); return BooleanValue.FALSE; } else { warning(L.l("'{0}' is not a valid include path", include)); return BooleanValue.FALSE; } // php/0b2d if (! _isAllowUrlInclude && isUrl(path)) { String msg = (L.l("not allowed to include url {0}", path.getURL())); log.warning(dbgId() + msg); error(msg); return BooleanValue.FALSE; } QuercusPage page = _includeMap.get(path); if (page != null && isOnce) return BooleanValue.TRUE; else if (page == null || page.isModified()) { page = _quercus.parse(path); pageInit(page); _includeMap.put(path, page); } return executePage(page); } catch (IOException e) { throw new QuercusModuleException(e); } } void executePage(Path path) { if (log.isLoggable(Level.FINEST)) { log.finest(this + " execute " + path); } try { QuercusPage page = _quercus.parse(path); pageInit(page); executePage(page); } catch (IOException e) { throw new QuercusException(e); } } /* * Returns true if this path is likely to be a URL. */ private boolean isUrl(Path path) { String scheme = path.getScheme(); if ("".equals(scheme) || "file".equals(scheme) || "memory".equals(scheme)) { return false; } if (path instanceof JarPath) { // php/0h1a return isUrl(((JarPath) path).getContainer()); } // XXX: too restrictive for filters return ! "php".equals(scheme) || "php://input".equals(path.toString()) || path.toString().startsWith("php://filter"); } /** * Looks up based on the pwd. */ public Path lookupPwd(Value relPathV) { if (! relPathV.isset()) return null; StringValue relPath = relPathV.toStringValue(); if (relPath.length() == 0) return null; Path path = _lookupCache.get(relPath); if (path == null) { path = getPwd().lookup(normalizePath(relPath)); _lookupCache.put(relPath, path); } return path; } /** * Looks up the path. */ public Path lookup(StringValue relPath) { return lookupInclude(getSelfDirectory(), normalizePath(relPath)); } /** * Looks up the path. */ public Path lookupInclude(StringValue relPath) { return lookupInclude(relPath, getPwd(), getSelfDirectory()); } private Path lookupInclude(StringValue include, Path pwd, Path scriptPwd) { String includePath = getDefaultIncludePath(); Path path = _quercus.getIncludeCache(include, includePath, pwd, scriptPwd); if (path == null) { path = lookupIncludeImpl(include, pwd, scriptPwd); /* if (path == null) path = NullPath.NULL; */ if (path != null) _quercus.putIncludeCache(include, includePath, pwd, scriptPwd, path); } if (path == NullPath.NULL) path = null; _includePath = includePath; _includePathIniCount = _iniCount; return path; } private String getDefaultIncludePath() { String includePath = _includePath; if (_includePathIniCount != _iniCount) { includePath = QuercusContext.INI_INCLUDE_PATH.getAsString(this); _includePath = null; _includePathList = null; } if (includePath == null) includePath = "."; return includePath; } private Path lookupIncludeImpl(StringValue includeValue, Path pwd, Path scriptPwd) { String include = normalizePath(includeValue); // php/0b0g Path path = lookupInclude(pwd, include); if (path == null) { // php/0b0l path = lookupInclude(scriptPwd, include); } if (path == null) { // php/0b21 path = scriptPwd.lookup(include); if (! includeExists(path)) path = null; } return path; } /** * Looks up the path. */ private Path lookupInclude(Path pwd, String relPath) { ArrayList<Path> pathList = getIncludePath(pwd); for (int i = 0; i < pathList.size(); i++) { Path path = pathList.get(i).lookup(relPath); if (path.canRead() && ! path.isDirectory()) { return path; } } return null; } private boolean includeExists(Path path) { if (path.canRead() && ! path.isDirectory()) return true; else if (! getQuercus().isRequireSource()) return getQuercus().includeExists(path); else return false; } /** * Returns the include path. */ private ArrayList<Path> getIncludePath(Path pwd) { String includePath = getDefaultIncludePath(); if (_includePathList == null) { _includePathList = new ArrayList<String>(); _includePathMap = new HashMap<Path,ArrayList<Path>>(); int head = 0; int tail; String pathSeparator = FileModule.PATH_SEPARATOR; int length = pathSeparator.length(); while ((tail = includePath.indexOf(pathSeparator, head)) >= 0) { String subpath = includePath.substring(head, tail); _includePathList.add(normalizePath(subpath)); head = tail + length; } String subpath = includePath.substring(head); _includePathList.add(normalizePath(subpath)); _includePath = includePath; _includePathIniCount = _iniCount; } ArrayList<Path> pathList = _includePathMap.get(pwd); if (pathList == null) { pathList = new ArrayList<Path>(); for (int i = 0; i < _includePathList.size(); i++) { pathList.add(pwd.lookup(_includePathList.get(i))); } _includePathMap.put(pwd, pathList); } return pathList; } /** * Sets the include path. */ public String setIncludePath(String path) { String prevIncludePath = QuercusContext.INI_INCLUDE_PATH.getAsString(this); if (_defaultIncludePath == null) _defaultIncludePath = prevIncludePath; QuercusContext.INI_INCLUDE_PATH.set(this, path); // reset include path cache count _includePathIniCount = -1; return prevIncludePath; } public String normalizePath(CharSequence path) { if (Path.isWindows()) { _cb.setLength(0); int len = path.length(); if (len >= 3) { char ch; char ch3; if (path.charAt(1) == ':' && ('a' <= (ch = path.charAt(0)) && ch <= 'z' || 'A' <= ch && ch <= 'Z') && (ch3 = path.charAt(2)) != '/' && ch3 != '\\') { _cb.append(ch); _cb.append(':'); _cb.append('\\'); _cb.append(ch3); for (int i = 3; i < len; i++) { _cb.append(path.charAt(i)); } return _cb.toString(); } } } return path.toString(); /* if (len >= 3) { char ch = path.charAt(0); char ch2 = path.charAt(1); char ch3 = path.charAt(2); _cb.append(ch); _cb.append(ch2); offset += 2; if (ch == '/') { if (('a' <= ch2 && ch2 <= 'z' || 'A' <= ch2 && ch2 <= 'Z') && ch3 == ':') { _cb.append(ch3); offset += 1; char ch4; if (len >= 4 && (ch4 = path.charAt(3)) != '/' && ch4 != '\\') { _cb.append('/'); _cb.append(ch4); offset += 1; } } else if (ch2 == ':' && ch3 != '/' && ch3 != '\\') { _cb.append('/'); _cb.append(ch3); offset += 1; } } if (ch == '/' && ('a' <= ch2 && ch2 <= 'z' || 'A' <= ch2 && ch2 <= 'Z') && ch3 == ':') { _cb.append(ch3); offset += 1; char ch4; if (len >= 4 && (ch4 = path.charAt(3)) != '/' && ch4 != '\\') { _cb.append('/'); _cb.append(ch4); offset += 1; } } else if (('a' <= ch && ch <= 'z' || 'A' <= ch && ch <= 'Z') && ch2 == ':' && ch3 != '/' && ch3 != '\\') { _cb.append('/'); _cb.append(ch3); offset += 1; } } for (; offset < len; offset++) { _cb.append(path.charAt(offset)); } return _cb.toString(); } else return path.toString(); */ } /** * Restores the default include path. */ public void restoreIncludePath() { QuercusContext.INI_INCLUDE_PATH.set(this, _defaultIncludePath); } /** * Returns all the included files. */ public ArrayValue getIncludedFiles() { ArrayValue array = new ArrayValueImpl(); ArrayList<String> list = new ArrayList<String>(); for (Path path : _includeMap.keySet()) { list.add(path.getNativePath()); } Collections.sort(list); for (String pathName : list) { array.put(createString(pathName)); } return array; } /** * Handles error suppression. */ public Value suppress(int errorMask, Value value) { setErrorMask(errorMask); return value; } /** * Handles exit/die */ public Value exit(Value msg) { if (msg.isNull() || msg instanceof LongValue) return exit(); try { getOut().print(msg.toString()); } catch (IOException e) { log.log(Level.WARNING, e.toString(), e); } throw new QuercusExitException(msg.toString()); } /** * Handles exit/die */ public Value exit() { throw new QuercusExitException(); } /** * Handles exit/die */ public Value die(String msg) { try { getOut().print(msg); } catch (IOException e) { log.log(Level.WARNING, e.toString(), e); } throw new QuercusDieException(msg); } /** * Handles exit/die */ public Value die() { throw new QuercusDieException(); } /** * Handles exit/die */ public Value cast(Class cl, Value value) { value = value.toValue(); if (value.isNull()) return null; else if (cl.isAssignableFrom(value.getClass())) return value; else { // php/3cr2 warning(L.l("{0} ({1}) is not assignable to {2}", value, value.getClass().getName(), cl.getName())); return null; } } /** * Returns the first value */ public static Value first(Value value) { return value; } /** * Returns the first value */ public static Value first(Value value, Value a1) { return value; } /** * Returns the first value */ public static Value first(Value value, double a1) { return value; } /** * Returns the first value */ public static long first(long value, Value a1) { return value; } /** * Returns the first value */ public static double first(double value, Value a1) { return value; } /** * Returns the first value */ public static long first(long value, double a1) { return value; } /** * Returns the first value */ public static double first(double value, double a1) { return value; } /** * Returns the first value */ public static Value first(Value value, Value a1, Value a2) { return value; } /** * Returns the first value */ public static Value first(Value value, Value a1, Value a2, Value a3) { return value; } /** * Returns the first value */ public static Value first(Value value, Value a1, Value a2, Value a3, Value a4) { return value; } /** * Returns the first value */ public static Value first(Value value, Value a1, Value a2, Value a3, Value a4, Value a5) { return value; } /** * Check for expected type. */ public Value expectString(Value value) { if (! value.isString() && ! value.isLong() && ! value.isDouble() && ! value.isBoolean() && ! value.isNull()) { //warning(L.l("argument must be a string, but {0} given", // value.getType())); return new UnexpectedValue(value); } return value; } /** * Check for expected type. */ public Value expectNumeric(Value value) { if (! value.isNull() && ! value.isLongConvertible()) { //warning(L.l("argument must be numeric, but {0} given", // value.getType())); return new UnexpectedValue(value); } return value; } /** * Check for expected type. */ public Value expectBoolean(Value value) { if (! value.isBoolean() && ! value.isNull() && ! value.isString() && ! value.isNumeric()) { //warning(L.l("argument must be boolean, but {0} given", // value.getType())); return new UnexpectedValue(value); } return value; } /** * Check for type hinting */ public void checkTypeHint(Value value, String type, String argName, String functionName) { if (value.isNull()) { error(L.l( "'{0}' is an unexpected value for " + "arg '{1}' in function '{2}', expected '{3}'", value, argName, functionName, type)); } } /** * A fatal runtime error. */ public Value error(String msg) { return error(B_ERROR, "", msg + getFunctionLocation()); } /** * A fatal runtime error. */ public Value error(Location location, String msg) { return error(B_ERROR, location, msg + getFunctionLocation()); } /** * A fatal runtime error. */ public Value error(String loc, String msg) { return error(B_ERROR, loc, msg + getFunctionLocation()); } /** * A warning with an exception. */ public Value error(String msg, Throwable e) { log.log(Level.WARNING, e.toString(), e); return error(msg); } /** * A warning with an exception. */ public Value error(Throwable e) { log.log(Level.WARNING, e.toString(), e); return error(e.toString()); } /** * A fatal runtime error. */ public QuercusRuntimeException createErrorException(String msg) throws QuercusRuntimeException { return createErrorException(null, msg); } /** * A fatal runtime error. */ public QuercusRuntimeException createErrorException(Location location, String msg) throws QuercusRuntimeException { if (location == null || location.isUnknown()) location = getLocation(); String prefix = location.getMessagePrefix(); String fullMsg = msg + getFunctionLocation(); error(B_ERROR, location, fullMsg); String exMsg = prefix + fullMsg; return new QuercusRuntimeException(fullMsg); } /** * A fatal runtime error. */ public QuercusRuntimeException createErrorException(Throwable e) throws QuercusRuntimeException { Location location = getLocation(); String prefix = location.getMessagePrefix(); String fullMsg = e.toString() + getFunctionLocation(); error(B_ERROR, location, fullMsg); String exMsg = prefix + fullMsg; return new QuercusRuntimeException(fullMsg, e); } /** * A runtime warning. */ public Value warning(String msg) { int mask = 1 << B_WARNING; if ((getErrorMask() & mask) != 0) { if (log.isLoggable(Level.FINER)) { QuercusException e = new QuercusException(msg); log.log(Level.FINER, e.toString(), e); } } return error(B_WARNING, "", msg + getFunctionLocation()); } /** * A runtime warning. */ public Value warning(Location location, String msg) { int mask = 1 << B_WARNING; if ((getErrorMask() & mask) != 0) { if (log.isLoggable(Level.FINER)) { QuercusException e = new QuercusException(msg); log.log(Level.FINER, e.toString(), e); } } return error(B_WARNING, location, "", msg + getFunctionLocation()); } /** * A warning with an exception. */ public Value warning(String msg, Throwable e) { log.log(Level.FINE, e.toString(), e); return warning(msg); } /** * A warning with an exception. */ public Value warning(Location location, String msg, Throwable e) { log.log(Level.FINE, e.toString(), e); return warning(location, msg); } /** * A warning with an exception. */ public Value warning(Throwable e) { return warning(e.toString(), e); } /** * A warning with an exception. */ public Value warning(Location location, Throwable e) { return warning(location, e.toString(), e); } /** * A runtime strict warning. */ public Value strict(String msg) { if (log.isLoggable(Level.FINER)) { QuercusException e = new QuercusException(msg); log.log(Level.FINER, e.toString(), e); } return error(B_STRICT, "", msg + getFunctionLocation()); } /** * A warning about an invalid argument passed to a function. */ public Value invalidArgument(String name, Object value) { return warning(L.l("invalid value `{0}' for `{1}'", value, name)); } /** * A warning about an deprecated argument passed to a function. */ public Value deprecatedArgument(String name) { return strict(L.l("argument `{1}' is deprecated", name)); } /** * A notice. */ public Value notice(String msg) { return error(B_NOTICE, "", msg + getFunctionLocation()); } /** * A notice with an exception. */ public Value notice(String msg, Throwable e) { log.log(Level.FINE, e.toString(), e); return notice(msg); } /** * A stub notice. */ public Value stub(String msg) { if (log.isLoggable(Level.FINE)) log.fine(getLocation().getMessagePrefix() + msg); return NullValue.NULL; } public static Value nullAsFalse(Value value) { return value == null || value.isNull() ? BooleanValue.FALSE : value; } /** * A parse error */ public Value parse(String msg) throws Exception { return error(B_PARSE, "", msg); } /** * A parse error */ public Value compileError(String msg) { return error(B_COMPILE_ERROR, "", msg); } /** * A parse warning */ public Value compileWarning(String msg) { return error(B_COMPILE_WARNING, "", msg); } /** * Returns the error mask. */ public int getErrorMask() { return getIni("error_reporting").toInt(); } /** * Sets the error mask. */ public int setErrorMask(int mask) { int oldMask = getErrorMask(); setIni("error_reporting", LongValue.create(mask)); return oldMask; } /** * Sets an error handler */ public void setErrorHandler(int mask, Callable fun) { for (int i = 0; i < _errorHandlers.length; i++) _prevErrorHandlers[i] = _errorHandlers[i]; if ((mask & E_ERROR) != 0) _errorHandlers[B_ERROR] = fun; if ((mask & E_WARNING) != 0) _errorHandlers[B_WARNING] = fun; if ((mask & E_PARSE) != 0) _errorHandlers[B_PARSE] = fun; if ((mask & E_NOTICE) != 0) _errorHandlers[B_NOTICE] = fun; if ((mask & E_USER_ERROR) != 0) _errorHandlers[B_USER_ERROR] = fun; if ((mask & E_USER_WARNING) != 0) _errorHandlers[B_USER_WARNING] = fun; if ((mask & E_USER_NOTICE) != 0) _errorHandlers[B_USER_NOTICE] = fun; if ((mask & E_STRICT) != 0) _errorHandlers[B_STRICT] = fun; if ((mask & E_RECOVERABLE_ERROR) != 0) _errorHandlers[B_RECOVERABLE_ERROR] = fun; } /** * Sets an error handler */ public void restoreErrorHandler() { for (int i = 0; i < _errorHandlers.length; i++) _errorHandlers[i] = _prevErrorHandlers[i]; } /** * Gets the exception handler */ public Callable getExceptionHandler() { return _exceptionHandler; } /** * Sets an exception handler */ public Value setExceptionHandler(Callable fun) { _prevExceptionHandler = _exceptionHandler; _exceptionHandler = fun; if (_prevExceptionHandler != null) { // return ((Value) _prevExceptionHandler).toStringValue(); } else return NullValue.NULL; } /** * Restore an exception handler */ public void restoreExceptionHandler() { _exceptionHandler = _prevExceptionHandler; } /* * Writes an error. */ public Value error(int code, String locString, String msg) { return error(code, null, locString, msg); } /* * Writes an error. */ public Value error(int code, Location location, String msg) { return error(code, location, "", msg); } /** * Writes an error. */ public Value error(int code, Location location, String loc, String msg) { int mask = 1 << code; int errorMask = getErrorMask(); if (log.isLoggable(Level.FINEST)) { QuercusException e = new QuercusException(loc + msg); log.log(Level.FINEST, e.toString(), e); } if ((errorMask & mask) != 0) { if (log.isLoggable(Level.FINE)) log.fine(this + " " + loc + msg); } if (code >= 0 && code < _errorHandlers.length && _errorHandlers[code] != null) { Callable handler = _errorHandlers[code]; try { _errorHandlers[code] = null; Value fileNameV = NullValue.NULL; if (location == null || location.isUnknown()) location = getLocation(); String fileName = location.getFileName(); if (fileName != null) fileNameV = createString(fileName); Value lineV = NullValue.NULL; int line = location.getLineNumber(); if (line > 0) lineV = LongValue.create(line); Value context = NullValue.NULL; handler.call(this, LongValue.create(mask), createString(msg), fileNameV, lineV, context); return NullValue.NULL; } catch (RuntimeException e) { throw e; } catch (Exception e) { throw new RuntimeException(e); } finally { _errorHandlers[code] = handler; } } if ((errorMask & mask) != 0) { try { String fullMsg = (getLocationPrefix(location, loc) + getCodeName(mask) + msg); if (getIniBoolean("track_errors")) setGlobalValue("php_errormsg", createString(fullMsg)); if ("stderr".equals(getIniString("display_errors"))) { // initial newline to match PHP System.err.println("\n" + fullMsg); } else if (getIniBoolean("display_errors")) { // initial newline to match PHP getOut().println("\n" + fullMsg); } if (getIniBoolean("log_errors")) log.info(fullMsg); } catch (IOException e) { log.log(Level.FINE, e.toString(), e); } } if ((mask & (E_ERROR | E_CORE_ERROR | E_COMPILE_ERROR | E_USER_ERROR)) != 0) { String locPrefix = getLocationPrefix(location, loc); QuercusErrorException exn; if (! "".equals(locPrefix)) { /* throw new QuercusLineExitException(getLocation() + getCodeName(mask) + msg); */ exn = new QuercusErrorException(locPrefix + getCodeName(mask) + msg); } else exn = new QuercusErrorException(msg); exn.fillInStackTrace(); if (log.isLoggable(Level.FINER)) { log.log(Level.FINER, exn.toString(), exn); } throw exn; } return NullValue.NULL; } /** * Returns the displayable location prefix. This may be slow * for compiled-mode because of the need to match line numbers. */ private String getLocationPrefix(Location location, String loc) { if (loc != null && ! "".equals(loc)) return loc; if (location == null || location.isUnknown()) location = getLocation(); return location.getMessagePrefix(); } /** * Returns the error code name. */ private String getCodeName(int code) { switch (code) { case E_ERROR: return "Fatal Error: "; case E_WARNING: return "Warning: "; case E_PARSE: return "Parse Error: "; case E_NOTICE: return "Notice: "; case E_CORE_ERROR: return "Fatal Error: "; case E_CORE_WARNING: return "Warning: "; case E_COMPILE_ERROR: return "Fatal Error: "; case E_COMPILE_WARNING: return "Warning : "; case E_USER_ERROR: return "Fatal Error: "; case E_USER_WARNING: return "Warning: "; case E_USER_NOTICE: return "Notice: "; case E_STRICT: return "Notice: "; case E_RECOVERABLE_ERROR: return "Error: "; default: return String.valueOf("ErrorCode(" + code + ")"); } } /** * Returns the source of an error line. */ public static String []getSourceLine(Path path, int sourceLine, int length) { if (path == null) return null; else if (path instanceof NullPath) { // for QuercusScriptEngine.eval() where only a Reader is passed in // XXX: not too pretty return null; } ReadStream is = null; try { is = path.openRead(); int line = 1; String lineString; for (; line < sourceLine; line++) { lineString = is.readLine(); if (lineString == null) return null; } String []result = new String[length]; int i = line - sourceLine; for (; i < length && (lineString = is.readLine()) != null; i++) { result[i] = lineString; } return result; } catch (IOException e) { log.log(Level.FINE, e.toString(), e); } finally { if (is != null) is.close(); } return null; } public final Location setLocation(Location newLocation) { Location location = _location; _location = newLocation; return location; } protected final Location getLocationImpl() { return _location; } /** * Returns the current execution location. * * Use with care, for compiled code this can be a relatively expensive * operation. */ public Location getLocation() { Location location = _location; if (location != null) return location; Expr call = peekCall(0); if (call != null) return call.getLocation(); return Location.UNKNOWN; } public int getSourceLine(String className, int javaLine) { return javaLine; } /** * Returns the current function. */ public String getFunctionLocation() { // XXX: need to work with compiled code, too Expr call = peekCall(0); if (call != null) return call.getFunctionLocation(); else return ""; } /** * Converts a boolean to the boolean value */ public static Value toValue(boolean value) { return value ? BooleanValue.TRUE : BooleanValue.FALSE; } /** * Converts a boolean to the boolean value */ public static Value toValue(long value) { return LongValue.create(value); } /** * Converts to a variable */ public static Var toVar(Value value) { if (value instanceof Var) return (Var) value; else if (value == null) return new Var(); else return new Var(value); } /** * Sets a vield variable */ public static Value setFieldVar(Value oldValue, Value value) { if (value instanceof Var) return value; else if (oldValue instanceof Var) return new Var(value); else return value; } /** * Sets a reference */ public static Value setRef(Value oldValue, Value value) { // php/3243 if (value instanceof Var) return value; /* else if (oldValue instanceof Var) { oldValue.set(value); return oldValue; } */ else return new Var(value); } /** * Sets a reference */ public static Var setEnvRef(Var oldVar, Value value) { // 3ab7 // XXX: need better test case, since that one isn't allowed by php if (value instanceof Var) return (Var) value; else { oldVar.set(value); return oldVar; } } /** * Returns the last value. */ public static Value comma(Value a0, Value a1) { return a1; } /** * Returns the last value. */ public static Value comma(Value a0, Value a1, Value a2) { return a2; } /** * Returns the last value. */ public static Value comma(Value a0, Value a1, Value a2, Value a3) { return a3; } /** * Returns the last value. */ public static Value comma(Value a0, Value a1, Value a2, Value a3, Value a4) { return a4; } // long comma /** * Returns the last value. */ public static long comma(Value a0, long a1) { return a1; } /** * Returns the last value. */ public static long comma(long a0, long a1) { return a1; } /** * Returns the last value. */ public static Value comma(long a0, Value a1) { return a1; } // // comma // /** * Returns the last value. */ public static double comma(Value a0, double a1) { return a1; } /** * Returns the last value. */ public static double comma(double a0, double a1) { return a1; } /** * Returns the last value. */ public static Value comma(double a0, Value a1) { return a1; } /** * Calls a parent::name method. */ /* public Value callParentMethod(Value qThis, String parentName, String funName, Value []args) { AbstractFunction fun = getClass(parentName).getFunction(funName); Value retValue = fun.callMethod(this, qThis, args); if (fun.isConstructor()) qThis.setJavaObject(retValue); return retValue; } */ /** * Calls a parent::name method. */ /* public Value callParentMethod(Value qThis, String parentName, int hash, char []name, int len, Value []args) { AbstractFunction fun = getClass(parentName).getFunction(hash, name, len); Value retValue = fun.callMethod(this, qThis, args); if (fun.isConstructor()) qThis.setJavaObject(retValue); return retValue; } */ public String toString() { return "Env[]"; } /** * Returns ifNull if condition.isNull(), otherwise returns ifNotNull. */ public Value ifNull(Value condition, Value ifNull, Value ifNotNull) { return condition.isNull() ? ifNull : ifNotNull; } /** * Returns the locale info. */ public LocaleInfo getLocaleInfo() { if (_locale == null) _locale = new LocaleInfo(); return _locale; } public long getMicroTime() { long nanoTime = _quercus.getExactTimeNanoseconds(); if (_firstMicroTime <= 0) { _firstNanoTime = nanoTime; _firstMicroTime = _quercus.getExactTime() * 1000 + (_firstNanoTime % 1000000L) / 1000; return _firstMicroTime; } else { long microDiff = (nanoTime - _firstNanoTime) / 1000; return _firstMicroTime + microDiff; } } /** * Registers a shutdown function. */ public void addShutdown(Callable callback, Value []args) { if (_shutdownList == null) _shutdownList = new ArrayList<Shutdown>(); _shutdownList.add(new Shutdown(callback, args)); } // XXX: hack until can clean up public void setGzStream(Object obj) { _gzStream = obj; } // XXX: hack until can clean up public Object getGzStream() { return _gzStream; } public void startDuplex(Object duplex) { throw new UnsupportedOperationException(getClass().getName()); /* if (_duplex != null) return; _duplex = duplex; */ } public void closeDuplex() { _duplex = null; close(); } public Object getDuplex() { return _duplex; } /** * Called when the Env is no longer needed. */ public void close() { _quercus.completeEnv(this); /* if (_duplex != null) { log.fine(this + " skipping close for duplex mode"); return; } */ try { // php/1l0t // output buffers callbacks may throw an exception while (_outputBuffer != null) { popOutputBuffer(); } } //catch (Exception e) { //throw new RuntimeException(e); //} finally { cleanup(); } } private void cleanup() { // cleanup is in reverse order of creation if (_objCleanupList != null) { for (int i = _objCleanupList.size() - 1; i >= 0; i--) { ObjectExtValue objCleanup = _objCleanupList.get(i); try { if (objCleanup != null) objCleanup.cleanup(this); } catch (Throwable e) { log.log(Level.FINER, e.toString(), e); } } } if (_shutdownList != null) { for (int i = 0; i < _shutdownList.size(); i++) { try { _shutdownList.get(i).call(this); } catch (Throwable e) { log.log(Level.FINE, e.toString(), e); } } } try { sessionWriteClose(); } catch (Throwable e) { log.log(Level.FINE, e.toString(), e); } if (_cleanupList != null) { ArrayList<EnvCleanup> cleanupList = new ArrayList<EnvCleanup>(_cleanupList); // cleanup is in reverse order of creation for (int i = cleanupList.size() - 1; i >= 0; i--) { EnvCleanup envCleanup = cleanupList.get(i); try { if (envCleanup != null) envCleanup.cleanup(); } catch (Throwable e) { log.log(Level.FINER, e.toString(), e); } } } _threadEnv.set(_oldThreadEnv); for (int i = 0; _removePaths != null && i < _removePaths.size(); i++) { Path path = _removePaths.get(i); try { path.remove(); } catch (IOException e) { log.log(Level.FINER, e.toString(), e); } } AbstractFunction []fun = _fun; _fun = null; if (fun != null) { boolean isUsed = false; /** * Fix for Bug #4077 * Page may be null when if the Env was created throught * the (QuercusContext)-Constructor and therefor every * parameter except the context is null. */ if (_page != null && _page.setRuntimeFunction(fun)) { isUsed = true; } for (QuercusPage page : _includeMap.values()) { if (page.setRuntimeFunction(fun)) { isUsed = true; } } if (! isUsed) { for (int i = fun.length - 1; i >= 0; i--) { fun[i] = null; } _freeFunList.free(fun); } } ClassDef []classDef = _classDef; _classDef = null; if (classDef != null) { // php/0b3b for (int i = 0; i < classDef.length; i++) { classDef[i] = null; } _freeClassDefList.free(classDef); } QuercusClass []qClass = _qClass; _qClass = null; if (qClass != null) { for (int i = 0; i < qClass.length; i++) { qClass[i] = null; } _freeClassList.free(qClass); } Value []consts = _const; _const = null; if (consts != null) { for (int i = 0; i < consts.length; i++) { consts[i] = null; } _freeConstList.free(consts); } if (_gmtDate != null) _freeGmtDateList.free(_gmtDate); if (_localDate != null) _freeLocalDateList.free(_localDate); } public void sessionWriteClose() { SessionArrayValue session = _session; _session = null; if (session != null) { SessionCallback callback = getSessionCallback(); if (callback != null) { String value; // php/1k6e if (session.getSize() > 0) value = VariableModule.serialize(this, session.getArray()); else value = ""; callback.write(this, session.getId(), value); callback.close(this); } else { _quercus.saveSession(this, session); Value sessionCopy = session.copy(this); setGlobalValue("_SESSION", sessionCopy); setGlobalValue("HTTP_SESSION_VARS", sessionCopy); } } } public String dbgId() { return getClass().getSimpleName() + "[" + _selfPath + "] "; } static class FieldGetEntry { private final String _className; private final StringValue _fieldName; FieldGetEntry(String className, StringValue fieldName) { _className = className; _fieldName = fieldName; } public boolean equals(Object o) { if (! (o instanceof FieldGetEntry)) return false; FieldGetEntry entry = (FieldGetEntry) o; return entry._className.equals(_className) && entry._fieldName.equals(_fieldName); } } static class ClassKey { private final WeakReference<ClassDef> _defRef; private final WeakReference<QuercusClass> _parentRef; private final int _hash; ClassKey(ClassDef def, QuercusClass parent) { _defRef = new WeakReference<ClassDef>(def); if (parent != null) _parentRef = new WeakReference<QuercusClass>(parent); else _parentRef = null; // hash needs to be precalculated so losing a weak references won't // change the result int hash = 37; if (def != null) hash = 65521 * hash + def.hashCode(); if (parent != null) hash = 65521 * hash + parent.hashCode(); _hash = hash; } public int hashCode() { return _hash; } public boolean equals(Object o) { ClassKey key = (ClassKey) o; ClassDef aDef = _defRef.get(); ClassDef bDef = key._defRef.get(); if (aDef != bDef) return false; if (_parentRef == key._parentRef) return true; else if (_parentRef == null || key._parentRef == null) return false; QuercusClass aParent = _parentRef.get(); QuercusClass bParent = key._parentRef.get(); return (aParent != null && aParent.equals(bParent)); } @Override public String toString() { return (getClass().getSimpleName() + "[" + _defRef.get() + "," + (_parentRef != null ? _parentRef.get() : null) + "]"); } } static { SPECIAL_VARS.put(MethodIntern.intern("GLOBALS"), _GLOBAL); SPECIAL_VARS.put(MethodIntern.intern("_SERVER"), _SERVER); SPECIAL_VARS.put(MethodIntern.intern("_GET"), _GET); SPECIAL_VARS.put(MethodIntern.intern("_POST"), _POST); SPECIAL_VARS.put(MethodIntern.intern("_FILES"), _FILES); SPECIAL_VARS.put(MethodIntern.intern("_REQUEST"), _REQUEST); SPECIAL_VARS.put(MethodIntern.intern("_COOKIE"), _COOKIE); SPECIAL_VARS.put(MethodIntern.intern("_SESSION"), _SESSION); SPECIAL_VARS.put(MethodIntern.intern("_ENV"), _ENV); SPECIAL_VARS.put(MethodIntern.intern("HTTP_GET_VARS"), HTTP_GET_VARS); SPECIAL_VARS.put(MethodIntern.intern("HTTP_POST_VARS"), HTTP_POST_VARS); SPECIAL_VARS.put(MethodIntern.intern("HTTP_POST_FILES"), HTTP_POST_FILES); SPECIAL_VARS.put(MethodIntern.intern("HTTP_COOKIE_VARS"), HTTP_COOKIE_VARS); SPECIAL_VARS.put(MethodIntern.intern("HTTP_SERVER_VARS"), HTTP_SERVER_VARS); SPECIAL_VARS.put(MethodIntern.intern("PHP_SELF"), PHP_SELF); SPECIAL_VARS.put(MethodIntern.intern("HTTP_RAW_POST_DATA"), HTTP_RAW_POST_DATA); DEFAULT_QUERY_SEPARATOR_MAP = new int[128]; DEFAULT_QUERY_SEPARATOR_MAP['&'] = 1; } }