Project

General

Profile

1 1643 darkviper
<?php
2
/**
3
 *
4
 * @category        WBCore
5
 * @package         WBCore_addons
6
 * @author          Werner v.d.Decken
7
 * @copyright       Website Baker Org. e.V.
8
 * @link			http://www.websitebaker2.org/
9
 * @license         http://www.gnu.org/licenses/gpl.html
10
 * @revision        $Revision$
11
 * @filesource		$HeadURL$
12
 * @lastmodified    $Date$
13
 */
14
15
class CopyTheme{
16
17
// global vars
18
	private $_oDb             = null;
19
	private $_aLang           = array();
20
	private $_aGlobals        = array();
21
// class properties
22
	private $_sThemesBasePath = ''; // (/var/www/httpdocs/wb/templates)
23
	private $_sSourceDir      = ''; // (default_theme)
24
	private $_sNewThemeDir    = ''; // (MyNewBackendTheme)
25
	private $_sNewThemeName   = ''; // ('my new Backend Theme')
26
27
	private $_aErrors         = array();
28
29
/**
30
 *
31
 * @param string $sSourceThemePath (THEME_PATH.'/templates/'.DEFAULT_THEME)
32
 * @param string $sNewThemeName (NewName)
33
 */
34
	public function __construct()
35
	{
36
	// import global vars
37
		$this->_oDb   = $GLOBALS['database'];
38
		$this->_aLang = $GLOBALS['MESSAGE'];
39
	// import global Consts
40
		$this->_aGlobals['TablePrefix']     = TABLE_PREFIX;
41
		$this->_aGlobals['Debug']           = (defined('DEBUG') && DEBUG === true);
42
		$this->_aGlobals['IsLinux']         = ((substr(__FILE__, 0, 1)) == '/');
43
		$this->_aGlobals['StringDirMode']   = STRING_DIR_MODE;
44
		$this->_aGlobals['StringFileMode']  = STRING_FILE_MODE;
45
	}
46
/**
47
 * start copy current theme into a new theme
48
 * @param string $sSourceThemePath (/var/www/httpdocs/wb/templates/destination_theme)
49
 * @param string $sNewThemeName (NewName)
50
 * @return bool
51
 */
52
	public function execute($sSourceThemePath, $sNewThemeName)
53
	{
54
		$bRetval = false;
55
		$this->clearError();
56
		$this->_init($sSourceThemePath, $sNewThemeName);
57
		if(!is_writeable($this->_sThemesBasePath)) {
58
			$this->_setError( $this->_aLang['THEME_DESTINATION_READONLY'].' >> '
59
			                  .$this->_sThemesBasePath );
60
			return false;
61
		}
62
		if($this->_copyTree()) {
63
			if($this->_modifyInfoFile()) {
64
				if($this->_registerNewTheme()) {
65
					return true;
66
				}
67
			}
68
		}
69
		$dir = $this->_sThemesBasePath.'/'.$this->_sNewThemeDir;
70
		$this->_doRollback($dir);
71
		return false;
72
	}
73
/**
74
 * initialize the class
75
 * @param string $sSourceThemePath (/var/www/httpdocs/wb/templates/destination_theme)
76
 * @param string $sNewThemeName (NewName)
77
 * @return boolean
78
 */
79
	private function _init($sSourceThemePath, $sNewThemeName)
80
	{
81
	// sanitize arguments and calculate local vars
82
		$this->_sThemesBasePath = str_replace('\\','/', dirname($sSourceThemePath));
83
		$this->_sSourceDir = basename($sSourceThemePath);
84
		$this->_sNewThemeDir = $this->_SanitizeNewDirName($sNewThemeName);
85
		$this->_sNewThemeName = $this->_SanitizeNewName($sNewThemeName);
86
	}
87
/**
88
 * sanitize the new name and make it unique
89
 * @param string $sName
90
 * @return string
91
 */
92
	private function _SanitizeNewName($sName)
93
	{
94
		$sName = mysql_real_escape_string($sName);
95
		$iCount = '';
96
		do {
97
			$sSearch = $sName.($iCount ? ' '.$iCount : '');
98
			$sql = 'SELECT COUNT(*) FROM `'.$this->_aGlobals['TablePrefix'].'addons` '
99
				 . 'WHERE LOWER(`name`)=\''.strtolower($sSearch).'\' AND `function`=\'theme\'';
100
			$exists = $this->_oDb->get_one($sql);
101
			$iCount = (int)$iCount + 1;
102
		}while($exists);
103
		return ($sName != $sSearch ? $sSearch : $sName);
104
	}
105
/**
106
 * generate a unique valid dirname from template name
107
 * @param string $sName
108
 * @return string
109
 */
110
	private function _SanitizeNewDirName($sName)
111
	{
112
		// remove all of the ASCII controllcodes
113
		$sName = preg_replace('/[^0-9a-zA-Z \-_]/', '', strtolower($sName));
114
		$sName = str_replace(array('-', '_'), array('- ', ' '), $sName);
115
		$sName = str_replace(' ', '', ucwords($sName));
116
		$sName = ($sName == '' ? 'MyNewTheme' : $sName);
117
		$iCount = '';
118
		do {
119
			$sSearch = $sName.($iCount ? '_'.$iCount : '');
120
			$sql = 'SELECT COUNT(*) FROM `'.$this->_aGlobals['TablePrefix'].'addons` '
121
				 . 'WHERE `directory`=\''.$sSearch.'\' AND `function`=\'theme\'';
122
			$exists = $this->_oDb->get_one($sql);
123
			$iCount = (int)$iCount + 1;
124
		}while($exists);
125
		return ($sName != $sSearch ? $sSearch : $sName);
126
	}
127
/**
128
 * copy the complete theme - directory tree with all included files
129
 * @return boolean true if ok
130
 */
131
	private function _copyTree()
132
	{
133
		$bRetval = true;
134
		$sSourceDir = $this->_sThemesBasePath.'/'.$this->_sSourceDir;
135
		// build file list to copy into destination theme
136
		$aFileList = array();
137
		try {
138
			$oIterator = new RecursiveDirectoryIterator($sSourceDir);
139
			foreach (new RecursiveIteratorIterator($oIterator) as $cur) {
140
				if($cur->isDir() || strpos($cur, '.svn') !== false) { continue; }
141
				$sPattern = '/^'.preg_quote($sSourceDir, '/').'/';
142
				$sFilename = preg_replace($sPattern, '', $cur->getPathname());
143
				$sFilePath = preg_replace($sPattern, '', $cur->getPath());
144
				$aFileList[$sFilename] = $sFilePath;
145
			}
146
			natsort($aFileList);
147
		}catch(Exeption $e) {
148
			$msg  = 'CopyTheme::_copyTree => '.$this->_aLang['GENERIC_FAILED_COMPARE'];
149
			$msg .= '<br />'.$e->getMessage();
150
			$this->_setError($msg);
151
			$bRetval = false;
152
		}
153
		if($bRetval) {
154
		// create all needed directories
155
			$aDirectories = array_unique(array_values($aFileList));
156
			$bRetval = $this->_createDirs($aDirectories);
157
		}
158
		if($bRetval) {
159
			// copy all needed files
160
			$aFiles = array_keys($aFileList);
161
			$bRetval = $this->_copyFiles($aFiles);
162
		}
163
		return $bRetval;
164
	}
165
/**
166
 * create all the directories from $aNewDirs-list under $sBaseDir
167
 * @param array $aNewDirList ( array('', '/images', '/images/files')
168
 */
169
	private function _createDirs($aNewDirList)
170
	{
171
		$bRetval = true;
172
		foreach($aNewDirList as $sDir) {
173
			$sNewDir = $this->_sThemesBasePath.'/'.$this->_sNewThemeDir.$sDir;
174
			if(!file_exists($sNewDir) &&  mkdir($sNewDir, 0777, true)) {
175
				if($this->_aGlobals['IsLinux']) {
176
					if(!chmod($sNewDir, $this->_aGlobals['StringDirMode'])) {
177
						$sMsg = 'CopyTheme::createDirs::chmod('.$sNewDir.') >> '
178
								.$this->_aLang['GENERIC_FAILED_COMPARE'];
179
						$this->_setError($sMsg);
180
						$bRetval = false;
181
						break;
182
					}
183
				}
184
			}else {
185
				$sMsg = 'CopyTheme::createDirs::mkdir('.$sNewDir.') >> '
186
						.$this->_aLang['GENERIC_FAILED_COMPARE'];
187
				$this->_setError($sMsg);
188
				$bRetval = false;
189
				break;
190
			}
191
		}
192
		return $bRetval;
193
	}
194
/**
195
 * copies a list of files from source directory to destination directory
196
 * @param array $aFileList (array('/index.php', '/images/index.php', '/images/files/index.php')
197
 */
198
	private function _copyFiles($aFileList)
199
	{
200
		$bRetval = true;
201
		$sSourceDir = $this->_sThemesBasePath.'/'.$this->_sSourceDir;
202
		$sDestinationDir = $this->_sThemesBasePath.'/'.$this->_sNewThemeDir;
203
		foreach($aFileList as $sFile) {
204
			if(copy($sSourceDir.$sFile, $sDestinationDir.$sFile)) {
205
				if($this->_aGlobals['IsLinux']) {
206
					if(!chmod($sDestinationDir.$sFile, $this->_aGlobals['StringFileMode'])) {
207
						$sMsg = 'CopyTheme::copyFiles::chmod('.$sDestinationDir.$sFile.') >> '
208
								.$this->_aLang['GENERIC_FAILED_COMPARE'];
209
						$this->_setError($sMsg);
210
						$bRetval = false;
211
						break;
212
					}
213
				}
214
			}else {
215
				$sMsg = 'CopyTheme::copyFiles::copy('.$sDestinationDir.$sFile.') >> '
216
						.$this->_aLang['GENERIC_FAILED_COMPARE'];
217
				$this->_setError($sMsg);
218
				$bRetval = false;
219
				break;
220
			}
221
		}
222
		return $bRetval;
223
	}
224
/**
225
 * register a available theme in the database (gets values from info.php)
226
 * @return bool TRUE if ok
227
 */
228
	private function _registerNewTheme()
229
	{
230
		$bRetval = true;
231
		$sThemeInfoFile = $this->_sThemesBasePath.'/'.$this->_sNewThemeDir.'/info.php';
232
		$aVariables = $this->_getThemeInfo($sThemeInfoFile);
233
		$sql = 'INSERT INTO `'.$this->_aGlobals['TablePrefix'].'addons` '
234
		     . 'SET `type`=\'template\', '
235
		     .     '`function`=\'theme\', '
236
		     .     '`directory`=\''.$aVariables['directory'].'\', '
237
		     .     '`name`=\''.$aVariables['name'].'\', '
238
		     .     '`description`=\''.mysql_real_escape_string($aVariables['description']).'\', '
239
		     .     '`version`=\''.$aVariables['version'].'\', '
240
		     .     '`platform`=\''.$aVariables['platform'].'\', '
241
		     .     '`author`=\''.mysql_real_escape_string($aVariables['author']).'\', '
242
		     .     '`license`=\''.mysql_real_escape_string($aVariables['license']).'\'';
243
		if(!$this->_oDb->query($sql)) {
244
			$sMsg = 'CopyTheme::registerNewTheme('.$this->_sNewThemeName.') >> '
245
			        .$this->_aLang['GENERIC_NOT_UPGRADED'];
246
			$sMsg .= (($this->_aGlobals['Debug']) ? '<br />'.$this->_oDb->get_error() : '');
247
			$this->_setError($sMsg);
248
			$bRetval = false;
249
		}
250
		return $bRetval;
251
	}
252
/**
253
 * modify info-file of copied theme
254
 * @return bool TRUE if ok
255
 */
256
	private function _modifyInfoFile()
257
	{
258
		$bRetval = false;
259
		$sThemeInfoFile = $this->_sThemesBasePath.'/'.$this->_sNewThemeDir.'/info.php';
260
		$aVariables = $this->_getThemeInfo($sThemeInfoFile);
261
		$aVariables['directory']   = $this->_sNewThemeDir;
262
		$aVariables['name']        = $this->_sNewThemeName;
263
		$aVariables['version']     = '0.0.1';
264
		$aVariables['description'] = '(copy): '.$aVariables['description'];
265
		if(file_exists($sThemeInfoFile)) {
266
			$sInfoContent = file_get_contents($sThemeInfoFile);
267
			foreach($aVariables as $key=>$val) {
268
				$sSearch  = '/(\$template_'.$key.'\s*=\s*(["\'])).*?(\2)\s*;/s';
269
				$sReplace = ($val != '' && is_numeric($val[0])) ? '${1}' : '$1';
270
				$sReplace .= $val.'$2;';
271
				$sInfoContent = preg_replace($sSearch, $sReplace, $sInfoContent);
272
			}
273
			// remove trailing "\?\>" to sanitize the php file
274
			$sInfoContent = preg_replace('/\s*?\?>\s*$/', '', $sInfoContent)."\n";
275
			if(file_put_contents($sThemeInfoFile, $sInfoContent) !== false) {
276
				return true;
277
			}
278
		}
279
		$this->_setError('CopyTheme::modifyInfoFile('.$this->_sNewThemeDir.'/info.php) >> '
280
		               .$this->_aLang['GENERIC_NOT_UPGRADED']);
281
		return $bRetval;
282
	}
283
/**
284
 * read old values from old info-file
285
 * @param string $sThemeInfoFile
286
 * @return array
287
 */
288
	private function _getThemeInfo($sThemeInfoFile)
289
	{
290
		if(file_exists($sThemeInfoFile)) {
291
			include $sThemeInfoFile;
292
			return array(
293
				'directory' => $template_directory?$template_directory:null,
294
				'name' => $template_name?$template_name:null,
295
				'version' => $template_version?$template_version:null,
296
				'description' => $template_description?$template_description:null,
297
				'platform' => $template_platform?$template_platform:null,
298
				'author' => $template_author?$template_author:null,
299
				'license' => $template_license?$template_license:null,
300
			);
301
		} else {
302
			return array(
303
				'directory' => null,
304
				'name' => null,
305
				'version' => null,
306
				'description' => null,
307
				'platform' => null,
308
				'author' => null,
309
				'license' => null,
310
			);
311
		}
312
	}
313
/**
314
 * on Error undo all already done copy/create actions
315
 * @param string $dir
316
 */
317
	private function _doRollback($dir)
318
	{
319
		$iFileErrors = 0;
320
		$iDirErrors  = 0;
321
		$iterator = new RecursiveIteratorIterator(new RecursiveDirectoryIterator($dir),
322
												  RecursiveIteratorIterator::CHILD_FIRST);
323
		foreach ($iterator as $path) {
324
			if ($path->isDir()) {
325
				rmdir($path->__toString());
326
			} else {
327
				unlink($path->__toString());
328
			}
329
		}
330
		unset($path);
331
		unset($iterator);
332
		if(file_exists($dir)) { rmdir($dir); }
333
	}
334
/**
335
 * add a new error message to the queue
336
 * @param string $sErrMsg
337
 */
338
	private function _setError($sErrMsg)
339
	{
340
		$this->_aErrors[] = $sErrMsg;
341
	}
342
/**
343
 * clear the errors queue
344
 */
345
	public function clearError()
346
	{
347
		$this->_aErrors = array();
348
	}
349
/**
350
 * true if there is an error otherwise false
351
 * @return bool
352
 */
353
	public function isError()
354
	{
355
		return (sizeof($this->_aErrors) > 0);
356
	}
357
/**
358
 * gets all error messages as multiline string
359
 * @param bool $nl2br true seperates lines by "<br />" else by "\n"
360
 * @return string
361
 */
362
	public function getError($nl2br = true)
363
	{
364
		$sClue = ($nl2br ? '<br />' : "\n");
365
		$sErrorMsg = implode($sClue, $this->_aErrors);
366
		return $sErrorMsg;
367
	}
368
369
370
} // end class