0001: /*
0002: * Copyright (c) 1998-2008 Caucho Technology -- all rights reserved
0003: *
0004: * This file is part of Resin(R) Open Source
0005: *
0006: * Each copy or derived work must preserve the copyright notice and this
0007: * notice unmodified.
0008: *
0009: * Resin Open Source is free software; you can redistribute it and/or modify
0010: * it under the terms of the GNU General Public License as published by
0011: * the Free Software Foundation; either version 2 of the License, or
0012: * (at your option) any later version.
0013: *
0014: * Resin Open Source is distributed in the hope that it will be useful,
0015: * but WITHOUT ANY WARRANTY; without even the implied warranty of
0016: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, or any warranty
0017: * of NON-INFRINGEMENT. See the GNU General Public License for more
0018: * details.
0019: *
0020: * You should have received a copy of the GNU General Public License
0021: * along with Resin Open Source; if not, write to the
0022: *
0023: * Free Software Foundation, Inc.
0024: * 59 Temple Place, Suite 330
0025: * Boston, MA 02111-1307 USA
0026: *
0027: * @author Scott Ferguson
0028: */
0029:
0030: package com.caucho.quercus;
0031:
0032: import com.caucho.config.ConfigException;
0033: import com.caucho.quercus.annotation.ClassImplementation;
0034: import com.caucho.quercus.env.*;
0035: import com.caucho.quercus.lib.file.FileModule;
0036: import com.caucho.quercus.lib.session.QuercusSessionManager;
0037: import com.caucho.quercus.module.ModuleContext;
0038: import com.caucho.quercus.module.ModuleInfo;
0039: import com.caucho.quercus.module.ModuleStartupListener;
0040: import com.caucho.quercus.module.QuercusModule;
0041: import com.caucho.quercus.module.IniDefinitions;
0042: import com.caucho.quercus.module.IniDefinition;
0043: import com.caucho.quercus.page.InterpretedPage;
0044: import com.caucho.quercus.page.PageManager;
0045: import com.caucho.quercus.page.QuercusPage;
0046: import com.caucho.quercus.parser.QuercusParser;
0047: import com.caucho.quercus.program.*;
0048: import com.caucho.util.Alarm;
0049: import com.caucho.util.L10N;
0050: import com.caucho.util.Log;
0051: import com.caucho.util.LruCache;
0052: import com.caucho.util.IntMap;
0053: import com.caucho.util.TimedCache;
0054: import com.caucho.vfs.*;
0055:
0056: import javax.sql.DataSource;
0057: import javax.servlet.ServletContext;
0058: import javax.servlet.http.*;
0059: import java.io.IOException;
0060: import java.io.InputStream;
0061: import java.lang.ref.SoftReference;
0062: import java.lang.reflect.InvocationTargetException;
0063: import java.sql.Connection;
0064: import java.net.URL;
0065: import java.util.*;
0066: import java.util.logging.Level;
0067: import java.util.logging.Logger;
0068:
0069: /**
0070: * Facade for the PHP language.
0071: */
0072: public class Quercus {
0073: private static L10N L = new L10N(Quercus.class);
0074: private static final Logger log = Log.open(Quercus.class);
0075:
0076: private static HashSet<String> _super Globals = new HashSet<String>();
0077:
0078: private static IniDefinitions _ini = new IniDefinitions();
0079:
0080: private final PageManager _pageManager;
0081: private final QuercusSessionManager _sessionManager;
0082:
0083: private final ClassLoader _loader;
0084:
0085: private ModuleContext _moduleContext;
0086:
0087: private HashMap<String, StringValue> _internMap = new HashMap<String, StringValue>();
0088:
0089: private HashMap<String, ModuleInfo> _modules = new HashMap<String, ModuleInfo>();
0090:
0091: private HashSet<ModuleStartupListener> _moduleStartupListeners = new HashSet<ModuleStartupListener>();
0092:
0093: private HashSet<String> _extensionSet = new HashSet<String>();
0094:
0095: private HashMap<String, Value> _constMap = new HashMap<String, Value>();
0096:
0097: private HashMap<String, AbstractFunction> _funMap = new HashMap<String, AbstractFunction>();
0098:
0099: private HashMap<String, AbstractFunction> _lowerFunMap = new HashMap<String, AbstractFunction>();
0100:
0101: /*
0102: private ClassDef _stdClassDef;
0103: private QuercusClass _stdClass;
0104:
0105: private HashMap<String, ClassDef> _staticClasses
0106: = new HashMap<String, ClassDef>();
0107:
0108: private HashMap<String, ClassDef> _lowerStaticClasses
0109: = new HashMap<String, ClassDef>();
0110: */
0111:
0112: private HashMap<String, JavaClassDef> _javaClassWrappers = new HashMap<String, JavaClassDef>();
0113:
0114: private HashMap<String, JavaClassDef> _lowerJavaClassWrappers = new HashMap<String, JavaClassDef>();
0115:
0116: private final IniDefinitions _iniDefinitions = new IniDefinitions();
0117:
0118: private IdentityHashMap<String, Value> _iniMap;
0119:
0120: private HashMap<Value, Value> _serverEnvMap = new HashMap<Value, Value>();
0121:
0122: private IntMap _classNameMap = new IntMap(8192);
0123: private ClassDef[] _classMap = new ClassDef[256];
0124:
0125: private IntMap _constantNameMap = new IntMap(8192);
0126:
0127: private IntMap _functionNameMap = new IntMap(8192);
0128: private AbstractFunction[] _functionMap = new AbstractFunction[256];
0129:
0130: private LruCache<String, QuercusProgram> _evalCache = new LruCache<String, QuercusProgram>(
0131: 4096);
0132:
0133: private TimedCache<IncludeKey, Path> _includeCache = new TimedCache<IncludeKey, Path>(
0134: 4096, 10000);
0135:
0136: //private LruCache<DefinitionKey,SoftReference<DefinitionState>> _defCache
0137: // = new LruCache<DefinitionKey,SoftReference<DefinitionState>>(4096);
0138:
0139: private long _defCacheHitCount;
0140: private long _defCacheMissCount;
0141:
0142: // XXX: needs to be a timed LRU
0143: private LruCache<String, SessionArrayValue> _sessionMap = new LruCache<String, SessionArrayValue>(
0144: 4096);
0145:
0146: private HashMap<String, Object> _specialMap = new HashMap<String, Object>();
0147:
0148: private String _scriptEncoding;
0149:
0150: private String _phpVersion = "5.2.0";
0151: private String _mySqlVersion;
0152:
0153: private boolean _isStrict;
0154: private boolean _isRequireSource;
0155:
0156: private DataSource _database;
0157:
0158: private long _staticId;
0159:
0160: private Path _pwd;
0161: private Path _workDir;
0162:
0163: private ServletContext _servletContext;
0164:
0165: /**
0166: * Constructor.
0167: */
0168: public Quercus() {
0169: _loader = Thread.currentThread().getContextClassLoader();
0170:
0171: _moduleContext = getLocalContext();
0172:
0173: initStaticFunctions();
0174: initStaticClasses();
0175: initStaticClassServices();
0176:
0177: _pageManager = createPageManager();
0178:
0179: _sessionManager = createSessionManager();
0180:
0181: _workDir = getWorkDir();
0182:
0183: _iniDefinitions.addAll(_ini);
0184: }
0185:
0186: public Env createEnv(QuercusPage page, WriteStream out,
0187: HttpServletRequest request, HttpServletResponse response) {
0188: return new Env(this , page, out, request, response);
0189: }
0190:
0191: /**
0192: * Returns the working directory.
0193: */
0194: public Path getPwd() {
0195: if (_pwd == null)
0196: _pwd = new FilePath(System.getProperty("user.dir"));
0197:
0198: return _pwd;
0199: }
0200:
0201: /**
0202: * Sets the working directory.
0203: */
0204: public void setPwd(Path path) {
0205: _pwd = path;
0206: }
0207:
0208: public Path getWorkDir() {
0209: if (_workDir == null)
0210: _workDir = getPwd().lookup("WEB-INF/work");
0211:
0212: return _workDir;
0213: }
0214:
0215: public void setWorkDir(Path workDir) {
0216: _workDir = workDir;
0217: }
0218:
0219: public String getCookieName() {
0220: return "JSESSIONID";
0221: }
0222:
0223: public String getVersion() {
0224: return "Open Source 3.1.2";
0225: }
0226:
0227: public String getVersionDate() {
0228: return "20070628T2777";
0229: }
0230:
0231: protected PageManager createPageManager() {
0232: return new PageManager(this );
0233: }
0234:
0235: protected QuercusSessionManager createSessionManager() {
0236: return new QuercusSessionManager();
0237: }
0238:
0239: /**
0240: * Returns the context for this class loader.
0241: */
0242: public final ModuleContext getLocalContext() {
0243: return getLocalContext(_loader);
0244: }
0245:
0246: public ModuleContext getLocalContext(ClassLoader loader) {
0247: synchronized (this ) {
0248: if (_moduleContext == null)
0249: _moduleContext = createModuleContext(loader);
0250: }
0251:
0252: return _moduleContext;
0253: }
0254:
0255: protected ModuleContext createModuleContext(ClassLoader loader) {
0256: return new ModuleContext(loader);
0257: }
0258:
0259: /**
0260: * Returns the module context.
0261: */
0262: public ModuleContext getModuleContext() {
0263: return _moduleContext;
0264: }
0265:
0266: public QuercusSessionManager getQuercusSessionManager() {
0267: return _sessionManager;
0268: }
0269:
0270: /**
0271: * true if the pages should be compiled.
0272: */
0273: public boolean isCompile() {
0274: return _pageManager.isCompile();
0275: }
0276:
0277: /*
0278: * Returns true if this is the Professional version.
0279: */
0280: public boolean isPro() {
0281: return false;
0282: }
0283:
0284: /*
0285: * Returns true if Quercus is running under Resin.
0286: */
0287: public boolean isResin() {
0288: return false;
0289: }
0290:
0291: /**
0292: * Returns true if unicode.semantics is on.
0293: */
0294: public boolean isUnicodeSemantics() {
0295: boolean value = getIniBoolean("unicode.semantics");
0296:
0297: return value;
0298: }
0299:
0300: public StringValue createString(String v) {
0301: if (isUnicodeSemantics())
0302: return new UnicodeBuilderValue(v);
0303: else
0304: return new StringBuilderValue(v);
0305: }
0306:
0307: /**
0308: * Set true if pages should be compiled.
0309: */
0310: public void setCompile(boolean isCompile) {
0311: _pageManager.setCompile(isCompile);
0312: }
0313:
0314: /**
0315: * Set true if pages should be compiled.
0316: */
0317: public void setLazyCompile(boolean isCompile) {
0318: _pageManager.setLazyCompile(isCompile);
0319: }
0320:
0321: public String getScriptEncoding() {
0322: if (_scriptEncoding != null)
0323: return _scriptEncoding;
0324: else if (isUnicodeSemantics())
0325: return "utf-8";
0326: else
0327: return "iso-8859-1";
0328: }
0329:
0330: public void setScriptEncoding(String encoding) {
0331: _scriptEncoding = encoding;
0332: }
0333:
0334: public String getMysqlVersion() {
0335: return _mySqlVersion;
0336: }
0337:
0338: public void setMysqlVersion(String version) {
0339: _mySqlVersion = version;
0340: }
0341:
0342: public String getPhpVersion() {
0343: return _phpVersion;
0344: }
0345:
0346: public void setPhpVersion(String version) {
0347: _phpVersion = version;
0348: }
0349:
0350: /*
0351: * Sets the ServletContext.
0352: */
0353: public void setServletContext(ServletContext servletContext) {
0354: _servletContext = servletContext;
0355: }
0356:
0357: /*
0358: * Returns the ServletContext.
0359: */
0360: public ServletContext getServletContext() {
0361: return _servletContext;
0362: }
0363:
0364: /**
0365: * Sets the default data source.
0366: */
0367: public void setDatabase(DataSource database) {
0368: _database = database;
0369: }
0370:
0371: /**
0372: * Gets the default data source.
0373: */
0374: public DataSource getDatabase() {
0375: return _database;
0376: }
0377:
0378: /**
0379: * Gets the default data source.
0380: */
0381: public DataSource findDatabase(String driver, String url) {
0382: if (_database != null)
0383: return _database;
0384: else {
0385: ClassLoader loader = Thread.currentThread()
0386: .getContextClassLoader();
0387:
0388: try {
0389: Class cls = loader.loadClass(driver);
0390:
0391: return (DataSource) cls.newInstance();
0392: } catch (ClassNotFoundException e) {
0393: throw new QuercusModuleException(e);
0394: } catch (InstantiationException e) {
0395: throw new QuercusModuleException(e);
0396: } catch (IllegalAccessException e) {
0397: throw new QuercusModuleException(e);
0398: }
0399: }
0400: }
0401:
0402: /**
0403: * Unwrap connection if necessary.
0404: */
0405: public Connection getConnection(Connection conn) {
0406: return conn;
0407: }
0408:
0409: /*
0410: * Marks the connection for removal from the connection pool.
0411: */
0412: public void markForPoolRemoval(Connection conn) {
0413: return;
0414: }
0415:
0416: /**
0417: * Unwrap statement if necessary.
0418: */
0419: public java.sql.Statement getStatement(java.sql.Statement stmt) {
0420: return stmt;
0421: }
0422:
0423: /**
0424: * Sets the strict mode.
0425: */
0426: public void setStrict(boolean isStrict) {
0427: _isStrict = isStrict;
0428: }
0429:
0430: /**
0431: * Gets the strict mode.
0432: */
0433: public boolean isStrict() {
0434: return _isStrict;
0435: }
0436:
0437: public void setRequireSource(boolean isRequireSource) {
0438: _isRequireSource = isRequireSource;
0439: }
0440:
0441: /*
0442: * Returns whether the php source is required for compiled files.
0443: */
0444: public boolean isRequireSource() {
0445: return _isRequireSource;
0446: }
0447:
0448: /**
0449: * Adds a module
0450: */
0451: public void addModule(QuercusModule module) throws ConfigException {
0452: try {
0453: introspectPhpModuleClass(module.getClass());
0454: } catch (Exception e) {
0455: throw ConfigException.create(e);
0456: }
0457: }
0458:
0459: /**
0460: * Adds a java class
0461: */
0462: public void addJavaClass(String name, Class type)
0463: throws ConfigException {
0464: try {
0465: if (type.isAnnotationPresent(ClassImplementation.class))
0466: introspectJavaImplClass(name, type, null);
0467: else
0468: introspectJavaClass(name, type, null, null);
0469: } catch (Exception e) {
0470: throw ConfigException.create(e);
0471: }
0472: }
0473:
0474: /**
0475: * Adds a java class
0476: */
0477: public void addJavaClass(String phpName, String className) {
0478:
0479: Class type;
0480:
0481: try {
0482: type = Class.forName(className, false, _loader);
0483: } catch (ClassNotFoundException e) {
0484: throw new QuercusRuntimeException(L.l(
0485: "`{0}' not valid: {1}", className, e.toString()), e);
0486: }
0487:
0488: addJavaClass(phpName, type);
0489: }
0490:
0491: /**
0492: * Adds a impl class
0493: */
0494: public void addImplClass(String name, Class type)
0495: throws ConfigException {
0496: try {
0497: introspectJavaImplClass(name, type, null);
0498: } catch (Exception e) {
0499: throw ConfigException.create(e);
0500: }
0501: }
0502:
0503: /**
0504: * Adds a java class
0505: */
0506: public JavaClassDef getJavaClassDefinition(Class type,
0507: String className) {
0508: JavaClassDef def = _javaClassWrappers.get(className);
0509:
0510: if (def != null)
0511: return def;
0512:
0513: try {
0514: def = getModuleContext().getJavaClassDefinition(type,
0515: className);
0516:
0517: addJavaClassWrapper(className, def);
0518:
0519: // def.introspect(getModuleContext());
0520:
0521: return def;
0522: } catch (RuntimeException e) {
0523: throw e;
0524: } catch (Exception e) {
0525: throw new QuercusRuntimeException(e);
0526: }
0527: }
0528:
0529: /**
0530: * Adds a java class
0531: */
0532: public JavaClassDef getJavaClassDefinition(String className) {
0533: JavaClassDef def = _javaClassWrappers.get(className);
0534:
0535: if (def != null)
0536: return def;
0537:
0538: try {
0539: def = getModuleContext().getJavaClassDefinition(className);
0540:
0541: addJavaClassWrapper(className, def);
0542:
0543: // def.introspect(getModuleContext());
0544:
0545: return def;
0546: } catch (RuntimeException e) {
0547: throw e;
0548: } catch (Exception e) {
0549: throw new QuercusRuntimeException(e);
0550: }
0551: }
0552:
0553: protected void addJavaClassWrapper(String className,
0554: JavaClassDef def) {
0555: _javaClassWrappers.put(className, def);
0556: }
0557:
0558: /**
0559: * Finds the java class wrapper.
0560: */
0561: public ClassDef findJavaClassWrapper(String name) {
0562: ClassDef def = _javaClassWrappers.get(name);
0563:
0564: if (def != null)
0565: return def;
0566:
0567: return _lowerJavaClassWrappers.get(name.toLowerCase());
0568: }
0569:
0570: /**
0571: * Sets an ini file.
0572: */
0573: public void setIniFile(Path path) {
0574: // XXX: Not sure why this dependency would be useful
0575: // Environment.addDependency(new Depend(path));
0576:
0577: if (path.canRead()) {
0578: Env env = new Env(this );
0579:
0580: Value result = FileModule.parse_ini_file(env, path, false);
0581:
0582: if (result instanceof ArrayValue) {
0583: ArrayValue array = (ArrayValue) result;
0584:
0585: for (Map.Entry<Value, Value> entry : array.entrySet()) {
0586: setIni(entry.getKey().toString(), entry.getValue()
0587: .toString());
0588: }
0589: }
0590: }
0591: }
0592:
0593: /**
0594: * Returns the IniDefinitions for all ini that have been defined by modules.
0595: */
0596: public IniDefinitions getIniDefinitions() {
0597: return _iniDefinitions;
0598: }
0599:
0600: /**
0601: * Returns a map of the ini values that have been explicitly set.
0602: */
0603: public IdentityHashMap<String, Value> getIniMap(boolean create) {
0604: if (_iniMap == null && create)
0605: _iniMap = new IdentityHashMap<String, Value>();
0606:
0607: return _iniMap;
0608: }
0609:
0610: /**
0611: * Sets an ini value.
0612: */
0613: public void setIni(String name, StringValue value) {
0614: _iniDefinitions.get(name).set(this , value);
0615: }
0616:
0617: /**
0618: * Sets an ini value.
0619: */
0620: public void setIni(String name, String value) {
0621: _iniDefinitions.get(name).set(this , value);
0622: }
0623:
0624: /**
0625: * Returns an ini value.
0626: */
0627: public boolean getIniBoolean(String name) {
0628: return _iniDefinitions.get(name).getAsBoolean(this );
0629: }
0630:
0631: /**
0632: * Returns an ini value as a long.
0633: */
0634: public long getIniLong(String name) {
0635: return _iniDefinitions.get(name).getAsLongValue(this ).toLong();
0636: }
0637:
0638: /**
0639: * Sets a server env value.
0640: */
0641: public void setServerEnv(String name, String value) {
0642: setServerEnv(createString(name), createString(value));
0643: }
0644:
0645: /**
0646: * Sets a server env value.
0647: */
0648: public void setServerEnv(StringValue name, StringValue value) {
0649: _serverEnvMap.put(name, value);
0650: }
0651:
0652: /**
0653: * Gets a server env value.
0654: */
0655: public Value getServerEnv(StringValue name) {
0656: return _serverEnvMap.get(name);
0657: }
0658:
0659: /**
0660: * Returns the server env map.
0661: */
0662: public HashMap<Value, Value> getServerEnvMap() {
0663: return _serverEnvMap;
0664: }
0665:
0666: /**
0667: * Returns the relative path.
0668: */
0669: /*
0670: public String getClassName(Path path)
0671: {
0672: return _pageManager.getClassName(path);
0673: }
0674: */
0675:
0676: /**
0677: * Returns an include path.
0678: */
0679: public Path getIncludeCache(String include, String includePath,
0680: Path pwd, Path scriptPwd) {
0681: IncludeKey key = new IncludeKey(include, includePath, pwd,
0682: scriptPwd);
0683:
0684: Path path = _includeCache.get(key);
0685:
0686: return path;
0687: }
0688:
0689: /**
0690: * Adds an include path.
0691: */
0692: public void putIncludeCache(String include, String includePath,
0693: Path pwd, Path scriptPwd, Path path) {
0694: IncludeKey key = new IncludeKey(include, includePath, pwd,
0695: scriptPwd);
0696:
0697: _includeCache.put(key, path);
0698: }
0699:
0700: /**
0701: * Returns the definition cache hit count.
0702: */
0703: public long getDefCacheHitCount() {
0704: return _defCacheHitCount;
0705: }
0706:
0707: /**
0708: * Returns the definition cache miss count.
0709: */
0710: public long getDefCacheMissCount() {
0711: return _defCacheMissCount;
0712: }
0713:
0714: /**
0715: * Returns the definition state for an include.
0716: */
0717: /*
0718: public DefinitionState getDefinitionCache(DefinitionKey key)
0719: {
0720: SoftReference<DefinitionState> defStateRef = _defCache.get(key);
0721:
0722: if (defStateRef != null) {
0723: DefinitionState defState = defStateRef.get();
0724:
0725: if (defState != null) {
0726: _defCacheHitCount++;
0727:
0728: return defState.copyLazy();
0729: }
0730: }
0731:
0732: _defCacheMissCount++;
0733:
0734: return null;
0735: }
0736: */
0737:
0738: /**
0739: * Returns the definition state for an include.
0740: */
0741: /*
0742: public void putDefinitionCache(DefinitionKey key,
0743: DefinitionState defState)
0744: {
0745: _defCache.put(key, new SoftReference<DefinitionState>(defState.copy()));
0746: }
0747: */
0748:
0749: /**
0750: * Clears the definition cache.
0751: */
0752: public void clearDefinitionCache() {
0753: // _defCache.clear();
0754: }
0755:
0756: /**
0757: * Parses a quercus program.
0758: *
0759: * @param path the source file path
0760: * @return the parsed program
0761: * @throws IOException
0762: */
0763: public QuercusPage parse(Path path) throws IOException {
0764: return _pageManager.parse(path);
0765: }
0766:
0767: /**
0768: * Parses a quercus program.
0769: *
0770: * @param path the source file path
0771: * @return the parsed program
0772: * @throws IOException
0773: */
0774: public QuercusPage parse(Path path, String fileName, int line)
0775: throws IOException {
0776: return _pageManager.parse(path, fileName, line);
0777: }
0778:
0779: /**
0780: * Parses a quercus program.
0781: *
0782: * @param path the source file path
0783: * @return the parsed program
0784: * @throws IOException
0785: */
0786: public QuercusPage parse(ReadStream is) throws IOException {
0787: return new InterpretedPage(QuercusParser.parse(this , is));
0788: }
0789:
0790: /**
0791: * Parses a quercus string.
0792: *
0793: * @param code the source code
0794: * @return the parsed program
0795: * @throws IOException
0796: */
0797: public QuercusProgram parseCode(String code) throws IOException {
0798: QuercusProgram program = _evalCache.get(code);
0799:
0800: if (program == null) {
0801: program = QuercusParser.parseEval(this , code);
0802: _evalCache.put(code, program);
0803: }
0804:
0805: return program;
0806: }
0807:
0808: /**
0809: * Parses a quercus string.
0810: *
0811: * @param code the source code
0812: * @return the parsed program
0813: * @throws IOException
0814: */
0815: public QuercusProgram parseEvalExpr(String code) throws IOException {
0816: // XXX: possible conflict with parse eval because of the
0817: // return value changes
0818: QuercusProgram program = _evalCache.get(code);
0819:
0820: if (program == null) {
0821: program = QuercusParser.parseEvalExpr(this , code);
0822: _evalCache.put(code, program);
0823: }
0824:
0825: return program;
0826: }
0827:
0828: /**
0829: * Parses a function.
0830: *
0831: * @param args the arguments
0832: * @param code the source code
0833: * @return the parsed program
0834: * @throws IOException
0835: */
0836: public Value parseFunction(String args, String code)
0837: throws IOException {
0838: return QuercusParser.parseFunction(this , args, code);
0839: }
0840:
0841: /**
0842: * Returns the function with the given name.
0843: */
0844: public AbstractFunction findFunction(String name) {
0845: AbstractFunction fun = _funMap.get(name);
0846:
0847: if ((fun == null) && !isStrict())
0848: fun = _lowerFunMap.get(name.toLowerCase());
0849:
0850: return fun;
0851: }
0852:
0853: /**
0854: * Returns the function with the given name.
0855: */
0856: public AbstractFunction findFunctionImpl(String name) {
0857: AbstractFunction fun = _funMap.get(name);
0858:
0859: return fun;
0860: }
0861:
0862: /**
0863: * Returns the function with the given name.
0864: */
0865: public AbstractFunction findLowerFunctionImpl(String lowerName) {
0866: AbstractFunction fun = _lowerFunMap.get(lowerName);
0867:
0868: return fun;
0869: }
0870:
0871: /**
0872: * Returns an array of the defined functions.
0873: */
0874: public ArrayValue getDefinedFunctions() {
0875: ArrayValue internal = new ArrayValueImpl();
0876:
0877: for (String name : _funMap.keySet()) {
0878: internal.put(name);
0879: }
0880:
0881: return internal;
0882: }
0883:
0884: //
0885: // name to id mappings
0886: //
0887:
0888: /**
0889: * Returns the id for a function name.
0890: */
0891: public int getFunctionId(String name) {
0892: if (!isStrict())
0893: name = name.toLowerCase();
0894:
0895: synchronized (_functionNameMap) {
0896: int id = _functionNameMap.get(name);
0897:
0898: if (id < 0) {
0899: id = _functionNameMap.size();
0900:
0901: _functionNameMap.put(name, id);
0902:
0903: if (_functionMap.length <= id) {
0904: AbstractFunction[] functionMap = new AbstractFunction[id + 256];
0905: System.arraycopy(_functionMap, 0, functionMap, 0,
0906: _functionMap.length);
0907: _functionMap = functionMap;
0908: }
0909:
0910: _functionMap[id] = new UndefinedFunction(name);
0911: }
0912:
0913: return id;
0914: }
0915: }
0916:
0917: /**
0918: * Returns the id for a function name.
0919: */
0920: public int findFunctionId(String name) {
0921: if (!isStrict())
0922: name = name.toLowerCase();
0923:
0924: synchronized (_functionNameMap) {
0925: return _functionNameMap.get(name);
0926: }
0927: }
0928:
0929: /**
0930: * Returns the number of functions
0931: */
0932: public int getFunctionIdCount() {
0933: return _functionNameMap.size();
0934: }
0935:
0936: /**
0937: * Returns the undefined functions
0938: */
0939: public AbstractFunction[] getFunctionMap() {
0940: return _functionMap;
0941: }
0942:
0943: /**
0944: * Returns the id for a class name.
0945: */
0946: public int getClassId(String name) {
0947: name = name.toLowerCase();
0948:
0949: synchronized (_classNameMap) {
0950: int id = _classNameMap.get(name);
0951:
0952: if (id < 0) {
0953: id = _classNameMap.size();
0954:
0955: _classNameMap.put(name, id);
0956:
0957: if (_classMap.length <= id) {
0958: ClassDef[] classMap = new ClassDef[id + 256];
0959: System.arraycopy(_classMap, 0, classMap, 0,
0960: _classMap.length);
0961: _classMap = classMap;
0962: }
0963:
0964: // _classMap[id] = new UndefinedClass(name);
0965: }
0966:
0967: return id;
0968: }
0969: }
0970:
0971: /**
0972: * Returns the id for a function name.
0973: */
0974: public int findClassId(String name) {
0975: synchronized (_classNameMap) {
0976: return _classNameMap.get(name);
0977: }
0978: }
0979:
0980: /**
0981: * Returns the number of classes
0982: */
0983: public int getClassIdCount() {
0984: return _classNameMap.size();
0985: }
0986:
0987: /**
0988: * Returns the undefined functions
0989: */
0990: public ClassDef[] getClassDefMap() {
0991: return _classMap;
0992: }
0993:
0994: /**
0995: * Returns the id for a constant
0996: */
0997: public int getConstantId(String name) {
0998: name = name.toLowerCase();
0999:
1000: synchronized (_constantNameMap) {
1001: int id = _constantNameMap.get(name);
1002:
1003: if (id < 0) {
1004: id = _constantNameMap.size();
1005:
1006: _constantNameMap.put(name, id);
1007: }
1008:
1009: return id;
1010: }
1011: }
1012:
1013: /**
1014: * Returns the number of defined constants
1015: */
1016: public int getConstantIdSize() {
1017: return _constantNameMap.size();
1018: }
1019:
1020: /**
1021: * Returns true if the variable is a superglobal.
1022: */
1023: public static boolean isSuperGlobal(String name) {
1024: return _super Globals.contains(name);
1025: }
1026:
1027: /**
1028: * Returns the stdClass definition.
1029: */
1030: public QuercusClass getStdClass() {
1031: return _moduleContext.getStdClass();
1032: }
1033:
1034: /**
1035: * Returns the class with the given name.
1036: */
1037: public ClassDef findClass(String name) {
1038: return _moduleContext.findClass(name);
1039: /*
1040: ClassDef def = _staticClasses.get(name);
1041:
1042: if (def == null)
1043: def = _lowerStaticClasses.get(name.toLowerCase());
1044:
1045: return def;
1046: */
1047: }
1048:
1049: /**
1050: * Returns the class maps.
1051: */
1052: public HashMap<String, ClassDef> getClassMap() {
1053: /*
1054: return _staticClasses;
1055: */
1056: return _moduleContext.getClassMap();
1057: }
1058:
1059: /**
1060: * Returns the module with the given name.
1061: */
1062: public QuercusModule findModule(String name) {
1063: ModuleInfo moduleInfo = _modules.get(name);
1064:
1065: return moduleInfo == null ? null : moduleInfo.getModule();
1066: }
1067:
1068: /**
1069: * Returns a list of the modules that have some startup code to run.
1070: */
1071: public HashSet<ModuleStartupListener> getModuleStartupListeners() {
1072: return _moduleStartupListeners;
1073: }
1074:
1075: /**
1076: * Returns true if an extension is loaded.
1077: */
1078: public boolean isExtensionLoaded(String name) {
1079: return _extensionSet.contains(name);
1080: }
1081:
1082: /**
1083: * Returns true if an extension is loaded.
1084: */
1085: public HashSet<String> getLoadedExtensions() {
1086: return _extensionSet;
1087: }
1088:
1089: /**
1090: * Returns true if an extension is loaded.
1091: */
1092: public Value getExtensionFuncs(String name) {
1093: ArrayValue value = null;
1094:
1095: for (ModuleInfo moduleInfo : _modules.values()) {
1096: Set<String> extensionSet = moduleInfo.getLoadedExtensions();
1097:
1098: if (extensionSet.contains(name)) {
1099: for (String functionName : moduleInfo.getFunctions()
1100: .keySet()) {
1101: if (value == null)
1102: value = new ArrayValueImpl();
1103:
1104: value.put(functionName);
1105: }
1106: }
1107: }
1108:
1109: if (value != null)
1110: return value;
1111: else
1112: return BooleanValue.FALSE;
1113: }
1114:
1115: public Collection<ModuleInfo> getModules() {
1116: return _modules.values();
1117: }
1118:
1119: public HashMap<String, Value> getConstMap() {
1120: return _constMap;
1121: }
1122:
1123: /**
1124: * Interns a string.
1125: */
1126: public StringValue intern(String name) {
1127: synchronized (_internMap) {
1128: StringValue value = _internMap.get(name);
1129:
1130: if (value == null) {
1131: name = name.intern();
1132:
1133: value = new StringBuilderValue(name);
1134: _internMap.put(name, value);
1135: }
1136:
1137: return value;
1138: }
1139: }
1140:
1141: /**
1142: * Returns a named constant.
1143: */
1144: public Value getConstant(String name) {
1145: return _constMap.get(name);
1146: }
1147:
1148: public String createStaticName() {
1149: return ("s" + _staticId++).intern();
1150: }
1151:
1152: /**
1153: * Loads the session from the backing.
1154: */
1155: public SessionArrayValue loadSession(Env env, String sessionId) {
1156: long now = Alarm.getCurrentTime();
1157:
1158: SessionArrayValue session = _sessionManager.getSession(env,
1159: sessionId, now);
1160:
1161: if (session == null)
1162: session = _sessionManager
1163: .createSession(env, sessionId, now);
1164:
1165: return session;
1166: }
1167:
1168: /**
1169: * Saves the session to the backing.
1170: */
1171: public void saveSession(Env env, SessionArrayValue session) {
1172: _sessionManager.saveSession(env, session);
1173: }
1174:
1175: /**
1176: * Removes the session from the backing.
1177: */
1178: public void destroySession(String sessionId) {
1179: _sessionManager.removeSession(sessionId);
1180: }
1181:
1182: /**
1183: * Loads a special value
1184: */
1185: public Object getSpecial(String key) {
1186: return _specialMap.get(key);
1187: }
1188:
1189: /**
1190: * Saves a special value
1191: */
1192: public void setSpecial(String key, Object value) {
1193: _specialMap.put(key, value);
1194: }
1195:
1196: /**
1197: * Scans the classpath for META-INF/services/com.caucho.quercus.QuercusModule
1198: */
1199: private void initStaticFunctions() {
1200: Thread thread = Thread.currentThread();
1201: ClassLoader loader = thread.getContextClassLoader();
1202:
1203: try {
1204: String quercusModule = "META-INF/services/com.caucho.quercus.QuercusModule";
1205: Enumeration<URL> urls = loader.getResources(quercusModule);
1206:
1207: HashSet<URL> urlSet = new HashSet<URL>();
1208:
1209: // get rid of duplicate entries found by multiple classloaders
1210: while (urls.hasMoreElements()) {
1211: URL url = urls.nextElement();
1212:
1213: urlSet.add(url);
1214: }
1215:
1216: for (URL url : urlSet) {
1217: InputStream is = null;
1218: ReadStream rs = null;
1219: try {
1220: is = url.openStream();
1221:
1222: rs = new ReadStream(new VfsStream(is, null));
1223:
1224: parseServicesModule(rs);
1225: } catch (Throwable e) {
1226: log.log(Level.WARNING, e.toString(), e);
1227: } finally {
1228: if (rs != null)
1229: rs.close();
1230: if (is != null)
1231: is.close();
1232: }
1233: }
1234:
1235: } catch (Exception e) {
1236: log.log(Level.WARNING, e.toString(), e);
1237: }
1238: }
1239:
1240: /**
1241: * Parses the services file, looking for PHP services.
1242: */
1243: private void parseServicesModule(ReadStream in) throws IOException,
1244: ClassNotFoundException, IllegalAccessException,
1245: InstantiationException {
1246: ClassLoader loader = Thread.currentThread()
1247: .getContextClassLoader();
1248: String line;
1249:
1250: while ((line = in.readLine()) != null) {
1251: int p = line.indexOf('#');
1252:
1253: if (p >= 0)
1254: line = line.substring(0, p);
1255:
1256: line = line.trim();
1257:
1258: if (line.length() > 0) {
1259: String className = line;
1260:
1261: try {
1262: Class cl;
1263: try {
1264: cl = Class.forName(className, false, loader);
1265: } catch (ClassNotFoundException e) {
1266: throw new ClassNotFoundException(L.l(
1267: "'{0}' not valid {1}", className, e
1268: .toString()));
1269: }
1270:
1271: introspectPhpModuleClass(cl);
1272: } catch (Throwable e) {
1273: log.info("Failed loading " + className + "\n"
1274: + e.toString());
1275: log.log(Level.FINE, e.toString(), e);
1276: }
1277: }
1278: }
1279: }
1280:
1281: /**
1282: * Introspects the module class for functions.
1283: *
1284: * @param cl the class to introspect.
1285: */
1286: private void introspectPhpModuleClass(Class cl)
1287: throws IllegalAccessException, InstantiationException,
1288: ConfigException {
1289: log.finer("Quercus loading module " + cl.getName());
1290:
1291: QuercusModule module = (QuercusModule) cl.newInstance();
1292:
1293: ModuleContext context = getLocalContext();
1294:
1295: ModuleInfo info = context.addModule(
1296: module.getClass().getName(), module);
1297:
1298: _modules.put(info.getName(), info);
1299:
1300: if (info.getModule() instanceof ModuleStartupListener)
1301: _moduleStartupListeners.add((ModuleStartupListener) info
1302: .getModule());
1303:
1304: for (String ext : info.getLoadedExtensions())
1305: _extensionSet.add(ext);
1306:
1307: Map<String, Value> map = info.getConstMap();
1308:
1309: if (map != null)
1310: _constMap.putAll(map);
1311:
1312: _iniDefinitions.addAll(info.getIniDefinitions());
1313:
1314: for (Map.Entry<String, AbstractFunction> entry : info
1315: .getFunctions().entrySet()) {
1316: String funName = entry.getKey();
1317: AbstractFunction fun = entry.getValue();
1318:
1319: _funMap.put(funName, fun);
1320: _lowerFunMap.put(funName.toLowerCase(), fun);
1321:
1322: int id = getFunctionId(funName);
1323: _functionMap[id] = fun;
1324: }
1325: }
1326:
1327: public static Value objectToValue(Object obj) {
1328: if (obj == null)
1329: return NullValue.NULL;
1330: else if (Byte.class.equals(obj.getClass())
1331: || Short.class.equals(obj.getClass())
1332: || Integer.class.equals(obj.getClass())
1333: || Long.class.equals(obj.getClass())) {
1334: return LongValue.create(((Number) obj).longValue());
1335: } else if (Float.class.equals(obj.getClass())
1336: || Double.class.equals(obj.getClass())) {
1337: return DoubleValue.create(((Number) obj).doubleValue());
1338: } else if (String.class.equals(obj.getClass())) {
1339: // XXX: i18n
1340: return new StringBuilderValue((String) obj);
1341: } else {
1342: // XXX: unknown types, e.g. Character?
1343:
1344: return null;
1345: }
1346: }
1347:
1348: /**
1349: * Scans the classpath for META-INF/services/com.caucho.quercus.QuercusClass
1350: */
1351: private void initStaticClassServices() {
1352: Thread thread = Thread.currentThread();
1353: ClassLoader loader = thread.getContextClassLoader();
1354:
1355: try {
1356: String quercusModule = "META-INF/services/com.caucho.quercus.QuercusClass";
1357: Enumeration<URL> urls = loader.getResources(quercusModule);
1358:
1359: while (urls.hasMoreElements()) {
1360: URL url = urls.nextElement();
1361:
1362: InputStream is = null;
1363: ReadStream rs = null;
1364: try {
1365: is = url.openStream();
1366:
1367: rs = new ReadStream(new VfsStream(is, null));
1368:
1369: parseClassServicesModule(rs);
1370: } catch (Throwable e) {
1371: log.log(Level.WARNING, e.toString(), e);
1372: } finally {
1373: if (rs != null)
1374: rs.close();
1375: if (is != null)
1376: is.close();
1377: }
1378: }
1379:
1380: } catch (Exception e) {
1381: log.log(Level.WARNING, e.toString(), e);
1382: }
1383: }
1384:
1385: /**
1386: * Parses the services file, looking for PHP services.
1387: */
1388: private void parseClassServicesModule(ReadStream in)
1389: throws IOException, ClassNotFoundException,
1390: IllegalAccessException, InstantiationException,
1391: ConfigException, NoSuchMethodException,
1392: InvocationTargetException {
1393: ClassLoader loader = Thread.currentThread()
1394: .getContextClassLoader();
1395: String line;
1396:
1397: while ((line = in.readLine()) != null) {
1398: int p = line.indexOf('#');
1399:
1400: if (p >= 0)
1401: line = line.substring(0, p);
1402:
1403: line = line.trim();
1404:
1405: if (line.length() == 0)
1406: continue;
1407:
1408: String[] args = line.split(" ");
1409:
1410: String className = args[0];
1411:
1412: Class cl;
1413:
1414: try {
1415: cl = Class.forName(className, false, loader);
1416:
1417: String phpClassName = null;
1418: String extension = null;
1419: String definedBy = null;
1420:
1421: for (int i = 1; i < args.length; i++) {
1422: if ("as".equals(args[i])) {
1423: i++;
1424: if (i >= args.length)
1425: throw new IOException(
1426: L
1427: .l(
1428: "expecting Quercus class name after '{0}' in definition for class {1}",
1429: "as", className));
1430:
1431: phpClassName = args[i];
1432: } else if ("provides".equals(args[i])) {
1433: i++;
1434: if (i >= args.length)
1435: throw new IOException(
1436: L
1437: .l(
1438: "expecting name of extension after '{0}' in definition for class {1}",
1439: "extension",
1440: className));
1441:
1442: extension = args[i];
1443: } else if ("definedBy".equals(args[i])) {
1444: i++;
1445: if (i >= args.length)
1446: throw new IOException(
1447: L
1448: .l(
1449: "expecting name of class implementing JavaClassDef after '{0}' in definition for class {1}",
1450: "definedBy",
1451: className));
1452:
1453: definedBy = args[i];
1454: } else {
1455: throw new IOException(
1456: L
1457: .l(
1458: "unknown token '{0}' in definition for class {1} ",
1459: args[i], className));
1460: }
1461: }
1462:
1463: if (phpClassName == null)
1464: phpClassName = className.substring(className
1465: .lastIndexOf('.') + 1);
1466:
1467: Class javaClassDefClass;
1468:
1469: if (definedBy != null) {
1470: javaClassDefClass = Class.forName(definedBy, false,
1471: loader);
1472: } else
1473: javaClassDefClass = null;
1474:
1475: introspectJavaClass(phpClassName, cl, extension,
1476: javaClassDefClass);
1477: } catch (Exception e) {
1478: log.info("Failed loading " + className + "\n"
1479: + e.toString());
1480: log.log(Level.FINE, e.toString(), e);
1481: }
1482: }
1483: }
1484:
1485: /**
1486: * Introspects the module class for functions.
1487: *
1488: * @param name the php class name
1489: * @param type the class to introspect.
1490: * @param extension the extension provided by the class, or null
1491: * @param javaClassDefClass
1492: */
1493: private void introspectJavaClass(String name, Class type,
1494: String extension, Class javaClassDefClass)
1495: throws IllegalAccessException, InstantiationException,
1496: ConfigException, NoSuchMethodException,
1497: InvocationTargetException {
1498: ModuleContext context = getLocalContext();
1499:
1500: /*
1501: if (type.isAnnotationPresent(ClassImplementation.class)) {
1502: if (javaClassDefClass != null)
1503: throw new UnimplementedException();
1504:
1505: ClassDef def = context.addClassImpl(name, type, extension);
1506: }
1507: else {
1508: */
1509: JavaClassDef def = context.addClass(name, type, extension,
1510: javaClassDefClass);
1511:
1512: _javaClassWrappers.put(name, def);
1513: _lowerJavaClassWrappers.put(name.toLowerCase(), def);
1514:
1515: /*
1516: _staticClasses.put(name, def);
1517: _lowerStaticClasses.put(name.toLowerCase(), def);
1518: */
1519: // }
1520: if (extension != null)
1521: _extensionSet.add(extension);
1522: }
1523:
1524: /**
1525: * Introspects the module class for functions.
1526: *
1527: * @param name the php class name
1528: * @param type the class to introspect.
1529: * @param extension the extension provided by the class, or null
1530: */
1531: private void introspectJavaImplClass(String name, Class type,
1532: String extension) throws IllegalAccessException,
1533: InstantiationException, ConfigException {
1534: if (log.isLoggable(Level.FINEST)) {
1535: if (extension == null)
1536: log.finest(L.l(
1537: "Quercus loading class {0} with type {1}",
1538: name, type.getName()));
1539: else
1540: log
1541: .finest(L
1542: .l(
1543: "Quercus loading class {0} with type {1} providing extension {2}",
1544: name, type.getName(), extension));
1545: }
1546:
1547: ModuleContext context = getLocalContext();
1548:
1549: // JavaImplClassDef def = context.addClassImpl(name, type, extension);
1550: try {
1551: JavaClassDef def = context.addClass(name, type, extension,
1552: null);
1553:
1554: /*
1555: _staticClasses.put(name, def);
1556: _lowerStaticClasses.put(name.toLowerCase(), def);
1557: */
1558: } catch (RuntimeException e) {
1559: throw e;
1560: } catch (Exception e) {
1561: throw ConfigException.create(e);
1562: }
1563: }
1564:
1565: /**
1566: * Scans the classpath for META-INF/services/com.caucho.quercus.QuercusClass
1567: */
1568: private void initStaticClasses() {
1569: /*
1570: _stdClassDef = new InterpretedClassDef("stdClass", null, new String[0]);
1571: _stdClass = new QuercusClass(_stdClassDef, null);
1572:
1573: _staticClasses.put(_stdClass.getName(), _stdClassDef);
1574: _lowerStaticClasses.put(_stdClass.getName().toLowerCase(), _stdClassDef);
1575:
1576: InterpretedClassDef exn = new InterpretedClassDef("Exception",
1577: null,
1578: new String[0]);
1579:
1580: try {
1581: exn.setConstructor(new StaticFunction(_moduleContext,
1582: null,
1583: Quercus.class.getMethod("exnConstructor", new Class[] { Env.class, Value.class, String.class })));
1584: } catch (Exception e) {
1585: throw new QuercusException(e);
1586: }
1587:
1588: // QuercusClass exnCl = new QuercusClass(exn, null);
1589:
1590: _staticClasses.put(exn.getName(), exn);
1591: _lowerStaticClasses.put(exn.getName().toLowerCase(), exn);
1592: */
1593: }
1594:
1595: public void close() {
1596: _pageManager.close();
1597: }
1598:
1599: public static Value exnConstructor(Env env, Value obj, String msg) {
1600: if (obj != null) {
1601: obj.putField(env, "message", new UnicodeValueImpl(msg));
1602: }
1603:
1604: return NullValue.NULL;
1605:
1606: }
1607:
1608: static class IncludeKey {
1609: private final String _include;
1610: private final String _includePath;
1611: private final Path _pwd;
1612: private final Path _scriptPwd;
1613:
1614: IncludeKey(String include, String includePath, Path pwd,
1615: Path scriptPwd) {
1616: _include = include;
1617: _includePath = includePath;
1618: _pwd = pwd;
1619: _scriptPwd = scriptPwd;
1620: }
1621:
1622: public int hashCode() {
1623: int hash = 37;
1624:
1625: hash = 65537 * hash + _include.hashCode();
1626: hash = 65537 * hash + _includePath.hashCode();
1627: hash = 65537 * hash + _pwd.hashCode();
1628: hash = 65537 * hash + _scriptPwd.hashCode();
1629:
1630: return hash;
1631: }
1632:
1633: public boolean equals(Object o) {
1634: if (!(o instanceof IncludeKey))
1635: return false;
1636:
1637: IncludeKey key = (IncludeKey) o;
1638:
1639: return (_include.equals(key._include)
1640: && _includePath.equals(key._includePath)
1641: && _pwd.equals(key._pwd) && _scriptPwd
1642: .equals(key._scriptPwd));
1643: }
1644: }
1645:
1646: static {
1647: _super Globals.add("GLOBALS");
1648: _super Globals.add("_COOKIE");
1649: _super Globals.add("_ENV");
1650: _super Globals.add("_FILES");
1651: _super Globals.add("_GET");
1652: _super Globals.add("_POST");
1653: _super Globals.add("_SERVER");
1654: _super Globals.add("_SESSION");
1655: _super Globals.add("_REQUEST");
1656: }
1657:
1658: public static final IniDefinition INI_INCLUDE_PATH = _ini.add(
1659: "include_path", ".", IniDefinition.PHP_INI_ALL);
1660: public static final IniDefinition INI_REGISTER_LONG_ARRAYS = _ini
1661: .add("register_long_arrays", true,
1662: IniDefinition.PHP_INI_PERDIR);
1663: public static final IniDefinition INI_UNICODE_SEMANTICS = _ini.add(
1664: "unicode.semantics", false, IniDefinition.PHP_INI_SYSTEM);
1665: public static final IniDefinition INI_UNICODE_FALLBACK_ENCODING = _ini
1666: .add("unicode.fallback_encoding", "utf-8",
1667: IniDefinition.PHP_INI_ALL);
1668: public static final IniDefinition INI_UNICODE_FROM_ERROR_MODE = _ini
1669: .add("unicode.from_error_mode", "2",
1670: IniDefinition.PHP_INI_ALL);
1671: public static final IniDefinition INI_UNICODE_FROM_ERROR_SUBST_CHAR = _ini
1672: .add("unicode.from_error_subst_char", "3f",
1673: IniDefinition.PHP_INI_ALL);
1674: public static final IniDefinition INI_UNICODE_HTTP_INPUT_ENCODING = _ini
1675: .add("unicode.http_input_encoding", null,
1676: IniDefinition.PHP_INI_ALL);
1677: public static final IniDefinition INI_UNICODE_OUTPUT_ENCODING = _ini
1678: .add("unicode.output_encoding", null,
1679: IniDefinition.PHP_INI_ALL);
1680: public static final IniDefinition INI_UNICODE_RUNTIME_ENCODING = _ini
1681: .add("unicode.runtime_encoding", null,
1682: IniDefinition.PHP_INI_ALL);
1683: public static final IniDefinition INI_UNICODE_SCRIPT_ENCODING = _ini
1684: .add("unicode.script_encoding", null,
1685: IniDefinition.PHP_INI_ALL);
1686:
1687: }
|