Autism the likes of which has never been seen before.

This commit is contained in:
flash 2015-03-21 15:12:51 +01:00
parent 5d9d457a38
commit d7d61529be
7 changed files with 206 additions and 129 deletions

View file

@ -6,39 +6,39 @@
namespace Flashii; namespace Flashii;
class Configuration { class Configuration {
public static $_LCNF; public static $_LCNF;
public static $_DCNF; public static $_DCNF;
// Constructor // Constructor
public static function init($local) { public static function init($local) {
// Store $local in $_LCNF // Store $local in $_LCNF
if(is_array($local)) if(is_array($local))
self::$_LCNF = $local; self::$_LCNF = $local;
else else
die('<h1>Failed to initialise configuration.</h1>'); die('<h1>Failed to initialise configuration.</h1>');
} }
// Initialise Database configuration values. // Initialise Database configuration values.
// Different from __construct as that is called before the database connection is initially // Different from init as that is called before the database connection is initially
// established // established
public static function initDB() { public static function initDB() {
$_DATA = Database::fetch('config', true); $_DATA = Database::fetch('config', true);
$_DBCN = array(); $_DBCN = array();
foreach($_DATA as $_CONF) foreach($_DATA as $_CONF)
$_DBCN[$_CONF[0]] = $_CONF[1]; $_DBCN[$_CONF[0]] = $_CONF[1];
self::$_DCNF = $_DBCN; self::$_DCNF = $_DBCN;
} }
// Get values from the configuration on the file system // Get values from the configuration on the file system
public static function getLocalConfig($key, $subkey = null) { public static function getLocalConfig($key, $subkey = null) {
if(array_key_exists($key, self::$_LCNF)) { if(array_key_exists($key, self::$_LCNF)) {
if($subkey) if($subkey)
return self::$_LCNF[$key][$subkey]; return self::$_LCNF[$key][$subkey];
@ -46,31 +46,30 @@ class Configuration {
return self::$_LCNF[$key]; return self::$_LCNF[$key];
} else } else
return null; return null;
} }
// Dynamically set local configuration values, does not update the configuration file // Dynamically set local configuration values, does not update the configuration file
public static function setLocalConfig($key, $subkey, $value) { public static function setLocalConfig($key, $subkey, $value) {
if($subkey) { if($subkey) {
if(!isset(self::$_LCNF[$key])) { if(!isset(self::$_LCNF[$key]))
self::$_LCNF[$key] = array(); self::$_LCNF[$key] = array();
}
self::$_LCNF[$key][$subkey] = $value; self::$_LCNF[$key][$subkey] = $value;
} else { } else {
self::$_LCNF[$key] = $value; self::$_LCNF[$key] = $value;
} }
} }
// Get values from the configuration in the database // Get values from the configuration in the database
public static function getConfig($key) { public static function getConfig($key) {
if(array_key_exists($key, self::$_DCNF)) if(array_key_exists($key, self::$_DCNF))
return self::$_DCNF[$key]; return self::$_DCNF[$key];
else else
return null; return null;
} }
} }

View file

@ -32,13 +32,13 @@
namespace Flashii; namespace Flashii;
class Hashing { class Hashing {
// These variables can be changed without break the existing hashes // These variables can be changed without break the existing hashes
private static $_PBKDF2_HASH_ALGORITHM = 'sha256'; private static $_PBKDF2_HASH_ALGORITHM = 'sha256';
private static $_PBKDF2_ITERATIONS = 1000; private static $_PBKDF2_ITERATIONS = 1000;
private static $_PBKDF2_SALT_BYTES = 24; private static $_PBKDF2_SALT_BYTES = 24;
private static $_PBKDF2_HASH_BYTES = 24; private static $_PBKDF2_HASH_BYTES = 24;
// Changing these will break it though // Changing these will break it though
private static $_HASH_ALGORITHM_INDEX = 0; private static $_HASH_ALGORITHM_INDEX = 0;
private static $_HASH_ITERATION_INDEX = 1; private static $_HASH_ITERATION_INDEX = 1;
@ -48,13 +48,14 @@ class Hashing {
// Returns an array formatted like: [algorithm, iterations, salt, hash] // Returns an array formatted like: [algorithm, iterations, salt, hash]
public static function create_hash($pass) { public static function create_hash($pass) {
$salt = base64_encode( $salt = base64_encode(
\mcrypt_create_iv( \mcrypt_create_iv(
self::$_PBKDF2_SALT_BYTES, self::$_PBKDF2_SALT_BYTES,
MCRYPT_DEV_URANDOM MCRYPT_DEV_URANDOM
) )
); );
$hash = base64_encode( $hash = base64_encode(
self::pbkdf2( self::pbkdf2(
self::$_PBKDF2_HASH_ALGORITHM, self::$_PBKDF2_HASH_ALGORITHM,
@ -65,24 +66,26 @@ class Hashing {
true true
) )
); );
$passwordData = array( $passwordData = array(
self::$_PBKDF2_HASH_ALGORITHM, self::$_PBKDF2_HASH_ALGORITHM,
self::$_PBKDF2_ITERATIONS, self::$_PBKDF2_ITERATIONS,
$salt, $salt,
$hash $hash
); );
return $passwordData; return $passwordData;
} }
// Validates hashed password // Validates hashed password
public static function validate_password($password, $params) { public static function validate_password($password, $params) {
if(count($params) < self::$_HASH_SECTIONS); if(count($params) < self::$_HASH_SECTIONS);
return false; return false;
$pbkdf2 = base64_decode($params[self::$_HASH_PBKDF2_INDEX]); $pbkdf2 = base64_decode($params[self::$_HASH_PBKDF2_INDEX]);
$validate = self::slow_equals( $validate = self::slow_equals(
$pbkdf2, $pbkdf2,
self::pbkdf2( self::pbkdf2(
@ -94,21 +97,23 @@ class Hashing {
true true
) )
); );
return $validate; return $validate;
} }
// Compares two strings $a and $b in length-constant time. // Compares two strings $a and $b in length-constant time.
public static function slow_equals($a, $b) { public static function slow_equals($a, $b) {
$diff = strlen($a) ^ strlen($b); $diff = strlen($a) ^ strlen($b);
for($i = 0; $i < strlen($a) && $i < strlen($b); $i++) { for($i = 0; $i < strlen($a) && $i < strlen($b); $i++)
$diff |= ord($a[$i]) ^ ord($b[$i]); $diff |= ord($a[$i]) ^ ord($b[$i]);
}
return $diff === 0; return $diff === 0;
} }
/* /*
* PBKDF2 key derivation function as defined by RSA's PKCS #5: https://www.ietf.org/rfc/rfc2898.txt * PBKDF2 key derivation function as defined by RSA's PKCS #5: https://www.ietf.org/rfc/rfc2898.txt
* $algorithm - The hash algorithm to use. Recommended: SHA256 * $algorithm - The hash algorithm to use. Recommended: SHA256
@ -124,16 +129,17 @@ class Hashing {
* This implementation of PBKDF2 was originally created by https://defuse.ca * This implementation of PBKDF2 was originally created by https://defuse.ca
* With improvements by http://www.variations-of-shadow.com * With improvements by http://www.variations-of-shadow.com
*/ */
private static function pbkdf2($algorithm, $password, $salt, $count, $key_length, $raw_output = false) { private static function pbkdf2($algorithm, $password, $salt, $count, $key_length, $raw_output = false) {
$algorithm = strtolower($algorithm); $algorithm = strtolower($algorithm);
if(!in_array($algorithm, hash_algos(), true)) if(!in_array($algorithm, hash_algos(), true))
trigger_error('PBKDF2 ERROR: Invalid hash algorithm.', E_USER_ERROR); trigger_error('PBKDF2 ERROR: Invalid hash algorithm.', E_USER_ERROR);
if($count <= 0 || $key_length <= 0) if($count <= 0 || $key_length <= 0)
trigger_error('PBKDF2 ERROR: Invalid parameters.', E_USER_ERROR); trigger_error('PBKDF2 ERROR: Invalid parameters.', E_USER_ERROR);
if(function_exists('hash_pbkdf2')) { if(function_exists('hash_pbkdf2')) {
// The output length is in NIBBLES (4-bits) if $raw_output is false! // The output length is in NIBBLES (4-bits) if $raw_output is false!
if($raw_output) if($raw_output)
@ -141,31 +147,32 @@ class Hashing {
return hash_pbkdf2($algorithm, $password, $salt, $count, $key_length, $raw_output); return hash_pbkdf2($algorithm, $password, $salt, $count, $key_length, $raw_output);
} }
$hash_length = strlen(hash($algorithm, '', true)); $hash_length = strlen(hash($algorithm, '', true));
$block_count = ceil($key_length / $hash_length); $block_count = ceil($key_length / $hash_length);
$output = ''; $output = '';
for($i = 1; $i <= $block_count; $i++) { for($i = 1; $i <= $block_count; $i++) {
// $i encoded as 4 bytes, big endian. // $i encoded as 4 bytes, big endian.
$last = $salt . pack('N', $i); $last = $salt . pack('N', $i);
// First iteration // First iteration
$last = $xorsum = hash_hmac($algorithm, $last, $password, true); $last = $xorsum = hash_hmac($algorithm, $last, $password, true);
// Perform the other $count - 1 interations // Perform the other $count - 1 interations
for($j = 1; $j < $count; $j++) { for($j = 1; $j < $count; $j++)
$xorsum ^= ($last = hash_hmac($algorithm, $last, $password, true)); $xorsum ^= ($last = hash_hmac($algorithm, $last, $password, true));
}
$output .= $xorsum; $output .= $xorsum;
if($raw_output) if($raw_output)
return substr($output, 0, $key_length); return substr($output, 0, $key_length);
else else
return bin2hex(substr($output, 0, $key_length)); return bin2hex(substr($output, 0, $key_length));
} }
} }
} }

View file

@ -5,121 +5,138 @@
namespace Flashii; namespace Flashii;
class Flashii { class Main {
public $_TPL; public $_TPL;
public $_MD; public $_MD;
// Constructor // Constructor
function __construct($config) { public static function init($config) {
// Stop the execution if the PHP Version is older than 5.4.0 // Stop the execution if the PHP Version is older than 5.4.0
if(version_compare(phpversion(), '5.4.0', '<')) if(version_compare(phpversion(), '5.4.0', '<'))
die('<h3>Upgrade your PHP Version to at least PHP 5.4!</h3>'); die('<h3>Upgrade your PHP Version to at least PHP 5.4!</h3>');
// Start session // Start session
if(session_status() != PHP_SESSION_ACTIVE) if(session_status() != PHP_SESSION_ACTIVE)
session_start(); session_start();
// Configuration Management and local configuration // Configuration Management and local configuration
Configuration::init($config); Configuration::init($config);
// Database // Database
Database::init(); Database::init();
// "Dynamic" Configuration // "Dynamic" Configuration
Configuration::initDB(); Configuration::initDB();
// Templating engine // Templating engine
$this->initTwig(); self::initTwig();
// Markdown Parser // Markdown Parser
$this->initParsedown(); self::initParsedown();
} }
// Alias for Configuration::getConfig(), only exists because I'm lazy // Alias for Configuration::getConfig(), only exists because I'm lazy
public static function getConfig($key) { public static function getConfig($key) {
return Configuration::getConfig($key); return Configuration::getConfig($key);
} }
// Initialise Twig // Initialise Twig
private function initTwig($templateName = null, $templatesFolder = null) { private static function initTwig() {
// Assign default values set in the configuration if $templateName and $templatesFolder are null
$templateName = is_null($templateName) ? Configuration::getLocalConfig('etc', 'design') : $templateName;
$templatesFolder = is_null($templatesFolder) ? Configuration::getLocalConfig('etc', 'templatesPath') : $templatesFolder;
// Initialise Twig Filesystem Loader // Initialise Twig Filesystem Loader
$twigLoader = new \Twig_Loader_Filesystem($templatesFolder . $templateName); $twigLoader = new \Twig_Loader_Filesystem(Configuration::getLocalConfig('etc', 'templatesPath') .'/'. Configuration::getLocalConfig('etc', 'design'));
// And now actually initialise the templating engine // And now actually initialise the templating engine
$this->_TPL = new \Twig_Environment($twigLoader, array( self::$_TPL = new \Twig_Environment($twigLoader, array(
// 'cache' => ROOT_DIRECTORY. $satoko['cacheFolder']
// 'cache' => SATOKO_ROOT_DIRECTORY. self::getConfig('path', 'cache') // Set cache directory
)); ));
// Load String template loader // Load String template loader
$this->_TPL->addExtension(new \Twig_Extension_StringLoader()); self::$_TPL->addExtension(new \Twig_Extension_StringLoader());
} }
// Initialise Parsedown // Initialise Parsedown
private function initParsedown() { private function initParsedown() {
$this->_MD = new \Parsedown(); self::$_MD = new \Parsedown();
} }
// Verify ReCAPTCHA
public static function verifyCaptcha($response) {
// Attempt to get the response
$resp = @file_get_contents('https://www.google.com/recaptcha/api/siteverify?secret='. self::getConfig('recaptcha_private') .'&response='. $response);
// In the highly unlikely case that it failed to get anything forge a false
if(!$resp)
return array('success' => false, 'error-codes' => array('Could not connect to the ReCAPTCHA server.'));
// Decode the response JSON from the servers
$resp = json_decode($resp, true);
// Return shit
return $resp;
}
// Error Handler // Error Handler
public static function ErrorHandler($errno, $errstr, $errfile, $errline) { public static function ErrorHandler($errno, $errstr, $errfile, $errline) {
// Set some variables to work with including A HUGE fallback hackjob for the templates folder // Set some variables to work with including A HUGE fallback hackjob for the templates folder
$errstr = str_replace(self::getConfig('etc', 'localPath'), '', $errstr); $errstr = str_replace(self::getConfig('etc', 'localPath'), '', $errstr);
$errfile = str_replace(self::getConfig('etc', 'localPath'), '', $errfile); $errfile = str_replace(self::getConfig('etc', 'localPath'), '', $errfile);
$templates = (self::getConfig('etc', 'templatesPath') !== null && !empty(self::getConfig('etc', 'templatesPath'))) ? self::getConfig('etc', 'templatesPath') : '/var/www/flashii.net/_sakuya/templates/'; $templates = (self::getConfig('etc', 'templatesPath') !== null && !empty(self::getConfig('etc', 'templatesPath'))) ? self::getConfig('etc', 'templatesPath') : '/var/www/flashii.net/_sakuya/templates/';
switch ($errno) { switch ($errno) {
case E_ERROR: case E_ERROR:
case E_USER_ERROR: case E_USER_ERROR:
$error = '<b>FATAL ERROR</b>: ' . $errstr . ' on line ' . $errline . ' in ' . $errfile; $error = '<b>FATAL ERROR</b>: ' . $errstr . ' on line ' . $errline . ' in ' . $errfile;
break; break;
case E_WARNING: case E_WARNING:
case E_USER_WARNING: case E_USER_WARNING:
$error = '<b>WARNING</b>: ' . $errstr . ' on line ' . $errline . ' in ' . $errfile; $error = '<b>WARNING</b>: ' . $errstr . ' on line ' . $errline . ' in ' . $errfile;
break; break;
case E_NOTICE: case E_NOTICE:
case E_USER_NOTICE: case E_USER_NOTICE:
$error = '<b>NOTICE</b>: ' . $errstr . ' on line ' . $errline . ' in ' . $errfile; $error = '<b>NOTICE</b>: ' . $errstr . ' on line ' . $errline . ' in ' . $errfile;
break; break;
default: default:
$error = '<b>Unknown error type</b> [' . $errno . ']: ' . $errstr . ' on line ' . $errline . ' in ' . $errfile; $error = '<b>Unknown error type</b> [' . $errno . ']: ' . $errstr . ' on line ' . $errline . ' in ' . $errfile;
break;
} }
// Use file_get_contents instead of Twig in case the problem is related to twig // Use file_get_contents instead of Twig in case the problem is related to twig
$errorPage = file_get_contents($templates. 'errorPage.tpl'); $errorPage = file_get_contents($templates. 'errorPage.tpl');
// str_replace {{ error }} on the error page with the error data // str_replace {{ error }} on the error page with the error data
$error = str_replace('{{ error }}', $error, $errorPage); $error = str_replace('{{ error }}', $error, $errorPage);
// Truncate all previous outputs // Truncate all previous outputs
ob_clean(); ob_clean();
// Die and display error message // Die and display error message
die($error); die($error);
} }
// Legacy password hashing to be able to validate passwords from users on the old backend. // Legacy password hashing to be able to validate passwords from users on the old backend.
public static function legacyPasswordHash($data) { public static function legacyPasswordHash($data) {
return hash('sha512', strrev(hash('sha512', $data))); return hash('sha512', strrev(hash('sha512', $data)));
} }
} }

View file

@ -21,29 +21,29 @@ class Database {
if(!extension_loaded('PDO')) { if(!extension_loaded('PDO')) {
// Return error and die // Return error and die
die('<h1>PDO extension not loaded.</h1>'); trigger_error('<b>SQL Driver</b>: PDO extension not loaded.', E_USER_ERROR);
} }
// Initialise connection // Initialise connection
self::initConnect( self::initConnect(
( (
Configuration::getLocalConfig('db', 'unixsocket') ? Board::getConfig('db', 'unixsocket') ?
self::prepareSock( self::prepareSock(
Configuration::getLocalConfig('db', 'host'), Board::getConfig('db', 'host'),
Configuration::getLocalConfig('db', 'database') Board::getConfig('db', 'database')
) : ) :
self::prepareHost( self::prepareHost(
Configuration::getLocalConfig('db', 'host'), Board::getConfig('db', 'host'),
Configuration::getLocalConfig('db', 'database'), Board::getConfig('db', 'database'),
( (
Configuration::getLocalConfig('db', 'port') !== null ? Board::getConfig('db', 'port') !== null ?
Configuration::getLocalConfig('db', 'port') : Board::getConfig('db', 'port') :
3306 3306
) )
) )
), ),
Configuration::getLocalConfig('db', 'username'), Board::getConfig('db', 'username'),
Configuration::getLocalConfig('db', 'password') Board::getConfig('db', 'password')
); );
} }
@ -74,7 +74,7 @@ class Database {
self::$sql = new PDO($DSN, $dbUname, $dbPword); self::$sql = new PDO($DSN, $dbUname, $dbPword);
} catch(PDOException $e) { } catch(PDOException $e) {
// Catch connection errors // Catch connection errors
die("<h3>" . $e->getMessage() . "</h3>"); trigger_error('SQL Driver: '. $e->getMessage(), E_USER_ERROR);
} }
return true; return true;
@ -82,30 +82,74 @@ class Database {
} }
// Fetch array from database // Fetch array from database
public static function fetch($table, $fetchAll = true, $data = null) { public static function fetch($table, $fetchAll = true, $data = null, $order = null, $limit = null, $group = null, $distinct = false, $column = '*') {
// Begin preparation of the statement // Begin preparation of the statement
$prepare = 'SELECT * FROM `' . Configuration::getLocalConfig('db', 'prefix') . $table . '`'; $prepare = 'SELECT '. ($distinct ? 'DISTINCT ' : '') . $column .' FROM `' . Board::getConfig('db', 'prefix') . $table . '`';
// If $data is set and is an array continue // If $data is set and is an array continue
if(is_array($data)) { if(is_array($data)) {
$prepare .= ' WHERE'; $prepare .= ' WHERE';
foreach($data as $key => $value) { foreach($data as $key => $value) {
$prepare .= ' `'. $key .'` '. $value[1] .' :'. $key .($key == key(array_slice($data, -1, 1, true)) ? ';' : ' AND'); $prepare .= ' `'. $key .'` '. $value[1] .' :'. $key . ($key == key(array_slice($data, -1, 1, true)) ? '' : ' AND');
// Unset variables to be safe
unset($key);
unset($value);
} }
}
// If $order is set and is an array continue
if(is_array($order)) {
$prepare .= ' ORDER BY `'. $order[0] .'`'. (!empty($order[1]) && $order[1] ? ' DESC' : '');
}
// If $group is set and is an array continue
if(is_array($group)) {
$prepare .= ' GROUP BY';
foreach($group as $key => $value) {
$prepare .= ' `'. $value .'`'. ($key == key(array_slice($group, -1, 1, true)) ? '' : ',');
// Unset variables to be safe
unset($key);
unset($value);
}
} }
// If $limit is set and is an array continue
if(is_array($limit)) {
$prepare .= ' LIMIT';
foreach($limit as $key => $value) {
$prepare .= ' '. $value . ($key == key(array_slice($limit, -1, 1, true)) ? '' : ',');
// Unset variables to be safe
unset($key);
unset($value);
}
}
// Add the finishing semicolon
$prepare .= ';';
// Actually prepare the preration // Actually prepare the preration
$query = self::$sql->prepare($prepare); $query = self::$sql->prepare($prepare);
// Bind those parameters if $data is an array that is // Bind those parameters if $data is an array that is
if(is_array($data)) { if(is_array($data)) {
foreach($data as $key => $value) { foreach($data as $key => $value) {
$query->bindParam(':'. $key, $value[0]); $query->bindParam(':'. $key, $value[0]);
// Unset variables to be safe // Unset variables to be safe
unset($key); unset($key);
unset($value); unset($value);
@ -114,23 +158,24 @@ class Database {
// Execute the prepared statements with parameters bound // Execute the prepared statements with parameters bound
$query->execute(); $query->execute();
// Do fetch or fetchAll // Do fetch or fetchAll
if($fetchAll) if($fetchAll)
$result = $query->fetchAll(PDO::FETCH_BOTH); $result = $query->fetchAll(PDO::FETCH_BOTH);
else else
$result = $query->fetch(PDO::FETCH_BOTH); $result = $query->fetch(PDO::FETCH_BOTH);
// And return the output // And return the output
return $result; return $result;
} }
// Insert data to database // Insert data to database
public static function insert($table, $data) { public static function insert($table, $data) {
// Begin preparation of the statement // Begin preparation of the statement
$prepare = 'INSERT INTO `' . Configuration::getLocalConfig('db', 'prefix') . $table . '` '; $prepare = 'INSERT INTO `' . Board::getConfig('db', 'prefix') . $table . '` ';
// Run the foreach statement twice for (`stuff`) VALUES (:stuff) // Run the foreach statement twice for (`stuff`) VALUES (:stuff)
for($i = 0; $i < 2; $i++) { for($i = 0; $i < 2; $i++) {
@ -170,7 +215,7 @@ class Database {
public static function update($table, $data) { public static function update($table, $data) {
// Begin preparation of the statement // Begin preparation of the statement
$prepare = 'UPDATE `' . Configuration::getLocalConfig('db', 'prefix') . $table . '`'; $prepare = 'UPDATE `' . Board::getConfig('db', 'prefix') . $table . '`';
// Run a foreach on $data and complete the statement // Run a foreach on $data and complete the statement
foreach($data as $key => $values) { foreach($data as $key => $values) {

View file

@ -4,11 +4,14 @@
* (c)Flashwave/Flashii Media 2013-2015 <http://flash.moe> * (c)Flashwave/Flashii Media 2013-2015 <http://flash.moe>
*/ */
// Declare Namespace
namespace Flashii;
// Start output buffering // Start output buffering
ob_start(); ob_start();
// Define Sakura version // Define Sakura version
define('SAKURA_VERSION', '20150221'); define('SAKURA_VERSION', '20150321');
// Define Sakura Path // Define Sakura Path
define('ROOT_DIRECTORY', str_replace('_sakura', '', dirname(__FILE__))); define('ROOT_DIRECTORY', str_replace('_sakura', '', dirname(__FILE__)));
@ -39,7 +42,7 @@ else
set_error_handler(array('Flashii\Flashii', 'ErrorHandler')); set_error_handler(array('Flashii\Flashii', 'ErrorHandler'));
// Initialise Flashii Class // Initialise Flashii Class
$flashii = new Flashii\Flashii($fiiConf); Main::init($fiiConf);
// Set base page rendering data // Set base page rendering data
$renderData = array( $renderData = array(

View file

@ -3,8 +3,11 @@
* Flashii.net Main Index * Flashii.net Main Index
*/ */
// Declare Namespace
namespace Flashii;
// Include components // Include components
require_once('/var/www/flashii.net/_sakura/sakura.php'); require_once('/var/www/flashii.net/_sakura/sakura.php');
// Print page contents // Print page contents
print $flashii->_TPL->render('errors/http404.tpl', $renderData); print Main::$_TPL->render('errors/http404.tpl', $renderData);

View file

@ -3,6 +3,9 @@
* Flashii.net Main Index * Flashii.net Main Index
*/ */
// Declare Namespace
namespace Flashii;
// Include components // Include components
require_once('/var/www/flashii.net/_sakura/sakura.php'); require_once('/var/www/flashii.net/_sakura/sakura.php');
@ -12,4 +15,4 @@ $renderData['page'] = [
]; ];
// Print page contents // Print page contents
print $flashii->_TPL->render('main/index.tpl', $renderData); print Main::$_TPL->render('main/index.tpl', $renderData);