--- /dev/null
+<?php
+/**
+ * Shaarli (application) utilities
+ */
+class ApplicationUtils
+{
+
+ /**
+ * Checks Shaarli has the proper access permissions to its resources
+ *
+ * @param array $globalConfig The $GLOBALS['config'] array
+ *
+ * @return array A list of the detected configuration issues
+ */
+ public static function checkResourcePermissions($globalConfig)
+ {
+ $errors = array();
+
+ // Check script and template directories are readable
+ foreach (array(
+ 'application',
+ 'inc',
+ 'plugins',
+ $globalConfig['RAINTPL_TPL']
+ ) as $path) {
+ if (! is_readable(realpath($path))) {
+ $errors[] = '"'.$path.'" directory is not readable';
+ }
+ }
+
+ // Check cache and data directories are readable and writeable
+ foreach (array(
+ $globalConfig['CACHEDIR'],
+ $globalConfig['DATADIR'],
+ $globalConfig['PAGECACHE'],
+ $globalConfig['RAINTPL_TMP']
+ ) as $path) {
+ if (! is_readable(realpath($path))) {
+ $errors[] = '"'.$path.'" directory is not readable';
+ }
+ if (! is_writable(realpath($path))) {
+ $errors[] = '"'.$path.'" directory is not writable';
+ }
+ }
+
+ // Check configuration files are readable and writeable
+ foreach (array(
+ $globalConfig['CONFIG_FILE'],
+ $globalConfig['DATASTORE'],
+ $globalConfig['IPBANS_FILENAME'],
+ $globalConfig['LOG_FILE'],
+ $globalConfig['UPDATECHECK_FILENAME']
+ ) as $path) {
+ if (! is_file(realpath($path))) {
+ # the file may not exist yet
+ continue;
+ }
+
+ if (! is_readable(realpath($path))) {
+ $errors[] = '"'.$path.'" file is not readable';
+ }
+ if (! is_writable(realpath($path))) {
+ $errors[] = '"'.$path.'" file is not writable';
+ }
+ }
+
+ return $errors;
+ }
+}
--- /dev/null
+<?php
+/**
+ * Exception class thrown when a filesystem access failure happens
+ */
+class IOException extends Exception
+{
+ private $path;
+
+ /**
+ * Construct a new IOException
+ *
+ * @param string $path path to the ressource that cannot be accessed
+ */
+ public function __construct($path)
+ {
+ $this->path = $path;
+ $this->message = 'Error accessing '.$this->path;
+ }
+}
$this->_links[$link['linkdate']] = $link;
// Write database to disk
- // TODO: raise an exception if the file is not write-able
- file_put_contents(
- $this->_datastore,
- self::$phpPrefix.base64_encode(gzdeflate(serialize($this->_links))).self::$phpSuffix
- );
+ $this->writeDB();
}
/**
}
}
+ /**
+ * Saves the database from memory to disk
+ *
+ * @throws IOException the datastore is not writable
+ */
+ private function writeDB()
+ {
+ if (is_file($this->_datastore) && !is_writeable($this->_datastore)) {
+ // The datastore exists but is not writeable
+ throw new IOException($this->_datastore);
+ } else if (!is_file($this->_datastore) && !is_writeable(dirname($this->_datastore))) {
+ // The datastore does not exist and its parent directory is not writeable
+ throw new IOException(dirname($this->_datastore));
+ }
+
+ file_put_contents(
+ $this->_datastore,
+ self::$phpPrefix.base64_encode(gzdeflate(serialize($this->_links))).self::$phpSuffix
+ );
+
+ }
+
/**
* Saves the database from memory to disk
*
// TODO: raise an Exception instead
die('You are not authorized to change the database.');
}
- file_put_contents(
- $this->_datastore,
- self::$phpPrefix.base64_encode(gzdeflate(serialize($this->_links))).self::$phpSuffix
- );
+
+ $this->writeDB();
+
invalidateCaches($pageCacheDir);
}
// Banned IPs
$GLOBALS['config']['IPBANS_FILENAME'] = $GLOBALS['config']['DATADIR'].'/ipbans.php';
+// Access log
+$GLOBALS['config']['LOG_FILE'] = $GLOBALS['config']['DATADIR'].'/log.txt';
+
// For updates check of Shaarli
$GLOBALS['config']['UPDATECHECK_FILENAME'] = $GLOBALS['config']['DATADIR'].'/lastupdatecheck.txt';
// Raintpl template directory (keep the trailing slash!)
$GLOBALS['config']['RAINTPL_TPL'] = 'tpl/';
-// Thuumbnail cache directory
+// Thumbnail cache directory
$GLOBALS['config']['CACHEDIR'] = 'cache';
// Atom & RSS feed cache directory
}
// Shaarli library
+require_once 'application/ApplicationUtils.php';
require_once 'application/Cache.php';
require_once 'application/CachedPage.php';
+require_once 'application/FileUtils.php';
require_once 'application/HttpUtils.php';
require_once 'application/LinkDB.php';
require_once 'application/TimeZone.php';
// Ensure the PHP version is supported
try {
checkPHPVersion('5.3', PHP_VERSION);
-} catch(Exception $e) {
+} catch(Exception $exc) {
header('Content-Type: text/plain; charset=utf-8');
- echo $e->getMessage();
+ echo $exc->getMessage();
exit;
}
header("Cache-Control: post-check=0, pre-check=0", false);
header("Pragma: no-cache");
-// Directories creations (Note that your web host may require different rights than 705.)
-if (!is_writable(realpath(dirname(__FILE__)))) die('<pre>ERROR: Shaarli does not have the right to write in its own directory.</pre>');
-
// Handling of old config file which do not have the new parameters.
if (empty($GLOBALS['title'])) $GLOBALS['title']='Shared links on '.escape(index_url($_SERVER));
if (empty($GLOBALS['timezone'])) $GLOBALS['timezone']=date_default_timezone_get();
if (empty($GLOBALS['titleLink'])) $GLOBALS['titleLink']='?';
// I really need to rewrite Shaarli with a proper configuation manager.
-// Run config screen if first run:
if (! is_file($GLOBALS['config']['CONFIG_FILE'])) {
+ // Ensure Shaarli has proper access to its resources
+ $errors = ApplicationUtils::checkResourcePermissions($GLOBALS['config']);
+
+ if ($errors != array()) {
+ $message = '<p>Insufficient permissions:</p><ul>';
+
+ foreach ($errors as $error) {
+ $message .= '<li>'.$error.'</li>';
+ }
+ $message .= '</ul>';
+
+ header('Content-Type: text/html; charset=utf-8');
+ echo $message;
+ exit;
+ }
+
+ // Display the installation form if no existing config is found
install();
}
function logm($message)
{
$t = strval(date('Y/m/d_H:i:s')).' - '.$_SERVER["REMOTE_ADDR"].' - '.strval($message)."\n";
- file_put_contents($GLOBALS['config']['DATADIR'].'/log.txt',$t,FILE_APPEND);
+ file_put_contents($GLOBAL['config']['LOG_FILE'], $t, FILE_APPEND);
}
// In a string, converts URLs to clickable links.
$value['tags']=trim(implode(' ',$tags));
$LINKSDB[$key]=$value;
}
- $LINKSDB->savedb($GLOBALS['config']['PAGECACHE']); // Save to disk.
+ $LINKSDB->savedb($GLOBALS['config']['PAGECACHE']);
echo '<script>alert("Tag was removed from '.count($linksToAlter).' links.");document.location=\'?\';</script>';
exit;
}
--- /dev/null
+<?php
+/**
+ * ApplicationUtils' tests
+ */
+
+require_once 'application/ApplicationUtils.php';
+
+
+/**
+ * Unitary tests for Shaarli utilities
+ */
+class ApplicationUtilsTest extends PHPUnit_Framework_TestCase
+{
+ /**
+ * Checks resource permissions for the current Shaarli installation
+ */
+ public function testCheckCurrentResourcePermissions()
+ {
+ $config = array(
+ 'CACHEDIR' => 'cache',
+ 'CONFIG_FILE' => 'data/config.php',
+ 'DATADIR' => 'data',
+ 'DATASTORE' => 'data/datastore.php',
+ 'IPBANS_FILENAME' => 'data/ipbans.php',
+ 'LOG_FILE' => 'data/log.txt',
+ 'PAGECACHE' => 'pagecache',
+ 'RAINTPL_TMP' => 'tmp',
+ 'RAINTPL_TPL' => 'tpl',
+ 'UPDATECHECK_FILENAME' => 'data/lastupdatecheck.txt'
+ );
+ $this->assertEquals(
+ array(),
+ ApplicationUtils::checkResourcePermissions($config)
+ );
+ }
+
+ /**
+ * Checks resource permissions for a non-existent Shaarli installation
+ */
+ public function testCheckCurrentResourcePermissionsErrors()
+ {
+ $config = array(
+ 'CACHEDIR' => 'null/cache',
+ 'CONFIG_FILE' => 'null/data/config.php',
+ 'DATADIR' => 'null/data',
+ 'DATASTORE' => 'null/data/store.php',
+ 'IPBANS_FILENAME' => 'null/data/ipbans.php',
+ 'LOG_FILE' => 'null/data/log.txt',
+ 'PAGECACHE' => 'null/pagecache',
+ 'RAINTPL_TMP' => 'null/tmp',
+ 'RAINTPL_TPL' => 'null/tpl',
+ 'UPDATECHECK_FILENAME' => 'null/data/lastupdatecheck.txt'
+ );
+ $this->assertEquals(
+ array(
+ '"null/tpl" directory is not readable',
+ '"null/cache" directory is not readable',
+ '"null/cache" directory is not writable',
+ '"null/data" directory is not readable',
+ '"null/data" directory is not writable',
+ '"null/pagecache" directory is not readable',
+ '"null/pagecache" directory is not writable',
+ '"null/tmp" directory is not readable',
+ '"null/tmp" directory is not writable'
+ ),
+ ApplicationUtils::checkResourcePermissions($config)
+ );
+ }
+}
*/
require_once 'application/Cache.php';
+require_once 'application/FileUtils.php';
require_once 'application/LinkDB.php';
require_once 'application/Utils.php';
require_once 'tests/utils/ReferenceLinkDB.php';
/**
* Attempt to instantiate a LinkDB whereas the datastore is not writable
*
- * @expectedException PHPUnit_Framework_Error_Warning
- * @expectedExceptionMessageRegExp /failed to open stream: No such file or directory/
+ * @expectedException IOException
+ * @expectedExceptionMessageRegExp /Error accessing null/
*/
public function testConstructDatastoreNotWriteable()
{