3 * <tasks:postinstallscript>
9 * @author Greg Beaver <cellog@php.net>
10 * @copyright 1997-2009 The Authors
11 * @license http://opensource.org/licenses/bsd-license.php New BSD License
12 * @version CVS: $Id: Postinstallscript.php 313023 2011-07-06 19:17:11Z dufuz $
13 * @link http://pear.php.net/package/PEAR
14 * @since File available since Release 1.4.0a1
19 require_once 'PEAR/Task/Common.php';
21 * Implements the postinstallscript file task.
23 * Note that post-install scripts are handled separately from installation, by the
24 * "pear run-scripts" command
27 * @author Greg Beaver <cellog@php.net>
28 * @copyright 1997-2009 The Authors
29 * @license http://opensource.org/licenses/bsd-license.php New BSD License
30 * @version Release: 1.9.4
31 * @link http://pear.php.net/package/PEAR
32 * @since Class available since Release 1.4.0a1
34 class PEAR_Task_Postinstallscript extends PEAR_Task_Common
42 * @var PEAR_PackageFile_v2
46 var $phase = PEAR_TASK_INSTALL;
49 * Validate the raw xml at parsing-time.
51 * This also attempts to validate the script to make sure it meets the criteria
52 * for a post-install script
53 * @param PEAR_PackageFile_v2
54 * @param array The XML contents of the <postinstallscript> tag
56 * @param array the entire parsed <file> tag
59 function validateXml($pkg, $xml, $config, $fileXml)
61 if ($fileXml['role'] != 'php') {
62 return array(PEAR_TASK_ERROR_INVALID, 'Post-install script "' .
63 $fileXml['name'] . '" must be role="php"');
65 PEAR::pushErrorHandling(PEAR_ERROR_RETURN);
66 $file = $pkg->getFileContents($fileXml['name']);
67 if (PEAR::isError($file)) {
68 PEAR::popErrorHandling();
69 return array(PEAR_TASK_ERROR_INVALID, 'Post-install script "' .
70 $fileXml['name'] . '" is not valid: ' .
72 } elseif ($file === null) {
73 return array(PEAR_TASK_ERROR_INVALID, 'Post-install script "' .
74 $fileXml['name'] . '" could not be retrieved for processing!');
76 $analysis = $pkg->analyzeSourceCode($file, true);
78 PEAR::popErrorHandling();
80 foreach ($pkg->getValidationWarnings() as $warn) {
81 $warnings .= $warn['message'] . "\n";
83 return array(PEAR_TASK_ERROR_INVALID, 'Analysis of post-install script "' .
84 $fileXml['name'] . '" failed: ' . $warnings);
86 if (count($analysis['declared_classes']) != 1) {
87 PEAR::popErrorHandling();
88 return array(PEAR_TASK_ERROR_INVALID, 'Post-install script "' .
89 $fileXml['name'] . '" must declare exactly 1 class');
91 $class = $analysis['declared_classes'][0];
92 if ($class != str_replace(array('/', '.php'), array('_', ''),
93 $fileXml['name']) . '_postinstall') {
94 PEAR::popErrorHandling();
95 return array(PEAR_TASK_ERROR_INVALID, 'Post-install script "' .
96 $fileXml['name'] . '" class "' . $class . '" must be named "' .
97 str_replace(array('/', '.php'), array('_', ''),
98 $fileXml['name']) . '_postinstall"');
100 if (!isset($analysis['declared_methods'][$class])) {
101 PEAR::popErrorHandling();
102 return array(PEAR_TASK_ERROR_INVALID, 'Post-install script "' .
103 $fileXml['name'] . '" must declare methods init() and run()');
105 $methods = array('init' => 0, 'run' => 1);
106 foreach ($analysis['declared_methods'][$class] as $method) {
107 if (isset($methods[$method])) {
108 unset($methods[$method]);
111 if (count($methods)) {
112 PEAR::popErrorHandling();
113 return array(PEAR_TASK_ERROR_INVALID, 'Post-install script "' .
114 $fileXml['name'] . '" must declare methods init() and run()');
117 PEAR::popErrorHandling();
118 $definedparams = array();
119 $tasksNamespace = $pkg->getTasksNs() . ':';
120 if (!isset($xml[$tasksNamespace . 'paramgroup']) && isset($xml['paramgroup'])) {
121 // in order to support the older betas, which did not expect internal tags
122 // to also use the namespace
123 $tasksNamespace = '';
125 if (isset($xml[$tasksNamespace . 'paramgroup'])) {
126 $params = $xml[$tasksNamespace . 'paramgroup'];
127 if (!is_array($params) || !isset($params[0])) {
128 $params = array($params);
130 foreach ($params as $param) {
131 if (!isset($param[$tasksNamespace . 'id'])) {
132 return array(PEAR_TASK_ERROR_INVALID, 'Post-install script "' .
133 $fileXml['name'] . '" <paramgroup> must have ' .
134 'an ' . $tasksNamespace . 'id> tag');
136 if (isset($param[$tasksNamespace . 'name'])) {
137 if (!in_array($param[$tasksNamespace . 'name'], $definedparams)) {
138 return array(PEAR_TASK_ERROR_INVALID, 'Post-install script "' .
139 $fileXml['name'] . '" ' . $tasksNamespace .
140 'paramgroup> id "' . $param[$tasksNamespace . 'id'] .
141 '" parameter "' . $param[$tasksNamespace . 'name'] .
142 '" has not been previously defined');
144 if (!isset($param[$tasksNamespace . 'conditiontype'])) {
145 return array(PEAR_TASK_ERROR_INVALID, 'Post-install script "' .
146 $fileXml['name'] . '" ' . $tasksNamespace .
147 'paramgroup> id "' . $param[$tasksNamespace . 'id'] .
148 '" must have a ' . $tasksNamespace .
149 'conditiontype> tag containing either "=", ' .
150 '"!=", or "preg_match"');
152 if (!in_array($param[$tasksNamespace . 'conditiontype'],
153 array('=', '!=', 'preg_match'))) {
154 return array(PEAR_TASK_ERROR_INVALID, 'Post-install script "' .
155 $fileXml['name'] . '" ' . $tasksNamespace .
156 'paramgroup> id "' . $param[$tasksNamespace . 'id'] .
157 '" must have a ' . $tasksNamespace .
158 'conditiontype> tag containing either "=", ' .
159 '"!=", or "preg_match"');
161 if (!isset($param[$tasksNamespace . 'value'])) {
162 return array(PEAR_TASK_ERROR_INVALID, 'Post-install script "' .
163 $fileXml['name'] . '" ' . $tasksNamespace .
164 'paramgroup> id "' . $param[$tasksNamespace . 'id'] .
165 '" must have a ' . $tasksNamespace .
166 'value> tag containing expected parameter value');
169 if (isset($param[$tasksNamespace . 'instructions'])) {
170 if (!is_string($param[$tasksNamespace . 'instructions'])) {
171 return array(PEAR_TASK_ERROR_INVALID, 'Post-install script "' .
172 $fileXml['name'] . '" ' . $tasksNamespace .
173 'paramgroup> id "' . $param[$tasksNamespace . 'id'] .
174 '" ' . $tasksNamespace . 'instructions> must be simple text');
177 if (!isset($param[$tasksNamespace . 'param'])) {
178 continue; // <param> is no longer required
180 $subparams = $param[$tasksNamespace . 'param'];
181 if (!is_array($subparams) || !isset($subparams[0])) {
182 $subparams = array($subparams);
184 foreach ($subparams as $subparam) {
185 if (!isset($subparam[$tasksNamespace . 'name'])) {
186 return array(PEAR_TASK_ERROR_INVALID, 'Post-install script "' .
187 $fileXml['name'] . '" parameter for ' .
188 $tasksNamespace . 'paramgroup> id "' .
189 $param[$tasksNamespace . 'id'] . '" must have ' .
190 'a ' . $tasksNamespace . 'name> tag');
192 if (!preg_match('/[a-zA-Z0-9]+/',
193 $subparam[$tasksNamespace . 'name'])) {
194 return array(PEAR_TASK_ERROR_INVALID, 'Post-install script "' .
195 $fileXml['name'] . '" parameter "' .
196 $subparam[$tasksNamespace . 'name'] .
197 '" for ' . $tasksNamespace . 'paramgroup> id "' .
198 $param[$tasksNamespace . 'id'] .
199 '" is not a valid name. Must contain only alphanumeric characters');
201 if (!isset($subparam[$tasksNamespace . 'prompt'])) {
202 return array(PEAR_TASK_ERROR_INVALID, 'Post-install script "' .
203 $fileXml['name'] . '" parameter "' .
204 $subparam[$tasksNamespace . 'name'] .
205 '" for ' . $tasksNamespace . 'paramgroup> id "' .
206 $param[$tasksNamespace . 'id'] .
207 '" must have a ' . $tasksNamespace . 'prompt> tag');
209 if (!isset($subparam[$tasksNamespace . 'type'])) {
210 return array(PEAR_TASK_ERROR_INVALID, 'Post-install script "' .
211 $fileXml['name'] . '" parameter "' .
212 $subparam[$tasksNamespace . 'name'] .
213 '" for ' . $tasksNamespace . 'paramgroup> id "' .
214 $param[$tasksNamespace . 'id'] .
215 '" must have a ' . $tasksNamespace . 'type> tag');
217 $definedparams[] = $param[$tasksNamespace . 'id'] . '::' .
218 $subparam[$tasksNamespace . 'name'];
226 * Initialize a task instance with the parameters
227 * @param array raw, parsed xml
228 * @param array attributes from the <file> tag containing this task
229 * @param string|null last installed version of this package, if any (useful for upgrades)
231 function init($xml, $fileattribs, $lastversion)
233 $this->_class = str_replace('/', '_', $fileattribs['name']);
234 $this->_filename = $fileattribs['name'];
235 $this->_class = str_replace ('.php', '', $this->_class) . '_postinstall';
236 $this->_params = $xml;
237 $this->_lastversion = $lastversion;
241 * Strip the tasks: namespace from internal params
245 function _stripNamespace($params = null)
247 if ($params === null) {
249 if (!is_array($this->_params)) {
252 foreach ($this->_params as $i => $param) {
253 if (is_array($param)) {
254 $param = $this->_stripNamespace($param);
256 $params[str_replace($this->_pkg->getTasksNs() . ':', '', $i)] = $param;
258 $this->_params = $params;
260 $newparams = array();
261 foreach ($params as $i => $param) {
262 if (is_array($param)) {
263 $param = $this->_stripNamespace($param);
265 $newparams[str_replace($this->_pkg->getTasksNs() . ':', '', $i)] = $param;
272 * Unlike other tasks, the installed file name is passed in instead of the file contents,
273 * because this task is handled post-installation
274 * @param PEAR_PackageFile_v1|PEAR_PackageFile_v2
275 * @param string file name
276 * @return bool|PEAR_Error false to skip this file, PEAR_Error to fail
277 * (use $this->throwError)
279 function startSession($pkg, $contents)
281 if ($this->installphase != PEAR_TASK_INSTALL) {
284 // remove the tasks: namespace if present
286 $this->_stripNamespace();
287 $this->logger->log(0, 'Including external post-installation script "' .
288 $contents . '" - any errors are in this script');
289 include_once $contents;
290 if (class_exists($this->_class)) {
291 $this->logger->log(0, 'Inclusion succeeded');
293 return $this->throwError('init of post-install script class "' . $this->_class
296 $this->_obj = new $this->_class;
297 $this->logger->log(1, 'running post-install script "' . $this->_class . '->init()"');
298 PEAR::pushErrorHandling(PEAR_ERROR_RETURN);
299 $res = $this->_obj->init($this->config, $pkg, $this->_lastversion);
300 PEAR::popErrorHandling();
302 $this->logger->log(0, 'init succeeded');
304 return $this->throwError('init of post-install script "' . $this->_class .
307 $this->_contents = $contents;
313 * @see PEAR_PackageFile_v2::runPostinstallScripts()
314 * @param array an array of tasks
315 * @param string install or upgrade