3 require_once(AK_LIB_DIR
.DS
.'AkLogger.php');
5 class FrameworkSetup
extends AkObject
7 var $available_databases = array(
9 'pgsql' => 'PostgreSQL',
12 var $available_locales = array('en', 'es');
13 var $locales = array('en');
15 var $stylesheets = array('scaffold','forms');
17 function __construct()
19 if(file_exists(AK_CONFIG_DIR
.DS
.'config.php')){
20 echo Ak
::t('The framework_setup.php found that you already have a configuration file at config/config.php. You need to remove that file first in order to run the setup.', array(), 'framework_setup');
28 * Will try to guess the best database on current server.
29 * Per example, if current server has MySQL and PostgreSQL it will pick up
30 * PostgreSQL if MySQL doens't support InnoDB tables.
32 * If none of the above is
35 function suggestDatabaseType()
38 * @todo add database check for postgre
40 return $this->_suggestMysql() ?
'mysql' : (function_exists('pg_connect') ?
'pgsql' : (AK_PHP5 ?
'sqlite' : 'mysql'));
43 function _suggestMysql()
45 if(function_exists('mysql_connect')){
46 if($db = @mysql_connect
( $this->getDatabaseHost(),
47 $this->getDatabaseUser(),
48 $this->getDatabasePassword())){
51 * @todo Checking if innodb is available break on some systems
52 * we should investigate a better way to do this
55 $result = mysql_query($db, "SHOW VARIABLES LIKE 'have_innodb';");
60 @mysql_query("SHOW VARIABLES LIKE 'have_innodb';", $db)
71 function createDatabase($mode)
75 $db = $this->databaseConnection('admin');
78 if($this->getDatabaseType($mode) != 'sqlite'){
79 $DataDict = NewDataDictionary($db);
80 if($this->getDatabaseType($mode) == 'mysql'){
81 $success = $this->_createMysqlDatabase($db, $mode) ?
$success : false;
89 function _createMysqlDatabase(&$db, $mode)
92 $success = $db->Execute('CREATE DATABASE '.$this->getDatabaseName($mode)) ?
$success : false;
93 $success = $db->Execute("GRANT SELECT,INSERT,UPDATE,DELETE,CREATE,DROP,ALTER ON ".
94 $this->getDatabaseName($mode).".* TO '".$this->getDatabaseUser($mode)."'@'".
95 $this->getDatabaseHost($mode)."' IDENTIFIED BY '".$this->getDatabasePassword($mode)."'") ?
$success : false;
99 function getDatabaseHost($mode = '')
101 return !isset($this->{$mode.'_database_host'}) ?
$this->suggestDatabaseHost() : $this->{$mode.'_database_host'};
104 function getDatabaseUser($mode = '')
106 return !isset($this->{$mode.'_database_user'}) ?
$this->suggestUserName() : $this->{$mode.'_database_user'};
109 function getDatabasePassword($mode = '')
111 return !isset($this->{$mode.'_database_password'}) ?
'' : $this->{$mode.'_database_password'};
114 function getDatabaseType()
116 return !isset($this->database_type
) ?
$this->suggestDatabaseType() : $this->database_type
;
119 function setDatabaseType($database_type)
121 $database_type = strtolower($database_type);
122 if(!in_array($database_type, array_keys($this->available_databases
))){
123 trigger_error(Ak
::t('Selected database is not supported yet by the Akelos Framework',array(),'framework_setup'));
124 }elseif(!$this->isDatabaseDriverAvalible($database_type)){
125 trigger_error(Ak
::t('Could not set %database_type as database type. Your current PHP settings do not support %database_type databases', array('%database_type '=>$database_type), 'framework_setup'));
127 $this->database_type
= $database_type;
128 return $this->database_type
;
133 function getDatabaseName($mode)
135 return !isset($this->{$mode.'_database_name'}) ?
136 $this->guessApplicationName().($mode=='development'?
'_dev':($mode=='testing'?
'_tests':'')) :
137 $this->{$mode.'_database_name'};
140 function setDatabaseName($database_name, $mode)
142 $this->{$mode.'_database_name'} = $database_name;
145 function setDatabaseHost($host, $mode)
147 $this->{$mode.'_database_host'} = $host;
150 function setDatabaseUser($user, $mode)
152 $this->{$mode.'_database_user'} = $user;
155 function setDatabasePassword($password, $mode)
157 $this->{$mode.'_database_password'} = $password;
161 function getDatabaseAdminUser()
163 return !isset($this->admin_database_user
) ?
'root' : $this->admin_database_user
;
166 function getDatabaseAdminPassword()
168 return !isset($this->admin_database_password
) ?
'' : $this->admin_database_password
;
172 function setDatabaseAdminUser($user)
174 $this->admin_database_user
= $user;
177 function setDatabaseAdminPassword($password)
179 $this->admin_database_password
= $password;
183 function databaseConnection($mode)
185 static $connections = array();
186 require_once(AK_CONTRIB_DIR
.DS
.'adodb'.DS
.'adodb.inc.php');
188 $dsn = $this->_getDsn($mode);
189 if(!isset($connections[$dsn])){
190 if(!$connections[$dsn] = @NewADOConnection
($dsn)){
194 return $connections[$dsn];
197 function _getDsn($mode)
199 if($mode == 'admin'){
200 $db_type = $this->getDatabaseType('production');
201 return $db_type.'://'.
202 $this->getDatabaseAdminUser().':'.
203 $this->getDatabaseAdminPassword().'@'.$this->getDatabaseHost('production').($db_type == 'mysql' ?
'/mysql' : '');
205 return $this->getDatabaseType() == 'sqlite' ?
206 "sqlite://".urlencode(AK_CONFIG_DIR
.DS
.$this->getDatabaseName($mode).'-'.$this->random
.'.sqlite') :
207 $this->getDatabaseType($mode)."://".$this->getDatabaseUser($mode).":".$this->getDatabasePassword($mode).
208 "@".$this->getDatabaseHost($mode)."/".$this->getDatabaseName($mode);
213 function getAvailableDatabases()
215 $databases = array();
216 foreach ($this->available_databases
as $type=>$description){
217 if($this->isDatabaseDriverAvalible($type)){
218 $databases[] = array('type' => $type, 'name' => $description);
226 function isDatabaseDriverAvalible($database_type = null)
228 $database_type = empty($database_type) ?
$this->getDatabaseType() : $database_type;
229 if(strstr($database_type,'mysql')){
230 $function = 'mysql_connect';
231 }elseif (strstr($database_type,'pg') ||
strstr($database_type,'gre')){
232 $function = 'pg_connect';
233 }elseif (strstr($database_type,'lite')){
234 $function = 'sqlite_open';
236 $function = $database_type.'_connect';
238 return function_exists($function);
241 function runFrameworkInstaller()
243 static $unique_dsn = array();
244 require_once(AK_LIB_DIR
.DS
.'AkInstaller.php');
245 require_once(AK_APP_DIR
.DS
.'installers'.DS
.'framework_installer.php');
247 foreach (array('production', 'development') as $mode){
248 $dsn = $this->_getDsn($mode);
249 if(!isset($unique_dsn[$dsn])){
250 $DbInstance =& AkDbAdapter
::getInstance(array(
251 'type' => $this->getDatabaseType($mode),
252 'file' => AK_CONFIG_DIR
.DS
.$this->getDatabaseName($mode).'-'.$this->random
.'.sqlite',
253 'user' => $this->getDatabaseUser($mode),
254 'password' => $this->getDatabasePassword($mode),
255 'host' => $this->getDatabaseHost($mode),
256 'database_name' => $this->getDatabaseName($mode)
259 $installer =& new FrameworkInstaller($DbInstance);
260 $installer->install(null, array('mode' => $mode));
261 $unique_dsn[$dsn] = true;
271 function getUrlSuffix()
273 return empty($this->url_suffix
) ? AK_SITE_URL_SUFFIX
: $this->url_suffix
;
277 function getConfigurationFile($settings = array())
281 $configuration_template = <<<CONFIG
284 \$database_settings = array(
285 'production' => array(
286 'type' => '%production_database_type', // mysql, sqlite or pgsql
287 'database_file' => '%production_database_file', // you only need this for SQLite
288 'host' => '%production_database_host',
290 'database_name' => '%production_database_name',
291 'user' => '%production_database_user',
292 'password' => '%production_database_password',
293 'options' => '' // persistent, debug, fetchmode, new
296 'development' => array(
297 'type' => '%development_database_type',
298 'database_file' => '%development_database_file',
299 'host' => '%development_database_host',
301 'database_name' => '%development_database_name',
302 'user' => '%development_database_user',
303 'password' => '%development_database_password',
307 // Warning: The database defined as 'testing' will be erased and
308 // re-generated from your development database when you run './script/test app'.
309 // Do not set this db to the same as development or production.
311 'type' => '%testing_database_type',
312 'database_file' => '%testing_database_file',
313 'host' => '%testing_database_host',
315 'database_name' => '%testing_database_name',
316 'user' => '%testing_database_user',
317 'password' => '%testing_database_password',
322 // If you want to write/delete/create files or directories using ftp instead of local file
323 // access, you can set an ftp connection string like:
324 // \$ftp_settings = 'ftp://username:password@example.com/path/to_your/base/dir';
325 \$ftp_settings = '%ftp_settings';
327 // Current environment. Options are: development, testing and production
328 defined('AK_ENVIRONMENT') ? null : define('AK_ENVIRONMENT', 'development');
332 // Locale settings ( you must create a file at /config/locales/ using en.php as departure point)
333 // Please be aware that your charset needs to be UTF-8 in order to edit the locales files
334 // auto will enable all the locales at config/locales/ dir
335 define('AK_AVAILABLE_LOCALES', '%locales');
337 // Use this in order to allow only these locales on web requests
338 define('AK_ACTIVE_RECORD_DEFAULT_LOCALES', '%locales');
339 define('AK_APP_LOCALES', '%locales');
340 define('AK_PUBLIC_LOCALES', '%locales');
342 %AK_URL_REWRITINGdefined('AK_URL_REWRITE_ENABLED') ? null : define('AK_URL_REWRITE_ENABLED', true);
346 include_once(dirname(__FILE__).DIRECTORY_SEPARATOR.'boot.php');
351 if(empty($settings)){
353 foreach (array('production','development','testing') as $mode){
354 $settings['%'.$mode.'_database_type'] = $this->getDatabaseType($mode);
355 if($settings['%'.$mode.'_database_type'] == 'sqlite'){
357 $settings['%'.$mode.'_database_file'] = AK_CONFIG_DIR
.DS
.$this->getDatabaseName($mode).'-'.$this->random
.'.sqlite';
358 $settings['%'.$mode.'_database_user'] =
359 $settings['%'.$mode.'_database_password'] =
360 $settings['%'.$mode.'_database_host'] =
361 $settings['%'.$mode.'_database_name'] = '';
363 $settings['%'.$mode.'_database_user'] = $this->getDatabaseUser($mode);
364 $settings['%'.$mode.'_database_password'] = $this->getDatabasePassword($mode);
365 $settings['%'.$mode.'_database_host'] = $this->getDatabaseHost($mode);
366 $settings['%'.$mode.'_database_name'] = $this->getDatabaseName($mode);
367 $settings['%'.$mode.'_database_file'] = '';
371 $settings['%ftp_settings'] = isset($this->ftp_enabled
) ?
'ftp://'.$this->getFtpUser().':'.$this->getFtpPassword().'@'.$this->getFtpHost().$this->getFtpPath() : '';
374 $settings['%locales'] = $this->getLocales();
376 $settings['%AK_URL_REWRITING'] = $this->isUrlRewriteEnabled() ?
'' : "// The web configuration wizard could not detect if you have mod_rewrite enabled. \n// If that is the case, you should uncomment the next line line for better performance. \n// ";
377 $settings['%AK_FRAMEWORK_DIR'] = defined('AK_FRAMEWORK_DIR') ?
378 "defined('AK_FRAMEWORK_DIR') ? null : define('AK_FRAMEWORK_DIR', '".AK_FRAMEWORK_DIR
."');" : '';
381 return str_replace(array_keys($settings), array_values($settings), $configuration_template);
385 function writeConfigurationFile($configuration_details)
387 if($this->canWriteConfigurationFile()){
388 return Ak
::file_put_contents(AK_CONFIG_DIR
.DS
.'config.php', $configuration_details);
393 function canWriteConfigurationFile()
395 if(isset($this->ftp_enabled
)){
396 $this->testFtpSettings();
398 $file_path = AK_CONFIG_DIR
.DS
.'config.php';
399 return !file_exists($file_path);
402 function writeRoutesFile()
404 if(isset($this->ftp_enabled
)){
405 $this->testFtpSettings();
407 $file_path = AK_CONFIG_DIR
.DS
.'routes.php';
408 if(!file_exists($file_path)){
409 return Ak
::file_put_contents($file_path, file_get_contents(AK_CONFIG_DIR
.DS
.'DEFAULT-routes.php'));
414 function modifyHtaccessFiles()
416 if($this->isUrlRewriteEnabled()){
420 if(isset($this->ftp_enabled
)){
421 $this->testFtpSettings();
423 $file_1 = AK_BASE_DIR
.DS
.'.htaccess';
424 $file_2 = AK_PUBLIC_DIR
.DS
.'.htaccess';
425 $file_1_content = @Ak
::file_get_contents($file_1);
426 $file_2_content = @Ak
::file_get_contents($file_2);
428 $url_suffix = $this->getUrlSuffix();
430 $url_suffix = $url_suffix[0] != '/' ?
'/'.$url_suffix : $url_suffix;
432 empty($file_1_content) ?
null : @Ak
::file_put_contents($file_1, str_replace('# RewriteBase /framework',' RewriteBase '.$url_suffix, $file_1_content));
433 empty($file_2_content) ?
null : @Ak
::file_put_contents($file_2, str_replace('# RewriteBase /framework',' RewriteBase '.$url_suffix, $file_2_content));
436 function isUrlRewriteEnabled()
438 return @file_get_contents
(AK_SITE_URL
.'/framework_setup/url_rewrite_check') == 'url_rewrite_working';
441 function getApplicationName()
443 if(!isset($this->application_name
)){
444 $this->setApplicationName($this->guessApplicationName());
446 return $this->application_name
;
450 function setApplicationName($application_name)
452 $this->application_name
= $application_name;
455 function guessApplicationName()
457 $application_name = array_pop(explode('/',AK_SITE_URL_SUFFIX
));
458 $application_name = empty($application_name) ?
substr(AK_BASE_DIR
, strrpos(AK_BASE_DIR
, DS
)+
1) : $application_name;
459 return empty($application_name) ?
'my_app' : $application_name;
462 function needsFtpFileHandling()
464 return !$this->_writeToTemporaryFile(AK_CONFIG_DIR
.DS
.'test_file.txt');
467 function _writeToTemporaryFile($file_path, $content = '', $mode = 'a+')
470 if(strstr($file_path, AK_BASE_DIR
)){
471 if(!$fp = @fopen
($file_path, $mode)) {
474 $this->_temporaryFilesCleanUp($file_path);
475 $result = @fwrite
($fp, $content);
476 if (false !== $result){
484 function _temporaryFilesCleanUp($file_path = null)
486 static $file_paths = array();
487 if($file_path == null && count($file_paths) > 0){
488 foreach ($file_paths as $file_path){
489 // we try to prevent removing nothing outside the framework
490 if(strstr($file_path, AK_BASE_DIR
)){
495 }elseif (!empty($file_path) && count($file_paths) == 0){
496 register_shutdown_function(array($this, '_temporaryFilesCleanUp'));
498 $file_paths[$file_path] = $file_path;
501 function addSetupOptions($options = array())
503 $options = array_merge($this->getDefaultOptions(), $options);
505 if(!$this->isDatabaseDriverAvalible($options['database']['type'])){
506 $this->addError(Ak
::t('Your current PHP settings do not have support for %database_type databases.',
507 array('%database_type'=>$options['database']['type']),'framework_setup'));
508 }elseif(!$db = $this->databaseConnection(
509 $options['database']['type'],
510 $options['database']['host'],
511 $options['database']['user'],
512 $options['database']['password'],
513 $options['database']['name'])){
514 $this->addError(Ak
::t('Could not connect to the database using %details', array(), 'framework_setup'),
515 array('%details'=>var_dump($options['database'])));
518 $options['server']['locales'] = str_replace(' ','', $options['server']['locales']);
519 $options['server']['locales'] = empty($options['server']['locales']) ?
'en' : $options['server']['locales'];
521 foreach ($options as $group=>$details){
522 if(!is_array($details)){
525 foreach ($details as $detail=>$value){
526 $this->{$group.'_'.$detail} = $value;
530 $this->options
= $options;
533 function getSetupOptions()
535 return isset($this->options
) ?
$this->options
: array();
538 function addError($error)
540 $this->errors
[] = $error;
545 return $this->errors
;
548 function getDefaultOptions()
551 'production_database_type'=> $this->getDatabaseType('production'),
552 'production_database_host'=> $this->getDatabaseHost('production'),
553 'production_database_name'=> $this->getDatabaseName('production'),
554 'production_database_user'=> $this->getDatabaseUser('production'),
555 'production_database_password'=> '',
557 'development_database_type'=> $this->getDatabaseType('development'),
558 'development_database_host'=> $this->getDatabaseHost('development'),
559 'development_database_name'=> $this->getDatabaseName('development'),
560 'development_database_user'=> $this->getDatabaseUser('development'),
561 'development_database_password'=> '',
563 'testing_database_type'=> $this->getDatabaseType('testing'),
564 'testing_database_host'=> $this->getDatabaseHost('testing'),
565 'testing_database_name'=> $this->getDatabaseName('testing'),
566 'testing_database_user'=> $this->getDatabaseUser('testing'),
567 'testing_database_password'=> '',
569 'admin_database_user' => $this->getDatabaseAdminUser(),
570 'admin_database_password' => $this->getDatabaseAdminPassword(),
572 'url_suffix'=> trim(AK_SITE_URL_SUFFIX
, '/'),
573 'locales'=> join(',',$this->suggestLocales()),
574 'ftp_user' => $this->getFtpUser(),
575 'ftp_host' => $this->getFtpHost(),
576 'ftp_path' => $this->getFtpPath(),
578 'random' => Ak
::randomString(),
582 function canUseFtpFileHandling()
584 return function_exists('ftp_connect');
587 function getFtpHost()
589 if(!isset($this->ftp_host
)){
590 return array_shift(explode('/', str_replace(array('http://','https://','www.'),array('','','ftp.'), AK_SITE_URL
).'/'));
592 return $this->ftp_host
;
595 function setFtpHost($ftp_host)
597 $this->ftp_host
= trim($ftp_host, '/');
600 function getFtpPath()
602 if(!isset($this->ftp_path
)){
603 return '/'.trim(join('/',array_slice(
605 str_replace(array('http://','https://'),'', AK_SITE_URL
).'/'),1)
608 return $this->ftp_path
;
611 function setFtpPath($ftp_path)
613 $this->ftp_path
= empty($ftp_path) ?
'' : '/'.trim($ftp_path,'/');
616 function getFtpUser()
618 return !isset($this->ftp_user
) ?
$this->suggestUserName() : $this->ftp_user
;
621 function setFtpUser($ftp_user)
623 $this->ftp_user
= $ftp_user;
626 function getFtpPassword()
628 return !isset($this->ftp_password
) ?
'' : $this->ftp_password
;
631 function setFtpPassword($ftp_password)
633 $this->ftp_password
= $ftp_password;
637 function setDefaultOptions()
639 foreach ($this->getDefaultOptions() as $k=>$v){
644 function hasUrlSuffix()
646 return !empty($this->url_suffix
) && trim($this->url_suffix
,'/') != '';
649 function suggestUserName()
651 if(AK_OS
=== 'WINDOWS'){
654 $script_owner = get_current_user();
655 return $script_owner == '' ?
'root' : $script_owner;
659 function testFtpSettings()
661 if(!$this->canUseFtpFileHandling()){
665 $ftp_path = 'ftp://'.$this->getFtpUser().':'.$this->getFtpPassword().'@'.
666 $this->getFtpHost().$this->getFtpPath();
668 @define
('AK_UPLOAD_FILES_USING_FTP', true);
669 @define
('AK_READ_FILES_USING_FTP', false);
670 @define
('AK_DELETE_FILES_USING_FTP', true);
671 @define
('AK_FTP_PATH', $ftp_path);
672 @define
('AK_FTP_AUTO_DISCONNECT', true);
674 if(@Ak
::file_put_contents(AK_CONFIG_DIR
.DS
.'test_file.txt','hello from ftp')){
675 $text = @Ak
::file_get_contents(AK_CONFIG_DIR
.DS
.'test_file.txt');
676 @Ak
::file_delete(AK_CONFIG_DIR
.DS
.'test_file.txt');
679 $this->ftp_enabled
= (isset($text) && $text == 'hello from ftp');
681 return $this->ftp_enabled
;
684 function getLocales()
686 return join(',',!isset($this->locales
) ?
$this->suggestLocales() : $this->_getLocales($this->locales
));
689 function setLocales($locales)
691 $this->locales
= $this->_getLocales($locales);
694 function _getLocales($locales)
696 return array_map('trim',array_unique(array_diff((is_array($locales) ?
$locales : explode(',',$locales.',')), array(''))));
699 function suggestLocales()
701 require_once(AK_LIB_DIR
.DS
.'AkLocaleManager.php');
703 $LocaleManager = new AkLocaleManager();
705 $langs = array('en');
706 if(AK_OS
=== 'WINDOWS'){
707 $langs[] = @$_ENV['LANG'];
709 $langs = array_merge($langs, $LocaleManager->getBrowserLanguages());
711 return array_unique(array_map('strtolower',array_diff($langs,array(''))));
714 function suggestDatabaseHost()
719 function relativizeStylesheetPaths()
721 $asset_path = $this->_getAssetBasePath();
722 if($this->hasUrlSuffix() ||
!empty($asset_path)){
723 $url_suffix = trim($this->getUrlSuffix(),'/');
724 if(!empty($asset_path)){
725 $url_suffix = trim($url_suffix.'/'.$asset_path,'/');
727 foreach ($this->stylesheets
as $stylesheet) {
728 $filename = AK_PUBLIC_DIR
.DS
.'stylesheets'.DS
.$stylesheet.'.css';
729 $relativized_css = preg_replace("/url\((\'|\")?\/images/","url($1/$url_suffix/images", @Ak
::file_get_contents($filename));
730 empty($relativized_css) ?
null : @Ak
::file_put_contents($filename, $relativized_css);
735 function _getAssetBasePath()
737 return defined('AK_INSECURE_APP_DIRECTORY_LAYOUT') && AK_INSECURE_APP_DIRECTORY_LAYOUT ?
'public' : '';
740 function removeSetupFiles()
742 @array_map
(array('Ak','file_delete'), array(
743 AK_APP_DIR
.DS
.'installers'.DS
.'database_installer.php',
744 AK_APP_DIR
.DS
.'installers'.DS
.'framework_installer.php',
745 AK_APP_DIR
.DS
.'installers'.DS
.'database_version.txt',
746 AK_APP_DIR
.DS
.'installers'.DS
.'framework_version.txt',
747 AK_APP_DIR
.DS
.'models'.DS
.'framework_setup.php',
748 AK_APP_DIR
.DS
.'controllers'.DS
.'framework_setup_controller.php'
750 @array_map
(array('Ak','directory_delete'), array(
751 AK_APP_DIR
.DS
.'views'.DS
.'framework_setup',
752 AK_APP_DIR
.DS
.'locales'.DS
.'framework_setup'