header { background: #999; margin: -2em -2em 1em -2em; border-radius: .5em; overflow: hidden; border-bottom: .2em solid #666; text-align: center; } #global > header h1 { font-weight: normal; font-size: 400%; margin: -.2em; } #global > header h1 a { color: #666; text-decoration: none; display: block; } #global > header h1 a:hover { color: #fff; transition: .5s; } #global > header h2 { font-weight: normal; } #global > footer { border-top: .2em solid #666; padding: .5em; font-size: 0.9em; color: #ccc; margin: 1em -2em -2em -2em; border-radius: .5em; background: #999; } #global > footer a { color: #fff; } #global > footer form { float: right; } #global > footer form p { display: inline; } input, textarea { padding: .2em; } fieldset input[type=text], fieldset textarea { width: 99%; } fieldset dt { margin: .5em 0; } fieldset dd { margin-left: 1em; } a.rss { background: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAA4AAAAOBAMAAADtZjDiAAAABGdBTUEAAK/INwWK6QAAADBQTFRF200A2kwA20wA10sA22Mi54Mg8ogf5Hgi+Jo49tq9445J8L+U6Ykz559o3E0A////BRDeewAAAAR0Uk5Ti+zi8Y/BLYAAAAB4SURBVAjXY2BQFBISFFRgYPG9VZPT1sDwZP3/nys6+hhM1t6e/xtIi/uuOTt/BpC//uedmz/yGMRX7/+d9TuPQeZM1Pyr+/MYTNPSzk+9v47BfP+06D/37zGY//8W/ev+PgbT/duirqzyY1BNSwsvcXFiYHoHAgwAS6I2i3LYZakAAAAASUVORK5CYII=") no-repeat left center; padding-left: 20px; } .powered { font-size: .9em; } fieldset { border: .1em solid #999; border-radius: .5em; padding: .5em 1em; margin: 1em; } #content header { text-align: center; margin: 1em 0; } #content header a { color: inherit; text-decoration: inherit; } #content article .content { max-width: 60em; margin: 1em auto; } #content footer { text-align: center; font-size: .9em; } .admin { color: red !important; background: yellow; padding: .2em .5em; display: inline-block; border-radius: .5em; } .tips, .error { background: #ddd; border-radius: .5em; padding: 1em; text-align: center; } dl.tips dt { font-weight: bold; } dl.tips dd { margin: 0.5em; } .error { color: red; font-size: 200%; } .content p, .content ul, .content ol, .content pre, .content blockquote, .content table, .content h1, .content h2, .content h3, .content h4, .content h5, .content h6 { margin: .5em 0; line-height: 120%; } .content ul, .content ol { margin-left: 2em; } .content sub, .content sup { line-height: 0; font-size: .8em; } .content table, .content tr, .content th, .content td { border: 1px solid #999; border-collapse: collapse; padding: .2em; background: #fff; } .content table th { background: #ddd; } .content .footnotes, .content pre, .content blockquote { background: #ddd; border-radius: .5em; padding: .5em; } .content .footnotes { font-size: .9em; margin-top: 1.5em; } .content hr { border: 1px solid #999; } @media screen and (max-width: 800px), handheld { #global > footer { text-align: center; } #global > footer form { float: none; } #global > footer form p { display: block; margin: .5em; } } CSS_EOF; // Serve the default stylesheet if (!empty($_SERVER['QUERY_STRING']) && $_SERVER['QUERY_STRING'] == 'style.css') { header('Content-Type: text/css'); header('Date: ' . date('D, j M Y G:i:s ') . 'GMT'); header('Content-Type: text/css'); header('Expires: ' . gmdate('D, d M Y H:i:s', time() + 3600*24*365) . ' GMT'); header('Cache-Control: max-age=31536000, must-revalidate'); header('Pragma: cache'); echo $default_css; exit; } class picoBlog { public $file = 'data.json'; public $bypage = 20; public $reverse_order = true; public $title = 'My picoBlog'; public $desc = 'Another useless blog'; public $locale = 'en_AU'; public $date_format = '%A %e %B %Y at %k:%M'; public $url = ''; public $root_url = ''; public $user_login = 'admin'; public $user_password = 'abcd'; public $markup = 'bbcode'; public $skriv = false; protected $posts = []; const VERSION = '2.0.0'; public function __construct() { $this->file = __DIR__ . '/' . $this->file; $this->skriv = file_exists(__DIR__ . '/SkrivLite.php'); $this->getUrl(); } public function login($login, $password) { if ($login != $this->user_login || $password != $this->user_password) return false; @session_start(); $_SESSION['logged'] = true; return true; } public function logout() { @session_start(); $_SESSION = []; } public function isLogged() { @session_start(); if (!empty($_SESSION['logged'])) return true; if (!empty($_SERVER['PHP_AUTH_USER']) && !empty($_SERVER['PHP_AUTH_PW']) && $_SERVER['PHP_AUTH_USER'] == $this->user_login && $_SERVER['PHP_AUTH_PW'] == $this->user_password) { return true; } return false; } public function getUrl($id = null, $title = null) { if (empty($this->url)) { $proto = empty($_SERVER['HTTPS']) ? 'http' : 'https'; $host = !empty($_SERVER['HTTP_HOST']) ? $_SERVER['HTTP_HOST'] : $_SERVER['SERVER_NAME']; $this->url = $proto . '://' . $host . $_SERVER['REQUEST_URI']; $this->url = preg_replace('/[\?&].*$/', '', $this->url); $this->root_url = preg_replace('!/.*?$!', '/', $this->url); } $url = $this->url; if ($id) { $url .= '?' . $this->getUri($id, $title); } return $url; } public function getUri($id = null, $title = null) { return base_convert($id, 10, 36) . '-' . (empty($title) ? 'post' : trim(preg_replace('/[^\w\d_.-]+/u', '-', $title), '-')); } public function formatText($text, $markup = null) { if (is_null($markup)) { $markup = $this->markup; } if ($markup == 'skriv') { if ($this->skriv === true) { require_once __DIR__ . '/SkrivLite.php'; $this->skriv = new \KD2\SkrivLite; } $text = $this->skriv->render($text); } else { $text = htmlspecialchars($text, ENT_QUOTES, 'UTF-8'); // Links on URLs $text = preg_replace('!(?<=\s|^)((ftp|http|https)://([^\s]+))!um', '[url]$1[/url]', $text); // BBCode $text = preg_replace('#(?', $text); $text = preg_replace('#(?\\1', $text); $text = preg_replace('#(?\\1', $text); if ($markup != 'bbcode_comments') { $text = preg_replace_callback('#(?'; }, $text); $text = preg_replace_callback('#(?' . $match[2] . ''; }, $text); } $text = nl2br($text); } return $text; } public function loadData() { if (file_exists($this->file)) { $content = file_get_contents($this->file); $content = json_decode($content, true); if (is_null($content)) throw new Exception('JSON decoding error code: ' . json_last_error()); $this->posts = $content['posts']; unset($content); $this->sortPosts(); return true; } return false; } public function sortPosts($force_reverse = null) { if ($this->reverse_order || $force_reverse) krsort($this->posts); else ksort($this->posts); } public function writeData() { $data = [ 'posts' => $this->posts, ]; return @file_put_contents($this->file, json_encode($data, JSON_PRETTY_PRINT)); } public function getPost($id) { return array_key_exists($id, $this->posts) ? $this->posts[$id] : false; } public function listPosts($begin=0) { return array_slice($this->posts, $begin, $this->bypage, true); } public function editPost($id, $title, $text) { $this->posts[(int)$id] = ['t' => trim($title), 'c' => trim($text)]; } public function deletePost($id) { unset($this->posts[(int)$id]); } public function getPagination() { if (count($this->posts) <= $this->bypage) return false; $pages = ceil(count($this->posts) / $this->bypage); return $pages; } } class picoConf { public $file = 'userconfig.php'; public function __construct() { $this->file = dirname(__FILE__) . '/' . $this->file; } public function write($config) { $out = '$value) { $value = strtr($value, ['$' => '\\$', '"' => '\\"']); $out .= '$pb->'.$key.' = "'.$value."\";\n"; } $out.= '?>'; if (!@file_put_contents($this->file, $out)) return false; return true; } } $pb = new picoBlog; // Loading user config if (file_exists(dirname(__FILE__) . '/userconfig.php')) { require_once dirname(__FILE__) . '/userconfig.php'; } // Migrate post data from PHP array (version 1.0.x) to JSON (1.1.x) if (file_exists(__DIR__ . '/datas.php')) { require __DIR__ . '/datas.php'; $json = [ 'posts' => [], ]; // Convert to UTF-8 if needed foreach ($datas as $id=>$post) { // Clever trick, see http://php.net/manual/en/reference.pcre.pattern.modifiers.php // "UTF-8 validity of the pattern is checked since PHP 4.3.5" (when using /u modifier) if (!preg_match('!!u', $post)) { $post = utf8_encode($post); } $json['posts'][(int)$id] = ['t' => null, 'c' => $post]; } file_put_contents($pb->file, json_encode($json, JSON_PRETTY_PRINT)); unset($datas, $json); echo "
The original posts data store has been renamed to datas_legacy_1.0.x.php.
" . "Wrong login or password. Try again!
'; html_foot(); } // Logout elseif (isset($_GET['logout'])) { $pb->logout(); html_head(); echo 'You have been disconnected.
'; html_foot(); } // User configuration elseif (isset($_GET['config']) AND $pb->isLogged()) { if (__post('save')) { $config = [ 'title' => __post('title'), 'desc' => __post('desc'), 'locale' => preg_match('/^[a-z]{2}_[A-Z]{2}$/', __post('locale')) ? __post('locale') : $pb->locale, 'date_format' => __post('date_format'), 'bypage' => (int) __post('bypage'), 'reverse_order' => (bool) __post('reverse_order'), 'user_login' => __post('user_login'), 'user_password' => __post('user_password'), 'markup' => __post('markup'), ]; $pc = new picoConf; if (!$pc->write($config)) { die("Can't write to ".$pc->file); } header('Location: '.$pb->url); exit; } html_head('Configuration', 'config'); echo 'Can\'t find this post.
'; else { html_post($id, $post); } html_foot(); } // Entries by page else { $page = 1; if (!empty($_SERVER['QUERY_STRING']) && preg_match('/^p([0-9]+)$/', $_SERVER['QUERY_STRING'], $match)) { $page = (int) $match[1]; } $begin = ($page - 1) * $pb->bypage; $list = $pb->listPosts($begin); html_head($pb->title); if ($pb->isLogged()) echo ''; if (empty($list)) echo 'No item.
'; else { foreach ($list as $id=>$post) { html_post($id, $post); } } $pages = $pb->getPagination(); if (!empty($pages)) { echo '