/******************************************************************************* * Copyright (c) 2009 IBM Corporation and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * IBM Corporation - initial API and implementation * Zend Technologies *******************************************************************************/ package org.eclipse.php.internal.debug.core.phpIni; import java.io.*; import java.util.ArrayList; import java.util.Calendar; import java.util.List; import org.eclipse.core.filesystem.EFS; import org.eclipse.core.internal.filesystem.local.LocalFile; import org.eclipse.core.resources.*; import org.eclipse.core.runtime.IPath; import org.eclipse.core.runtime.NullProgressMonitor; import org.eclipse.core.runtime.Platform; import org.eclipse.dltk.core.*; import org.eclipse.dltk.core.environment.EnvironmentPathUtils; import org.eclipse.php.internal.core.includepath.IncludePath; import org.eclipse.php.internal.core.util.PHPSearchEngine; import org.eclipse.php.internal.debug.core.Logger; import org.eclipse.php.internal.debug.core.PHPDebugPlugin; @SuppressWarnings("restriction") public class PHPINIUtil { private static final String PHP_INI_FILE = "php.ini"; //$NON-NLS-1$ private static final String INCLUDE_PATH = "include_path"; //$NON-NLS-1$ private static final String ZEND_EXTENSION = "zend_extension"; //$NON-NLS-1$ private static final String ZEND_EXTENSION_TS = "zend_extension_ts"; //$NON-NLS-1$ private static final String MEMORY_LIMIT = "memory_limit"; //$NON-NLS-1$ private static final String DATE_TIMEZONE = "date.timezone"; //$NON-NLS-1$ private static void modifyIncludePath(File phpIniFile, String[] includePath) { try { INIFileModifier m = new INIFileModifier(phpIniFile); m.removeAllEntries(INCLUDE_PATH); StringBuilder valueBuf = new StringBuilder("."); //$NON-NLS-1$ for (String path : includePath) { valueBuf.append(File.pathSeparatorChar).append(path); } m.addEntry(INCLUDE_PATH, valueBuf.toString()); m.close(); } catch (IOException e) { PHPDebugPlugin.log(e); } } private static void modifyDebuggerExtensionPath(File phpIniFile, String extensionPath) { try { INIFileModifier m = new INIFileModifier(phpIniFile); if (Platform.OS_WIN32.equals(Platform.getOS())) { if (m.removeAllEntries(ZEND_EXTENSION_TS, ".*\\.\\\\ZendDebugger\\.dll.*")) { //$NON-NLS-1$ m.addEntry(ZEND_EXTENSION_TS, extensionPath); } } else { if (m.removeAllEntries(ZEND_EXTENSION, ".*\\./ZendDebugger\\.so.*")) { //$NON-NLS-1$ m.addEntry(ZEND_EXTENSION, extensionPath); } } m.close(); } catch (IOException e) { PHPDebugPlugin.log(e); } } private static void modifyExtensionDir(File phpIniFile, String extensionPath) { try { INIFileModifier m = new INIFileModifier(phpIniFile); m.addEntry("extension_dir", extensionPath, true); //$NON-NLS-1$ m.close(); } catch (IOException e) { PHPDebugPlugin.log(e); } } /** * Adds/Creates the php ini file according to the project include path * settings. * * @param phpIniFile * null or already existing ini file * @param project * @return the ini file */ public static File createPhpIniByProject(File phpIniFile, IProject project) { File tempIniFile = createTemporaryPHPINIFile(phpIniFile); // Modify include path: if (project != null) { IncludePath[] path = PHPSearchEngine.buildIncludePath(project); List<String> includePath = new ArrayList<String>(path.length); for (IncludePath pathObject : path) { if (pathObject.isBuildpath()) { IBuildpathEntry entry = (IBuildpathEntry) pathObject.getEntry(); if (entry.getEntryKind() == IBuildpathEntry.BPE_VARIABLE) { IPath entryPath = DLTKCore.getResolvedVariablePath(entry.getPath()); includePath.add(entryPath.toFile().getAbsolutePath()); } else if (entry.getEntryKind() == IBuildpathEntry.BPE_PROJECT || entry.getEntryKind() == IBuildpathEntry.BPE_SOURCE || entry.getEntryKind() == IBuildpathEntry.BPE_LIBRARY) { if (entry.getEntryKind() == IBuildpathEntry.BPE_PROJECT) { IWorkspaceRoot root = ResourcesPlugin.getWorkspace().getRoot(); IResource resource = root.findMember(entry.getPath()); IModelElement scriptProject = DLTKCore.create(resource); if (scriptProject instanceof IScriptProject) { try { IProjectFragment[] projectFragments = ((IScriptProject) scriptProject) .getProjectFragments(); for (IProjectFragment projectFragment : projectFragments) { if (projectFragment.getResource() instanceof IFolder || projectFragment.getResource() instanceof IProject) addIncludePath(includePath, projectFragment.getPath()); } } catch (ModelException e) { } } } else { addIncludePath(includePath, entry.getPath()); } } else if (entry.getEntryKind() == IBuildpathEntry.BPE_CONTAINER) { try { // Retries the local paths from the container final IScriptProject scriptProject = DLTKCore.create(project); final IBuildpathContainer buildpathContainer = DLTKCore .getBuildpathContainer(entry.getPath(), scriptProject); if (buildpathContainer != null) { final IBuildpathEntry[] buildpathEntries = buildpathContainer.getBuildpathEntries(); if (buildpathEntries != null) { for (IBuildpathEntry iBuildpathEntry : buildpathEntries) { final IPath localPath = EnvironmentPathUtils .getLocalPath(iBuildpathEntry.getPath()); includePath.add(localPath.toOSString()); } } } } catch (ModelException e) { Logger.logException(e); } } } else if (pathObject.getEntry() instanceof IContainer) { IContainer container = (IContainer) pathObject.getEntry(); IPath location = container.getLocation(); if (location != null) { includePath.add(location.toOSString()); } } } modifyIncludePath(tempIniFile, includePath.toArray(new String[includePath.size()])); } return tempIniFile; } private static void addIncludePath(List<String> includePath, IPath path) { IPath entryPath = EnvironmentPathUtils.getLocalPath(path); IResource resource = ResourcesPlugin.getWorkspace().getRoot().findMember(entryPath); if (resource != null) { IPath location = resource.getLocation(); if (location != null) { includePath.add(location.toOSString()); } } else { includePath.add(entryPath.toOSString()); } } /** * Make some preparations before PHP CLI launch session: * <ul> * <li>Adds include path * <li>Modifies Zend Debugger path in the PHP configuration file * </ul> * * @param phpIniFile * PHP configuration file instance * @param phpExePath * Path to the PHP executable * @param project * Current project * @return created temporary PHP configuration file */ public static File prepareBeforeLaunch(File phpIniFile, String phpExePath, IProject project) { File tempIniFile = createTemporaryPHPINIFile(phpIniFile); tempIniFile = createPhpIniByProject(phpIniFile, project); // Modify Zend Debugger extension entry: if (phpIniFile != null) { File debuggerFile = new File(phpIniFile.getParentFile(), Platform.OS_WIN32.equals(Platform.getOS()) ? "ZendDebugger.dll" : "ZendDebugger.so"); //$NON-NLS-1$ //$NON-NLS-2$ if (debuggerFile.exists()) { modifyDebuggerExtensionPath(tempIniFile, debuggerFile.getAbsolutePath()); } modifyExtensionDir(tempIniFile, new File(debuggerFile.getParentFile(), "ext") //$NON-NLS-1$ .getAbsolutePath()); } if (PHPDebugPlugin.DEBUG) { System.out.println("\nPHP.ini contents:\n---------------------"); //$NON-NLS-1$ try { BufferedReader r = new BufferedReader(new FileReader(tempIniFile)); String line; while ((line = r.readLine()) != null) { System.out.println(line); } r.close(); System.out.println(); } catch (IOException e) { } } return tempIniFile; } /** * Creates temporary PHP configuration file and returns its instance of * <code>null</code> in case of error. This file will be removed when the * program exits. * * @return temporary PHP configuration file instance */ public static File createTemporaryPHPINIFile() { return createTemporaryPHPINIFile(null); } /** * Creates temporary PHP configuration file and returns its instance of * <code>null</code> in case of error. This file will be removed when the * program exits. * * @param originalPHPIniFile * If specified - its contents will be copied to the temporary * file * @return temporary PHP configuration file instance */ public static File createTemporaryPHPINIFile(File originalPHPIniFile) { File phpIniFile = null; try { // Create temporary directory: File tempDir = new File(System.getProperty("java.io.tmpdir"), "php-ini"); //$NON-NLS-1$ //$NON-NLS-2$ if (!tempDir.exists()) { tempDir.mkdir(); tempDir.deleteOnExit(); } tempDir = File.createTempFile("session", null, tempDir); //$NON-NLS-1$ tempDir.delete(); // delete temp file tempDir.mkdir(); tempDir.deleteOnExit(); // Create empty configuration file: phpIniFile = new File(tempDir, PHP_INI_FILE); phpIniFile.createNewFile(); phpIniFile.deleteOnExit(); if (originalPHPIniFile != null && originalPHPIniFile.exists()) { new LocalFile(originalPHPIniFile).copy(new LocalFile(phpIniFile), EFS.OVERWRITE, new NullProgressMonitor()); } appendDefaultPHPIniContent(phpIniFile); } catch (Exception e) { PHPDebugPlugin.log(e); } return phpIniFile; } private static void appendDefaultPHPIniContent(File phpIniFile) throws IOException { try { INIFileModifier m = new INIFileModifier(phpIniFile); if (!m.hasEntry(MEMORY_LIMIT)) { m.addEntry(MEMORY_LIMIT, "256M"); //$NON-NLS-1$ } if (!m.hasEntry(DATE_TIMEZONE)) { m.addEntry(DATE_TIMEZONE, Calendar.getInstance().getTimeZone().getID()); } m.close(); } catch (IOException e) { PHPDebugPlugin.log(e); } } /** * Locate and return a PHP configuration file path for the given PHP * executable. The locating is done by trying to return a PHP configuration * file that is located next to the executable. The return value can be null * in case it fails to locate a valid file. * * @param phpExe * The PHP executable path. * @return A PHP configuration file path, or <code>null</code> if it fails. */ public static File findPHPIni(String phpExe) { File phpExeFile = new File(phpExe); File phpIniFile = new File(phpExeFile.getParentFile(), PHP_INI_FILE); if (!phpIniFile.exists() || !phpIniFile.canRead()) { // Try to detect via library: try { Process p = Runtime.getRuntime().exec(new String[] { phpExeFile.getAbsolutePath(), "-i" }); //$NON-NLS-1$ BufferedReader r = new BufferedReader(new InputStreamReader(p.getInputStream())); String l; while ((l = r.readLine()) != null) { int i = l.indexOf(" => "); //$NON-NLS-1$ if (i > 0) { String key = l.substring(0, i); String value = l.substring(i + 4); if ("Loaded Configuration File".equals(key)) { //$NON-NLS-1$ phpIniFile = new File(value); break; } } } r.close(); } catch (IOException e) { } } if (phpIniFile.exists() && phpIniFile.canRead()) { return phpIniFile; } return null; } }