From 732c7d5f6c811f1053f1f92301f5abc625956a04 Mon Sep 17 00:00:00 2001
From: Mitsukarenai
Date: Mon, 22 Apr 2013 12:00:26 +0200
Subject: [PATCH] ??
---
autoblogs/autoblog.php | 908 ++++++++++++++++++++++++++++++++++++
class_rssfeed.php | 277 +++++++++++
config.php | 43 ++
docs/docs.txt | 4 +
functions.php | 302 ++++++++++++
index.php | 926 +++++++++++++++++++++++++++++++++++++
resources/autoblog.css | 48 ++
resources/icon-logo.svg | 218 +++++++++
resources/rss.png | Bin 0 -> 691 bytes
resources/user.css.example | 10 +
version | 1 +
xsaf3.php | 169 +++++++
12 files changed, 2906 insertions(+)
create mode 100644 autoblogs/autoblog.php
create mode 100755 class_rssfeed.php
create mode 100755 config.php
create mode 100644 docs/docs.txt
create mode 100755 functions.php
create mode 100755 index.php
create mode 100644 resources/autoblog.css
create mode 100644 resources/icon-logo.svg
create mode 100644 resources/rss.png
create mode 100644 resources/user.css.example
create mode 100644 version
create mode 100755 xsaf3.php
diff --git a/autoblogs/autoblog.php b/autoblogs/autoblog.php
new file mode 100644
index 0000000..87a8b28
--- /dev/null
+++ b/autoblogs/autoblog.php
@@ -0,0 +1,908 @@
+='))
+ die("This software requires PHP version 5.3.0 at least, yours is ".phpversion());
+
+if (!class_exists('SQLite3'))
+ die("This software requires the SQLite3 PHP extension, and it can't be found on this system!");
+
+libxml_disable_entity_loader(true);
+
+// Config and data file locations
+
+if (file_exists(__DIR__ . '/../config.php')) {
+ require_once __DIR__ . '/../config.php';
+}
+//else die("Configuration file not found.");
+
+if (file_exists(__DIR__ . '/../functions.php')){
+ require_once __DIR__ . '/../functions.php';
+}
+else die("Functions file not found.");
+
+if (!defined('ROOT_DIR'))
+ define('ROOT_DIR', __DIR__);
+
+if (!defined('CONFIG_FILE')) define('CONFIG_FILE', ROOT_DIR . '/vvb.ini');
+if (!defined('ARTICLES_DB_FILE')) define('ARTICLES_DB_FILE', ROOT_DIR . '/articles.db');
+if (!defined('MEDIA_DIR')) define('MEDIA_DIR', ROOT_DIR . '/media');
+
+if (!defined('LOCAL_URL'))
+{
+ // Automagic URL discover
+ define('LOCAL_URL', 'http' . (!empty($_SERVER['HTTPS']) ? 's' : '')."://{$_SERVER['HTTP_HOST']}{$_SERVER['REQUEST_URI']}");
+}
+
+if (!defined('LOCAL_URI'))
+{
+ // filename
+ define('LOCAL_URI', (basename($_SERVER['SCRIPT_FILENAME']) == 'index.php' ? '' : basename($_SERVER['SCRIPT_FILENAME'])) . '?');
+}
+
+if (!function_exists('__'))
+{
+ // Translation?
+ function __($str)
+ {
+ if ($str == '_date_format')
+ return '%A %e %B %Y at %H:%M';
+ else
+ return $str;
+ }
+}
+
+// ERROR MANAGEMENT
+
+class VroumVroum_User_Exception extends Exception {}
+
+class VroumVroum_Feed_Exception extends Exception
+{
+ static public function getXMLErrorsAsString($errors)
+ {
+ $out = array();
+
+ foreach ($errors as $error)
+ {
+ $return = $xml[$error->line - 1] . "\n";
+ $return .= str_repeat('-', $error->column) . "^\n";
+
+ switch ($error->level) {
+ case LIBXML_ERR_WARNING:
+ $return .= "Warning ".$error->code.": ";
+ break;
+ case LIBXML_ERR_ERROR:
+ $return .= "Error ".$error->code.": ";
+ break;
+ case LIBXML_ERR_FATAL:
+ $return .= "Fatal Error ".$error->code.": ";
+ break;
+ }
+
+ $return .= trim($error->message) .
+ "\n Line: ".$error->line .
+ "\n Column: ".$error->column;
+
+ if ($error->file) {
+ $return .= "\n File: ".$error->file;
+ }
+
+ $out[] = $return;
+ }
+
+ return $out;
+ }
+}
+
+error_reporting(E_ALL);
+
+function exception_error_handler($errno, $errstr, $errfile, $errline )
+{
+ // For @ ignored errors
+ if (error_reporting() === 0) return;
+ throw new ErrorException($errstr, 0, $errno, $errfile, $errline);
+}
+
+function exception_handler($e)
+{
+ if ($e instanceOf VroumVroum_User_Exception)
+ {
+ echo ''.$e->getMessage().' ';
+ exit;
+ }
+
+ $error = "Error happened !\n\n".
+ $e->getCode()." - ".$e->getMessage()."\n\nIn: ".
+ $e->getFile() . ":" . $e->getLine()."\n\n";
+
+ if (!empty($_SERVER['HTTP_HOST']))
+ $error .= 'http://'.$_SERVER['HTTP_HOST'].$_SERVER['REQUEST_URI']."\n\n";
+
+ $error .= $e->getTraceAsString();
+ //$error .= print_r($_SERVER, true);
+
+ echo $error;
+ exit;
+}
+
+set_error_handler("exception_error_handler");
+set_exception_handler("exception_handler");
+
+// CONFIGURATION
+
+class VroumVroum_Config
+{
+ public $site_type = '';
+ public $site_title = '';
+ public $site_description = '';
+ public $site_url = '';
+ public $feed_url = '';
+ public $articles_per_page = 10;
+ public $update_interval = 3600;
+ public $update_timeout = 10;
+
+ public function __construct()
+ {
+ if (!file_exists(CONFIG_FILE))
+ throw new VroumVroum_User_Exception("Missing configuration file '".basename(CONFIG_FILE)."'.");
+
+ $ini = parse_ini_file(CONFIG_FILE);
+
+ foreach ($ini as $key=>$value)
+ {
+ $key = strtolower($key);
+
+ if (!property_exists($this, $key))
+ continue; // Unknown config
+
+ if (is_string($this->$key) || is_null($this->$key))
+ $this->$key = trim((string) $value);
+ elseif (is_int($this->$key))
+ $this->$key = (int) $value;
+ elseif (is_bool($this->$key))
+ $this->$key = (bool) $value;
+ }
+
+ // Check that all required values are filled
+ $check = array('site_type', 'site_title', 'site_url', 'feed_url', 'update_timeout', 'update_interval', 'articles_per_page');
+ foreach ($check as $c)
+ {
+ if (!trim($this->$c))
+ throw new VroumVroum_User_Exception("Missing or empty configuration value '".$c."' which is required!");
+ }
+
+ }
+
+ public function __set($key, $value)
+ {
+ return;
+ }
+}
+
+// BLOG
+
+class VroumVroum_Blog
+{
+ protected $articles = null;
+ protected $local = null;
+
+ public $config = null;
+
+ static public function removeHTML($str)
+ {
+ $str = strip_tags($str);
+ $str = html_entity_decode($str, ENT_QUOTES, 'UTF-8');
+ return $str;
+ }
+
+ static public function toURI($str)
+ {
+ $uri = self::removeHTML(trim($str));
+ $uri = substr($uri, 0, 70);
+ $uri = preg_replace('/[^\w\d()\p{L}]+/u', '-', $uri);
+ $uri = preg_replace('/-{2,}/', '-', $uri);
+ $uri = preg_replace('/^-|-$/', '', $uri);
+ return $uri;
+ }
+
+ public function __construct()
+ {
+ $this->config = new VroumVroum_Config;
+
+ $create_articles_db = file_exists(ARTICLES_DB_FILE) ? false : true;
+
+ $this->articles = new SQLite3(ARTICLES_DB_FILE);
+
+ if ($create_articles_db)
+ {
+ $this->articles->exec('
+ CREATE TABLE articles (
+ id INTEGER PRIMARY KEY,
+ feed_id TEXT,
+ title TEXT,
+ uri TEXT,
+ url TEXT,
+ date INT,
+ content TEXT
+ );
+ CREATE TABLE update_log (
+ date INT PRIMARY KEY,
+ success INT,
+ log TEXT
+ );
+ CREATE UNIQUE INDEX feed_id ON articles (feed_id);
+ CREATE INDEX date ON articles (date);
+ ');
+ }
+
+ $this->articles->createFunction('countintegers', array($this, 'sql_countintegers'));
+ }
+
+ public function getLocalURL($in)
+ {
+ return "./?".(is_array($in) ? $in['uri'] : $in);
+ }
+
+ protected function log_update($success, $log = '')
+ {
+ $this->articles->exec('INSERT INTO update_log (date, success, log) VALUES (\''.time().'\', \''.(int)(bool)$success.'\',
+ \''.$this->articles->escapeString($log).'\');');
+
+ // Delete old log
+ $this->articles->exec('DELETE FROM update_log WHERE date > (SELECT date FROM update_log ORDER BY date DESC LIMIT 100,1);');
+
+ return true;
+ }
+
+ public function insertOrUpdateArticle($feed_id, $title, $url, $date, $content)
+ {
+ $exists = $this->articles->querySingle('SELECT date, id, title, content FROM articles WHERE feed_id = \''.$this->articles->escapeString($feed_id).'\';', true);
+
+ if (empty($exists))
+ {
+ $uri = self::toURI($title);
+
+ if ($this->articles->querySingle('SELECT 1 FROM articles WHERE uri = \''.$this->articles->escapeString($uri).'\';'))
+ {
+ $uri = date('Y-m-d-') . $uri;
+ }
+
+ $content = $this->mirrorMediasForArticle($content, $url);
+
+ $this->articles->exec('INSERT INTO articles (id, feed_id, title, uri, url, date, content) VALUES (NULL,
+ \''.$this->articles->escapeString($feed_id).'\', \''.$this->articles->escapeString($title).'\',
+ \''.$this->articles->escapeString($uri).'\', \''.$this->articles->escapeString($url).'\',
+ \''.(int)$date.'\', \''.$this->articles->escapeString($content).'\');');
+
+ $id = $this->articles->lastInsertRowId();
+
+ $title = self::removeHTML($title);
+ $content = self::removeHTML($content);
+
+ }
+ else
+ {
+ // Doesn't need update
+ if ($date == $exists['date'] && $content == $exists['content'] && $title == $exists['title'])
+ {
+ return false;
+ }
+
+ $id = $exists['id'];
+
+ if ($content != $exists['content'])
+ $content = $this->mirrorMediasForArticle($content, $url);
+
+ $this->articles->exec('UPDATE articles SET title=\''.$this->articles->escapeString($title).'\',
+ url=\''.$this->articles->escapeString($url).'\', content=\''.$this->articles->escapeString($content).'\',
+ date=\''.(int)$date.'\' WHERE id = \''.(int)$id.'\';');
+
+ $title = self::removeHTML($title);
+ $content = self::removeHTML($content);
+
+ }
+
+ return $id;
+ }
+
+ public function mustUpdate()
+ {
+ if (isset($_GET['update']))
+ return true;
+
+ $last_update = $this->articles->querySingle('SELECT date FROM update_log ORDER BY date DESC LIMIT 1;');
+
+ if (!empty($last_update) && (int) $last_update > (time() - $this->config->update_interval))
+ return false;
+
+ return true;
+ }
+
+ protected function _getStreamContext()
+ {
+ return stream_context_create(
+ array(
+ 'http' => array(
+ 'method' => 'GET',
+ 'timeout' => $this->config->update_timeout,
+ 'header' => "User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:20.0; Autoblogs; +https://github.com/mitsukarenai/Projet-Autoblog/) Gecko/20100101 Firefox/20.0\r\n",
+ )
+ )
+ );
+ }
+
+ public function update()
+ {
+ if (!$this->mustUpdate())
+ return false;
+
+ try {
+ $body = file_get_contents($this->config->feed_url, false, $this->_getStreamContext());
+ }
+ catch (ErrorException $e)
+ {
+ $this->log_update(false, $e->getMessage() . "\n\n" . (!empty($http_response_header) ? implode("\n", $http_response_header) : ''));
+ throw new VroumVroum_Feed_Exception("Can't retrieve feed: ".$e->getMessage());
+ }
+
+ libxml_use_internal_errors(true);
+ $xml = @simplexml_load_string($body);
+
+ if (!$xml)
+ {
+ $errors = VroumVroum_Feed_Exception::getXMLErrorsAsString(libxml_get_errors());
+ $this->log_update(false, implode("\n", $errors) . "\n\n" . $body);
+ throw new VroumVroum_Feed_Exception("Feed is invalid - XML error: ".implode(" - ", $errors));
+ }
+
+ $updated = 0;
+ $this->articles->exec('BEGIN TRANSACTION;');
+
+ if (isset($xml->entry)) // ATOM feed
+ {
+ foreach ($xml->entry as $item)
+ {
+ $date = isset($item->published) ? (string) $item->published : (string) $item->updated;
+ $guid = !empty($item->id) ? (string)$item->id : (string)$item->link['href'];
+
+ $id = $this->insertOrUpdateArticle($guid, (string)$item->title,
+ (string)$item->link['href'], strtotime($date), (string)$item->content);
+
+ if ($id !== false)
+ $updated++;
+ }
+ }
+ elseif (isset($xml->item)) // RSS 1.0 /RDF
+ {
+ foreach ($xml->item as $item)
+ {
+ $guid = (string) $item->attributes('http://www.w3.org/1999/02/22-rdf-syntax-ns#')->about ?: (string)$item->link;
+ $date = (string) $item->children('http://purl.org/dc/elements/1.1/')->date;
+
+ $id = $this->insertOrUpdateArticle($guid, (string)$item->title, (string)$item->link,
+ strtotime($date), (string) $item->children('http://purl.org/rss/1.0/modules/content/'));
+
+ if ($id !== false)
+ $updated++;
+ }
+ }
+ elseif (isset($xml->channel->item)) // RSS 2.0
+ {
+ foreach ($xml->channel->item as $item)
+ {
+ $content = (string) $item->children('http://purl.org/rss/1.0/modules/content/');
+ $guid = !empty($item->guid) ? (string) $item->guid : (string) $item->link;
+
+ if (empty($content) && !empty($item->description))
+ $content = (string) $item->description;
+
+ $id = $this->insertOrUpdateArticle($guid, (string)$item->title, (string)$item->link,
+ strtotime((string) $item->pubDate), $content);
+
+ if ($id !== false)
+ $updated++;
+ }
+ }
+ else
+ {
+ throw new VroumVroum_Feed_Exception("Unknown feed type?!");
+ }
+
+ $this->log_update(true, $updated . " elements updated");
+
+ $this->articles->exec('END TRANSACTION;');
+
+ return $updated;
+ }
+
+ public function listArticlesByPage($page = 1)
+ {
+ $nb = $this->config->articles_per_page;
+ $begin = ($page - 1) * $nb;
+ $res = $this->articles->query('SELECT * FROM articles ORDER BY date DESC LIMIT '.(int)$begin.','.(int)$nb.';');
+
+ $out = array();
+
+ while ($row = $res->fetchArray(SQLITE3_ASSOC))
+ {
+ $out[] = $row;
+ }
+
+ return $out;
+ }
+
+ public function listLastArticles()
+ {
+ return array_merge($this->listArticlesByPage(1), $this->listArticlesByPage(2));
+ }
+
+ public function countArticles()
+ {
+ return $this->articles->querySingle('SELECT COUNT(*) FROM articles;');
+ }
+
+ public function getArticleFromURI($uri)
+ {
+ return $this->articles->querySingle('SELECT * FROM articles WHERE uri = \''.$this->articles->escapeString($uri).'\';', true);
+ }
+
+ public function sql_countintegers($in)
+ {
+ return substr_count($in, ' ');
+ }
+
+ public function searchArticles($query)
+ {
+ $res = $this->articles->query('SELECT id, uri, title, content
+ FROM articles
+ WHERE content LIKE \'%'.$this->articles->escapeString($query).'%\'
+ ORDER BY id DESC
+ LIMIT 0,100;');
+
+ $out = array();
+
+ while ($row = $res->fetchArray(SQLITE3_ASSOC))
+ {
+ $row['url'] = $this->getLocalURL($this->articles->querySingle('SELECT uri FROM articles WHERE id = \''.(int)$row['id'].'\';'));
+ $out[] = $row;
+ }
+
+ return $out;
+ }
+
+ public function mirrorMediasForArticle($content, $url)
+ {
+ if (!file_exists(MEDIA_DIR))
+ {
+ mkdir(MEDIA_DIR);
+ }
+
+ $schemes = array('http', 'https');
+ $extensions = explode(',', preg_quote('jpg,jpeg,png,apng,gif,svg,pdf,odt,ods,epub,webp,wav,mp3,ogg,aac,wma,flac,opus,mp4,webm', '!'));
+ $extensions = implode('|', $extensions);
+
+ $from = parse_url($url);
+ if( isset($from['path']) ) { // not exist if http://exemple.com
+ $from['path'] = preg_replace('![^/]*$!', '', $from['path']);
+ }else{
+ $from['path'] = '';
+ }
+
+ preg_match_all('!(src|href)\s*=\s*[\'"]?([^"\'<>\s]+\.(?:'.$extensions.'))[\'"]?!i', $content, $match, PREG_SET_ORDER);
+
+ foreach ($match as $m)
+ {
+ $url = parse_url($m[2]);
+
+ if (empty($url['scheme']))
+ $url['scheme'] = $from['scheme'];
+
+ if (empty($url['host']))
+ $url['host'] = $from['host'];
+
+ if (!in_array(strtolower($url['scheme']), $schemes))
+ continue;
+
+ if ($url['path'][0] != '/')
+ $url['path'] = $from['path'] . $url['path'];
+
+ $filename = basename($url['path']);
+ $url = $url['scheme'] . '://' . $url['host'] . $url['path'];
+
+ $filename = substr(sha1($url), -8) . '.' . substr(preg_replace('![^\w\d_.-]!', '', $filename), -64);
+ $copied = false;
+
+ if (!file_exists(MEDIA_DIR . '/' . $filename))
+ {
+ try {
+ $copied = $this->_copy($url, MEDIA_DIR . '/' . $filename);
+ }
+ catch (ErrorException $e)
+ {
+ // Ignore copy errors
+ }
+ }
+ $content = str_replace($m[0], $m[1] . '="'.'media/'.$filename.'" data-original-source="'.$url.'"', $content);
+ }
+ return $content;
+ }
+
+ /* copy() is buggy with http streams and safe_mode enabled (which is bad), so here's a workaround */
+ protected function _copy($from, $to)
+ {
+ $in = fopen($from, 'r', false, $this->_getStreamContext());
+ $out = fopen($to, 'w', false);
+ $size = stream_copy_to_stream($in, $out);
+ fclose($in);
+ fclose($out);
+ return $size;
+ }
+}
+
+// DISPLAY AND CONTROLLERS
+
+$vvb = new VroumVroum_Blog;
+$config = $vvb->config;
+$site_type = escape($config->site_type);
+
+if (isset($_GET['feed'])) // FEED
+{
+ header('Content-Type: application/atom+xml; charset=UTF-8');
+ echo '
+
+ '.escape($config->site_title).'
+ '.escape(html_entity_decode(strip_tags($config->site_description), ENT_COMPAT, 'UTF-8')).'
+ '.date(DATE_ATOM, filemtime(ARTICLES_DB_FILE)).'
+
+ '.LOCAL_URL.'
+
+ Projet Autoblog ';
+
+ foreach($vvb->listLastArticles() as $art)
+ {
+ echo '
+
+
+ '.escape($config->site_title).'
+ '.escape($config->site_url).'
+
+
+
+ '.str_replace('?feed', '?', LOCAL_URL).urlencode(str_replace('./?', '', $vvb->getLocalURL($art))).'
+ '.date(DATE_ATOM, $art['date']).'
+
+
+ source) '.escape_content($art['content']).']]>
+
+ ';
+ }
+
+ echo '
+ ';
+ exit;
+}
+
+if (isset($_GET['opml'])) // OPML
+{
+ //header('Content-Type: application/octet-stream');
+ header('Content-type: text/xml');
+ header('Content-Disposition: attachment; filename="'.escape($config->site_title).'.xml"');
+ $opmlfile = new SimpleXMLElement(' ');
+ $opmlfile->addAttribute('version', '1.0');
+ $opmlhead = $opmlfile->addChild('head');
+ $opmlhead->addChild('title', escape($config->site_title));
+ $opmlhead->addChild('dateCreated', date('r', time()));
+ $opmlbody = $opmlfile->addChild('body');
+ $outline = $opmlbody->addChild('outline');
+ $outline->addAttribute('title', escape($config->site_title));
+ $outline->addAttribute('text', escape($config->site_type));
+ $outline->addAttribute('htmlUrl', escape($config->site_url));
+ $outline->addAttribute('xmlUrl', escape($config->feed_url));
+
+ echo $opmlfile->asXML();
+ exit;
+}
+
+if (isset($_GET['media'])) // MEDIA
+{
+ header('Content-Type: application/json');
+ if(is_dir(MEDIA_DIR))
+ {
+ $url = str_replace('?media', 'media/', LOCAL_URL);
+ $files = scandir(MEDIA_DIR);
+ unset($files[0]); // .
+ unset($files[1]); // ..
+ echo json_encode(array("url"=> $url, "files" => $files));
+ }
+ exit;
+}
+
+if (isset($_GET['update']))
+{
+ $_SERVER['QUERY_STRING'] = '';
+}
+
+// CONTROLLERS
+$search = !empty($_GET['q']) ? trim($_GET['q']) : '';
+$article = null;
+
+if (!$search && !empty($_SERVER['QUERY_STRING']) && !is_numeric($_SERVER['QUERY_STRING']))
+{
+ $uri = rawurldecode($_SERVER['QUERY_STRING']);
+ $article = $vvb->getArticleFromURI($uri);
+
+ if (!$article)
+ {
+ header('HTTP/1.1 404 Not Found', true, 404);
+ }
+}
+
+// common CSS
+$css=' * { margin: 0; padding: 0; }
+ body { font-family:sans-serif; background-color: #efefef; padding: 1%; color: #333; }
+ img { max-width: 100%; height: auto; }
+ a { text-decoration: none; color: #000;font-weight:bold; }
+ .header a { text-decoration: none; color: #000;font-weight:bold; }
+ .header { text-align:center; padding: 30px 3%; max-width:70em;margin:0 auto; }
+ .article .title { margin-bottom: 1em; }
+ .article .title h2 a:hover { color:#403976; }
+ .article h4 { font-weight: normal; font-size: small; color: #666; }
+ .article .source a { color: #666; }
+ .searchForm { float:right; }
+ .searchForm input { }
+ .pagination { background-color:white;padding: 12px 10px 12px 10px;border:1px solid #aaa;max-width:70em;margin:1em auto;box-shadow:0px 5px 7px #aaa; }
+ .pagination b { font-size: 1.2em; color: #333; }
+ .pagination a { color:#000; margin: 0 0.5em; }
+ .pagination a:hover { color:#333; }
+ .footer a { color:#000; }
+ .footer a:hover { color:#333; }
+ .content ul, .content ol { margin-left: 2em; }
+ .content h1, .content h2, .content h3, .content h4, .content h5, .content h6,
+ .content ul, .content ol, .content p, .content object, .content div, .content blockquote,
+ .content dl, .content pre { margin-bottom: 0.8em; }
+ .content pre, .content blockquote { background: #ddd; border: 1px solid #999; padding: 0.2em; max-width: 100%; overflow: auto; }
+ .content h1 { font-size: 1.5em; }
+ .content h2 { font-size: 1.4em;color:#000; }
+ .result h3 a { color: darkblue; text-decoration: none; text-shadow: 1px 1px 1px #fff; }
+ #error { position: fixed; top: 0; left: 0; right: 0; padding: 1%; background: #fff; border-bottom: 2px solid red; color: darkred; }
+';
+
+if($site_type == 'generic') // custom CSS for generic
+ {
+ $css = $css.'.header h1 a { color: #333;font-size:40pt;text-shadow: #ccc 0px 5px 5px;text-transform:uppercase; }
+ .article .title h2 { margin: 0; color:#333; text-shadow: 1px 1px 1px #fff; }
+ .article .title h2 a { color:#000; text-decoration:none; }
+ .article .source { font-size: 0.8em; color: #666; }
+ .article { background-color:white;padding: 12px 10px 12px 10px;border:1px solid #aaa;max-width:70em;margin:1em auto;box-shadow:0px 5px 7px #aaa; }
+ .footer { text-align:center; font-size: small; color:#333; clear: both; }';
+ }
+ else if($site_type == 'microblog' || $site_type == 'twitter' || $site_type == 'identica') // custom CSS for microblog
+ {
+ $css = $css.'.header h1 a { color: #333;font-size:40pt;text-shadow: #ccc 0px 5px 5px; }
+ .article .title h2 { width: 10em;white-space: nowrap;overflow: hidden;text-overflow: ellipsis;font-size: 0.7em;margin: 0; color:#333; text-shadow: 1px 1px 1px #fff; }
+ .article .title h2 a { color:#333; text-decoration:none; }
+ .article { background-color:white;padding: 12px 10px 12px 10px;border:1px solid #aaa;max-width:70em;margin:0 auto;box-shadow:0px 5px 7px #aaa; }
+ .article .source { font-size: 0.8em; color: #666; }
+ .footer { margin-top:1em;text-align:center; font-size: small; color:#333; clear: both; }
+ .content {font-size:0.9em;white-space: nowrap;overflow: hidden;text-overflow: ellipsis;}';
+ }
+ else if($site_type == 'shaarli') // custom CSS for shaarli
+ {
+ $css = $css.'.header h1 a { color: #333;font-size:40pt;text-shadow: #ccc 0px 5px 5px; }
+ .article .title h2 { margin: 0; color:#333; text-shadow: 1px 1px 1px #fff; }
+ .article .title h2 a { color:#000; text-decoration:none; }
+ .article { background-color:white;padding: 12px 10px 12px 10px;border:1px solid #aaa;max-width:70em;margin:1em auto;box-shadow:0px 5px 7px #aaa; }
+ .article .source { margin-top:1em;font-size: 0.8em; color: #666; }
+ .footer { text-align:center; font-size: small; color:#333; clear: both; }';
+ }
+
+
+// HTML HEADER
+echo '
+
+
+
+
+ '.escape($config->site_title).'
+
+
+
+
+
+
+';
+
+if ($vvb->mustUpdate())
+{
+ echo '
+
+
+
'.__('Update').'
+
+
+ '.__('Updating database... Please wait.').'
+
+
';
+}
+
+if (!empty($search))
+{
+ $results = $vvb->searchArticles($search);
+ $text = sprintf(__('%d results for %s '), count($results), escape($search));
+ echo '
+
+
+
'.__('Search').'
+ '.$text.'
+
+
';
+
+ foreach ($results as $art)
+ {
+ echo '
+
+
+
'.$art['content'].'
+
';
+ }
+}
+elseif (!is_null($article))
+{
+ if (!$article)
+ {
+ echo '
+
+
+
'.__('Not Found').'
+ '.(!empty($uri) ? '
'.escape($vvb->getLocalURL($uri)) . '
' : '').'
+ '.__('Article not found.').'
+
+
';
+ }
+ else
+ {
+ display_article($article);
+ }
+}
+else
+{
+ if (!empty($_SERVER['QUERY_STRING']) && is_numeric($_SERVER['QUERY_STRING']))
+ $page = (int) $_SERVER['QUERY_STRING'];
+ else
+ $page = 1;
+
+ $list = $vvb->listArticlesByPage($page);
+
+ foreach ($list as $article)
+ {
+ display_article($article);
+ }
+
+ $max = $vvb->countArticles();
+ if ($max > $config->articles_per_page)
+ {
+ echo '';
+ }
+}
+
+echo '
+';
+
+if ($vvb->mustUpdate())
+{
+ try {
+ ob_end_flush();
+ flush();
+ }
+ catch (Exception $e)
+ {
+ // Silent, not critical
+ }
+
+ try {
+ $updated = $vvb->update();
+ }
+ catch (VroumVroum_Feed_Exception $e)
+ {
+ echo '
+
+ '.escape($e->getMessage()).'
+
';
+ $updated = 0;
+ }
+
+ if ($updated > 0)
+ {
+ echo '
+ ';
+ }
+ else
+ {
+ echo '
+ ';
+ }
+}
+
+echo '
+
+';
+
+
+function escape_content($str)
+{
+ $str = preg_replace('!<\s*(style|script|link)!', '<\\1', $str);
+ $str = str_replace('="media/', '="./media/', $str);
+ return $str;
+}
+
+// ARTICLE HTML CODE
+function display_article($article)
+{
+ global $vvb, $config;
+ echo '
+
+
+
+ '.strftime(__('_date_format'), $article['date']).'
+
+
'.escape_content($article['content']).'
+
'.__('Source:').' '.escape($article['url']).'
+
+
';
+}
+
+?>
diff --git a/class_rssfeed.php b/class_rssfeed.php
new file mode 100755
index 0000000..59fd431
--- /dev/null
+++ b/class_rssfeed.php
@@ -0,0 +1,277 @@
+
+ *
+ * + 03/2013
+ * Few changes, AutoblogRSS and FileRSSFeed
+ * @author Arthur Hoaro
+ */
+class RSSFeed {
+ protected $xml;
+
+ /**
+ * Construct a RSS feed
+ */
+ public function __construct() {
+ $template = <<
+
+
+
+
+END;
+
+ $this->xml = new SimpleXMLElement($template);
+ }
+
+ /**
+ * Set RSS Feed headers
+ * @param $title the title of the feed
+ * @param $link link to the website where you can find the RSS feed
+ * @param $description a description of the RSS feed
+ * @param $rsslink the link to this RSS feed
+ */
+ public function setHeaders($title, $link, $description, $rsslink) {
+ $atomlink = $this->xml->channel->addChild("atom:link","","http://www.w3.org/2005/Atom");
+ $atomlink->addAttribute("href",$rsslink);
+ $atomlink->addAttribute("rel","self");
+ $atomlink->addAttribute("type","application/rss+xml");
+
+ $this->xml->channel->title = $title;
+ $this->xml->channel->link = $link;
+ $this->xml->channel->description = $description;
+ }
+
+ /**
+ * Set the language of the RSS feed
+ * @param $lang the language of the RSS feed
+ */
+ public function setLanguage($lang) {
+ $this->xml->channel->addChild("language",$lang);
+ }
+ /**
+ * Adds a picture to the RSS feed
+ * @param $url URL to the image
+ * @param $title The image title. Usually same as the RSS feed's title
+ * @param $link Where the image should link to. Usually same as the RSS feed's link
+ */
+ public function setImage($url, $title, $link) {
+ $image = $this->xml->channel->addChild("image");
+ $image->url = $url;
+ $image->title = $title;
+ $image->link = $link;
+ }
+ /**
+ * Add a item to the RSS feed
+ * @param $title The title of the RSS feed
+ * @param $link Link to the item's url
+ * @param $description The description of the item
+ * @param $author The author who wrote this item
+ * @param $guid Unique ID for this post
+ * @param $timestamp Unix timestamp for making a date
+ */
+ public function addItem($title, $link, $description, $author, $guid, $timestamp) {
+ $item = $this->xml->channel->addChild("item");
+ $item->title = $title;
+ $item->description = $description;
+ $item->link = $link;
+ $item->guid = $guid;
+ if( isset($guid['isPermaLink']))
+ $item->guid['isPermaLink'] = $guid['isPermaLink'];
+ if( !empty( $author) )
+ $item->author = $author;
+ $item->pubDate = date(DATE_RSS,intval($timestamp));
+ }
+ /**
+ * Displays the RSS feed
+ */
+ public function displayXML() {
+ header('Content-type: application/rss+xml; charset=utf-8');
+ echo $this->xml->asXML();
+ exit;
+ }
+
+ public function getXML() {
+ return $this->xml;
+ }
+}
+
+class RSSMerger {
+ private $feeds = array();
+
+ /**
+ * Constructs a RSSmerger object
+ */
+ function __construct() {
+
+ }
+
+ /**
+ * Populates the feeds array from the given url which is a rss feed
+ * @param $url
+ */
+ function add($xml) {
+
+ foreach($xml->channel->item as $item) {
+ $item->sitetitle = $xml->channel->title;
+ $item->sitelink = $xml->channel->link;
+
+ preg_match("/^[A-Za-z]{3}, ([0-9]{2}) ([A-Za-z]{3}) ([0-9]{4}) ([0-9]{2}):([0-9]{2}):([0-9]{2}) ([\+|\-]?[0-9]{4})$/", $item->pubDate, $match);
+ $item->time = time($match[4]+($match[6]/100),$match[5],$match[6],date("m",strtotime($match[2])),$match[1],$match[3]);
+
+ $this->feeds[] = $item;
+ }
+ }
+ /**
+ * Comparing function for sorting the feeds
+ * @param $value1
+ * @param $value2
+ */
+ function feeds_cmp($value1,$value2) {
+ if(intval($value1->time) == intval($value2->time))
+ return 0;
+
+ return (intval($value1->time) < intval($value2->time)) ? +1 : -1;
+ }
+
+ /**
+ * Sorts the feeds array using the Compare function feeds_cmp
+ */
+ function sort() {
+ usort($this->feeds,Array("RssMerger","feeds_cmp"));
+ }
+
+ /**
+ * This function return the feed items.
+ * @param $limit how many feed items that should be returned
+ * @return the feeds array
+ */
+ function getFeeds($limit) {
+ return array_slice($this->feeds,0,$limit);
+ }
+}
+
+class FileRSSFeed extends RSSFeed {
+ protected $filename;
+
+ public function __construct($filename) {
+ parent::__construct();
+ $this->filename = $filename;
+
+ $this->load();
+ }
+
+ public function load() {
+ if ( file_exists( $this->filename )) {
+ $this->xml = simplexml_load_file($this->filename);
+ }
+ }
+
+ public function create($title, $link, $description, $rsslink) {
+ parent::setHeaders($title, $link, $description, $rsslink);
+ $this->write();
+ }
+
+ public function addItem($title, $link, $description, $author, $guid, $timestamp) {
+ parent::addItem($title, $link, $description, $author, $guid, $timestamp);
+ $this->write();
+ }
+
+ private function write() {
+ if ( file_exists( $this->filename )) {
+ unlink($this->filename);
+ }
+
+ $outputXML = new RSSFeed();
+ foreach($this->xml->channel->item as $f) {
+ $item = $outputXML->addItem($f->title,$f->link,$f->description,$f->author,$f->guid, strtotime($f->pubDate));
+ }
+
+ $merger = new RssMerger();
+ $merger->add($outputXML->getXML());
+ $merger->sort();
+
+ unset($this->xml->channel->item);
+ foreach($merger->getFeeds(20) as $f) {
+ parent::addItem($f->title,$f->link,$f->description,$f->author,$f->guid,$f->time);
+ }
+
+ file_put_contents( $this->filename, $this->xml->asXML(), LOCK_EX );
+ }
+}
+
+class AutoblogRSS extends FileRSSFeed {
+ public function __construct($filename) {
+ parent::__construct($filename);
+ }
+
+ public function addUnavailable($title, $folder, $siteurl, $rssurl) {
+ $path = pathinfo( $_SERVER['PHP_SELF'] );
+ $autobHref = 'http'.(!empty($_SERVER['HTTPS'])?'s':'').'://'.
+ $_SERVER["SERVER_NAME"].':'.$_SERVER["SERVER_PORT"]. $path['dirname'].'/'.$folder;
+
+ parent::addItem( 'L\'autoblog "'. $title.'" est indisponible', $autobHref,
+ 'Autoblog: '.$title.'
+ Site: '. $siteurl .'
+ RSS: '.$rssurl.'
+ Folder: '. $folder ,
+ 'admin@'.$_SERVER['SERVER_NAME'],
+ $autobHref,
+ time()
+ );
+ }
+
+ public function addAvailable($title, $folder, $siteurl, $rssurl) {
+ $path = pathinfo( $_SERVER['PHP_SELF'] );
+ $autobHref = 'http'.(!empty($_SERVER['HTTPS'])?'s':'').'://'.
+ $_SERVER["SERVER_NAME"].':'.$_SERVER["SERVER_PORT"]. $path['dirname'].'/'.$folder;
+
+ parent::addItem( 'L\'autoblog "'. $title.'" est de nouveau disponible', $autobHref,
+ 'Autoblog : '.$title.'
+ Site: '. $siteurl .'
+ RSS: '.$rssurl.'
+ Folder: '. $folder ,
+ 'admin@'.$_SERVER['SERVER_NAME'],
+ $autobHref,
+ time()
+ );
+ }
+
+ public function addCodeChanged($title, $folder, $siteurl, $rssurl, $code) {
+ $path = pathinfo( $_SERVER['PHP_SELF'] );
+ $autobHref = 'http'.(!empty($_SERVER['HTTPS'])?'s':'').'://'.
+ $_SERVER["SERVER_NAME"].':'.$_SERVER["SERVER_PORT"]. $path['dirname'].'/'.$folder;
+
+ parent::addItem( 'L\'autoblog "'. $title.'" a renvoyé un code imprévu', $autobHref,
+ 'Code: '. $code .'
+ Autoblog : '.$title.'
+ Site: '. $siteurl .'
+ RSS: '.$rssurl.'
+ Folder: '. $folder ,
+ 'admin@'.$_SERVER['SERVER_NAME'],
+ $autobHref,
+ time()
+ );
+ }
+
+ public function addNewAutoblog($title, $folder, $siteurl, $rssurl) {
+ $path = pathinfo( $_SERVER['PHP_SELF'] );
+ $autobHref = 'http'.(!empty($_SERVER['HTTPS'])?'s':'').'://'.
+ $_SERVER["SERVER_NAME"].':'.$_SERVER["SERVER_PORT"]. $path['dirname'].'/'.$folder;
+
+ parent::addItem( 'L\'autoblog "'. $title.'" a été ajouté à la ferme', $autobHref,
+ 'Autoblog : '.$title.'
+ Site: '. $siteurl .'
+ RSS: '.$rssurl.'
+ Folder: '. $folder ,
+ 'admin@'.$_SERVER['SERVER_NAME'],
+ $autobHref,
+ time()
+ );
+ }
+}
+
+?>
diff --git a/config.php b/config.php
new file mode 100755
index 0000000..8f98017
--- /dev/null
+++ b/config.php
@@ -0,0 +1,43 @@
+SebSauvage et Bohwaz .');
+
+// define( 'ALLOW_FULL_UPDATE', TRUE );
+// define( 'ALLOW_CHECK_UPDATE', TRUE );
+
+/**
+ * If you set ALLOW_NEW_AUTOBLOGS to FALSE, the following options do not matter.
+ **/
+// define( 'ALLOW_NEW_AUTOBLOGS', TRUE );
+// define( 'ALLOW_NEW_AUTOBLOGS_BY_LINKS', TRUE );
+// define( 'ALLOW_NEW_AUTOBLOGS_BY_SOCIAL', TRUE );
+// define( 'ALLOW_NEW_AUTOBLOGS_BY_BUTTON', TRUE );
+// define( 'ALLOW_NEW_AUTOBLOGS_BY_OPML_FILE', TRUE );
+// define( 'ALLOW_NEW_AUTOBLOGS_BY_OPML_LINK', TRUE );
+// define( 'ALLOW_NEW_AUTOBLOGS_BY_XSAF', TRUE );
+
+/**
+ * More about TwitterBridge : https://github.com/mitsukarenai/twitterbridge
+ **/
+// define( 'API_TWITTER', FALSE );
+
+/**
+ * Import autoblogs from friend's autoblog farm - Add a link to the JSON export
+ **/
+$friends_autoblog_farm = array(
+ 'https://raw.github.com/mitsukarenai/xsaf-bootstrap/master/3.json',
+ // 'https://www.ecirtam.net/autoblogs/?export',
+ // 'https://autoblog.suumitsu.eu/?export',
+ // 'http://streisand.hoa.ro/?export',
+);
+?>
diff --git a/docs/docs.txt b/docs/docs.txt
new file mode 100644
index 0000000..a4c763e
--- /dev/null
+++ b/docs/docs.txt
@@ -0,0 +1,4 @@
+You can manually add files in the /docs/ directory, such as PDF, docs, images, etc.
+You can also add subfolders in /docs/ for website mirroring. Be sure that your subfolder contains a file named index.html.
+
+Delete this file to hide the 'Autres documents' block in your autoblogs homepage.
diff --git a/functions.php b/functions.php
new file mode 100755
index 0000000..b1f68d1
--- /dev/null
+++ b/functions.php
@@ -0,0 +1,302 @@
+SebSauvage et Bohwaz .');
+
+// Functions
+function NoProtocolSiteURL($url) {
+ $protocols = array("http://", "https://");
+ $siteurlnoproto = str_replace($protocols, "", $url);
+
+ // Remove the / at the end of string
+ if ( $siteurlnoproto[strlen($siteurlnoproto) - 1] == '/' )
+ $siteurlnoproto = substr($siteurlnoproto, 0, -1);
+
+ // Remove index.php/html at the end of string
+ if( strpos($url, 'index.php') || strpos($url, 'index.html') ) {
+ $siteurlnoproto = preg_replace('#(.*)/index\.(html|php)$#', '$1', $siteurlnoproto);
+ }
+
+ return $siteurlnoproto;
+}
+
+
+function DetectRedirect($url)
+{
+ if(parse_url($url, PHP_URL_HOST)==FALSE) {
+ //die('Not a URL');
+ throw new Exception('Not a URL: '. escape ($url) );
+ }
+ $response = get_headers($url, 1);
+ if(!empty($response['Location'])) {
+ $response2 = get_headers($response['Location'], 1);
+ if(!empty($response2['Location'])) {
+ //die('too much redirection');
+ throw new Exception('too much redirection: '. escape ($url) );
+ }
+ else { return $response['Location']; }
+ }
+ else {
+ return $url;
+ }
+}
+
+function urlToFolder($url) {
+ return sha1(NoProtocolSiteURL($url));
+}
+
+function urlToFolderSlash($url) {
+ return sha1(NoProtocolSiteURL($url).'/');
+}
+
+function folderExists($url) {
+ return file_exists(AUTOBLOGS_FOLDER . urlToFolder($url)) || file_exists(AUTOBLOGS_FOLDER . urlToFolderSlash($url));
+}
+
+function escape($str) {
+ return htmlspecialchars($str, ENT_COMPAT, 'UTF-8', false);
+}
+
+function createAutoblog($type, $sitename, $siteurl, $rssurl, $error = array()) {
+ if( $type == 'generic' || empty( $type )) {
+ $var = updateType( $siteurl );
+ $type = $var['type'];
+ if( !empty( $var['name']) ) {
+ if( !stripos($siteurl, $var['name'] === false) )
+ $sitename = ucfirst($var['name']) . ' - ' . $sitename;
+ }
+ }
+
+ if(folderExists($siteurl)) {
+ $error[] = 'Erreur : l\'autoblog '. $sitename .' existe déjà.';
+ return $error;
+ }
+
+ $foldername = AUTOBLOGS_FOLDER . urlToFolderSlash($siteurl);
+
+ if ( mkdir($foldername, 0755, false) ) {
+
+ /**
+ * RSS
+ **/
+ try { // à déplacer après la tentative de création de l'autoblog crée avec succès ?
+ require_once('class_rssfeed.php');
+ $rss = new AutoblogRSS(RSS_FILE);
+ $rss->addNewAutoblog($sitename, $foldername, $siteurl, $rssurl);
+ }
+ catch (Exception $e) {
+ ;
+ }
+
+ $fp = fopen($foldername .'/index.php', 'w+');
+ if( !fwrite($fp, "") )
+ $error[] = "Impossible d'écrire le fichier index.php";
+ fclose($fp);
+
+ $fp = fopen($foldername .'/vvb.ini', 'w+');
+ if( !fwrite($fp, '[VroumVroumBlogConfig]
+SITE_TYPE="'. $type .'"
+SITE_TITLE="'. $sitename .'"
+SITE_DESCRIPTION="Site original : '. $sitename .' "
+SITE_URL="'. $siteurl .'"
+FEED_URL="'. $rssurl .'"
+ARTICLES_PER_PAGE="'. getArticlesPerPage( $type ) .'"
+UPDATE_INTERVAL="'. getInterval( $type ) .'"
+UPDATE_TIMEOUT="'. getTimeout( $type ) .'"') )
+ $error[] = "Impossible d'écrire le fichier vvb.ini";
+ fclose($fp);
+ }
+ else
+ $error[] = "Impossible de créer le répertoire.";
+ updateXML('new_autoblog_added', 'new', $foldername, $sitename, $siteurl, $rssurl); /* éventuellement une conditionnelle ici: if(empty($error)) ? */
+ return $error;
+}
+
+function getArticlesPerPage( $type ) {
+ switch( $type ) {
+ case 'microblog':
+ return 20;
+ case 'shaarli':
+ return 20;
+ default:
+ return 5;
+ }
+}
+
+function getInterval( $type ) {
+ switch( $type ) {
+ case 'microblog':
+ return 300;
+ case 'shaarli':
+ return 1800;
+ default:
+ return 3600;
+ }
+}
+
+function getTimeout( $type ) {
+ switch( $type ) {
+ case 'microblog':
+ return 30;
+ case 'shaarli':
+ return 30;
+ default:
+ return 30;
+ }
+}
+
+function updateType($siteurl) {
+ if( strpos($siteurl, 'twitter.com') !== FALSE ) {
+ return array('type' => 'twitter', 'name' => 'twitter');
+ }
+ elseif ( strpos( $siteurl, 'identi.ca') !== FALSE ) {
+ return array('type' => 'identica', 'name' => 'identica');
+ }
+ elseif( strpos( $siteurl, 'shaarli' ) !== FALSE ) {
+ return array('type' => 'shaarli', 'name' => 'shaarli');
+ }
+ else
+ return array('type' => 'generic', 'name' => '');
+}
+
+function debug($data)
+{
+ echo '';
+ var_dump($data);
+ echo ' ';
+}
+
+function __($str)
+{
+ switch ($str)
+ {
+ case 'Search':
+ return 'Recherche';
+ case 'Update':
+ return 'Mise à jour';
+ case 'Updating database... Please wait.':
+ return 'Mise à jour de la base de données, veuillez patienter...';
+ case '%d results for %s ':
+ return '%d résultats pour la recherche %s ';
+ case 'Not Found':
+ return 'Introuvable';
+ case 'Article not found.':
+ return 'Cet article n\'a pas été trouvé.';
+ case 'Older':
+ return 'Plus anciens';
+ case 'Newer':
+ return 'Plus récents';
+ case 'ATOM Feed':
+ return 'Flux ATOM';
+ case 'Update complete!':
+ return 'Mise à jour terminée !';
+ case 'Click here to reload this webpage.':
+ return 'Cliquez ici pour recharger cette page.';
+ case 'Source:':
+ return 'Source :';
+ case '_date_format':
+ return '%A %e %B %Y à %H:%M';
+ case 'configuration':
+ case 'articles':
+ return $str;
+ case 'Media export':
+ return 'Export fichiers media';
+ default:
+ return $str;
+ }
+}
+
+function updateXML($status, $response_code, $autoblog_url, $autoblog_title, $autoblog_sourceurl, $autoblog_sourcefeed)
+{
+$json = json_decode(file_get_contents(RESOURCES_FOLDER.'rss.json'), true);
+$json[] = array(
+ 'timestamp'=>time(),
+ 'autoblog_url'=>$autoblog_url,
+ 'autoblog_title'=>$autoblog_title,
+ 'autoblog_sourceurl'=>$autoblog_sourceurl,
+ 'autoblog_sourcefeed'=>$autoblog_sourcefeed,
+ 'status'=>$status,
+ 'response_code'=>$response_code
+ );
+file_put_contents(RESOURCES_FOLDER.'rss.json', json_encode($json), LOCK_EX);
+}
+
+function displayXMLstatus_tmp($status, $response_code, $autoblog_url, $autoblog_title, $autoblog_sourceurl, $autoblog_sourcefeed) {
+ switch ($status)
+ {
+ case 'unavailable':
+ return 'Autoblog "'.$autoblog_title.'": site distant inaccessible (code '.$response_code.') Autoblog: '.$autoblog_title.' Site: '. $autoblog_sourceurl .' RSS: '.$autoblog_sourcefeed.' ';
+ case 'moved':
+ return 'Autoblog "'.$autoblog_title.'": site distant redirigé (code '.$response_code.') Autoblog: '.$autoblog_title.' Site: '. $autoblog_sourceurl .' RSS: '.$autoblog_sourcefeed.' ';
+ case 'not_found':
+ return 'Autoblog "'.$autoblog_title.'": site distant introuvable (code '.$response_code.') Autoblog: '.$autoblog_title.' Site: '. $autoblog_sourceurl .' RSS: '.$autoblog_sourcefeed.' ';
+ case 'remote_error':
+ return 'Autoblog "'.$autoblog_title.'": site distant a problème serveur (code '.$response_code.') Autoblog: '.$autoblog_title.' Site: '. $autoblog_sourceurl .' RSS: '.$autoblog_sourcefeed.' ';
+ case 'available':
+ return 'Autoblog "'.$autoblog_title.'": site distant à nouveau opérationnel (code '.$response_code.') Autoblog: '.$autoblog_title.' Site: '. $autoblog_sourceurl .' RSS: '.$autoblog_sourcefeed.' ';
+ case 'new_autoblog_added':
+ return 'Autoblog "'.$autoblog_title.'" ajouté (code '.$response_code.') Autoblog: '.$autoblog_title.' Site: '. $autoblog_sourceurl .' RSS: '.$autoblog_sourcefeed.' ';
+ }
+}
+
+function displayXML_tmp() {
+header('Content-type: application/rss+xml; charset=utf-8');
+echo '
+ '.serverUrl(true).'';
+echo 'Projet Autoblog'. ((strlen(HEAD_TITLE)>0) ? ' | '. HEAD_TITLE : '').' '.serverUrl(true),"Projet Autoblog - RSS : Ajouts et changements de disponibilité.".' ';
+if(file_exists(RESOURCES_FOLDER.'rss.json'))
+{
+ $json = json_decode(file_get_contents(RESOURCES_FOLDER.'rss.json'), true);
+ foreach ($json as $item)
+ {
+ $description = displayXMLstatus_tmp($item['status'],$item['response_code'],$item['autoblog_url'],$item['autoblog_title'],$item['autoblog_sourceurl'],$item['autoblog_sourcefeed']);
+ $link = serverUrl(true).AUTOBLOGS_FOLDER.$item['autoblog_url'];
+ $date = date("r", $item['timestamp']);
+ print <<
+ {$item['autoblog_title']}
+
+ {$link}
+ {$item['timestamp']}
+ admin@{$_SERVER['SERVER_NAME']}
+ {$date}
+
+EOT;
+ }
+}
+echo ' ';
+}
+?>
diff --git a/index.php b/index.php
new file mode 100755
index 0000000..be3c7e4
--- /dev/null
+++ b/index.php
@@ -0,0 +1,926 @@
+loadXML($data) or die('xml malformé');
+ $title = $dom->getElementsByTagName('title');
+ return $title->item(0)->nodeValue;
+}
+
+function get_link_from_feed($url) {
+ return get_link_from_datafeed(file_get_contents($url));
+}
+
+function get_link_from_datafeed($data) {
+ if($data === false) { return 'url inaccessible'; }
+ $xml = simplexml_load_string($data); // quick feed check
+
+ // ATOM feed && RSS 1.0 /RDF && RSS 2.0
+ if (!isset($xml->entry) && !isset($xml->item) && !isset($xml->channel->item))
+ die('le flux n\'a pas une syntaxe valide');
+
+ $check = substr($data, 0, 5);
+ if($check !== 'channel->link;
+ if($channel['link'] === NULL) {
+ $dom = new DOMDocument;
+ $dom->loadXML($data) or die('xml malformé');
+ $link = $dom->getElementsByTagName('uri');
+ return $link->item(0)->nodeValue;
+ }
+ else {
+ return $channel['link'];
+ }
+}
+
+function serverUrl($return_subfolder = false)
+{
+ $https = (!empty($_SERVER['HTTPS']) && (strtolower($_SERVER['HTTPS'])=='on')) || $_SERVER["SERVER_PORT"]=='443'; // HTTPS detection.
+ $serverport = ($_SERVER["SERVER_PORT"]=='80' || ($https && $_SERVER["SERVER_PORT"]=='443') ? '' : ':'.$_SERVER["SERVER_PORT"]);
+ if($return_subfolder === true) {
+ $path = pathinfo( $_SERVER['PHP_SELF'] );
+ $subfolder = $path['dirname'] .'/';
+ } else $subfolder = '';
+ return 'http'.($https?'s':'').'://'.$_SERVER["SERVER_NAME"].$serverport.$subfolder;
+}
+
+function objectCmp($a, $b) {
+ return strcasecmp ($a->site_title, $b->site_title);
+}
+
+function generate_antibot() {
+ $letters = array('zéro', 'un', 'deux', 'trois', 'quatre', 'cinq', 'six', 'sept', 'huit', 'neuf', 'dix', 'onze', 'douze', 'treize', 'quatorze', 'quinze', 'seize', 'dix-sept', 'dix-huit', 'dix-neuf', 'vingt');
+ return $letters[mt_rand(1, 20)];
+}
+
+function check_antibot($number, $text_number) {
+ $letters = array('zéro', 'un', 'deux', 'trois', 'quatre', 'cinq', 'six', 'sept', 'huit', 'neuf', 'dix', 'onze', 'douze', 'treize', 'quatorze', 'quinze', 'seize', 'dix-sept', 'dix-huit', 'dix-neuf', 'vingt');
+ return ( array_search( $text_number, $letters ) === intval($number) ) ? true : false;
+}
+
+function create_from_opml($opml) {
+ global $error, $success;
+
+ foreach( $opml->body->outline as $outline ) {
+ if ( !empty( $outline['title'] ) && !empty( $outline['text'] ) && !empty( $outline['xmlUrl']) && !empty( $outline['htmlUrl'] )) {
+ try {
+ $rssurl = DetectRedirect(escape( $outline['xmlUrl']));
+
+ $sitename = escape( $outline['title'] );
+ $siteurl = escape($outline['htmlUrl']);
+ $sitetype = escape($outline['text']); if ( $sitetype == 'generic' or $sitetype == 'microblog' or $sitetype == 'shaarli') { } else { $sitetype = 'generic'; }
+
+ $error = array_merge( $error, createAutoblog( $sitetype, $sitename, $siteurl, $rssurl, $error ) );
+
+ if( empty ( $error ))
+ $success[] = 'Autoblog "'. $sitename .'" crée avec succès. → afficher l\'autoblog .';
+ }
+ catch (Exception $e) {
+ $error[] = $e->getMessage();
+ }
+ }
+ }
+}
+
+/**
+ * Simple version check
+ **/
+function versionCheck() {
+ $versionfile = 'version';
+ $lastestUrl = 'https://raw.github.com/mitsukarenai/Projet-Autoblog/master/0.3/version';
+
+ $expire = time() - 84600 ; // 23h30 en secondes
+ $lockfile = '.versionlock';
+
+ if (file_exists($lockfile) && filemtime($lockfile) > $expire) {
+ if( file_get_contents($lockfile) == 'NEW' ) {
+ // No new version installed
+ if( filemtime( $lockfile ) > filemtime( $versionfile ) )
+ return true;
+ else unlink($lockfile);
+ }
+ else return false;
+ }
+
+ if (file_exists($lockfile) && filemtime($lockfile) < $expire) { unlink($lockfile); }
+
+ if( file_get_contents($versionfile) != file_get_contents($lastestUrl) ) {
+ file_put_contents($lockfile, 'NEW');
+ return true;
+ }
+ file_put_contents($lockfile, '.');
+ return false;
+ }
+ $update_available = (ALLOW_CHECK_UPDATE) ? versionCheck() : false;
+
+/**
+* RSS Feed
+**/
+if( !file_exists(RSS_FILE)) {
+ require_once('class_rssfeed.php');
+ $rss = new AutoblogRSS(RSS_FILE);
+ $rss->create('Projet Autoblog'. ((strlen(HEAD_TITLE)>0) ? ' | '. HEAD_TITLE : ''), serverUrl(true),"Projet Autoblog - RSS : Ajouts et changements de disponibilité.", serverUrl(true) . RSS_FILE);
+}
+if (isset($_GET['rss'])) {
+ require_once('class_rssfeed.php');
+ $rss = new AutoblogRSS(RSS_FILE);
+ $rss->displayXML();
+ die;
+}
+
+if( !file_exists(RESOURCES_FOLDER.'rss.json')) {
+ file_put_contents(RESOURCES_FOLDER.'rss.json', '', LOCK_EX);
+}
+
+if (isset($_GET['rss_tmp'])) {
+ displayXML_tmp();
+ die;
+}
+
+/**
+ * SVG
+ **/
+if (isset($_GET['check']))
+{
+ //echo "1";
+ header('Content-type: image/svg+xml');
+ $randomtime=rand(86400, 259200); /* intervalle de mise à jour: de 1 à 3 jours (pour éviter que le statut de tous les autoblogs soit rafraichi en bloc et bouffe le CPU) */
+ $expire=time() -$randomtime ;
+
+ /* SVG minimalistes */
+ $svg_vert='OK ';
+ $svg_jaune='mv ';
+ $svg_rouge='err ';
+ $svg_twitter=' ';
+ $svg_identica=' ';
+ $svg_statusnet=' ';
+
+ $errorlog="./".escape( $_GET['check'] ) ."/error.log";
+
+ $oldvalue = null;
+ if(file_exists($errorlog)) { $oldvalue = file_get_contents($errorlog); };
+ if(file_exists($errorlog) && filemtime($errorlog) < $expire) { unlink($errorlog); } /* errorlog périmé ? Suppression. */
+ if(file_exists($errorlog)) /* errorlog existe encore ? se contenter de lire sa taille pour avoir le statut */
+ {
+ if(filesize($errorlog) == "0") {die($svg_vert);}
+ else if(filesize($errorlog) == "1") {die($svg_jaune);}
+ else {die($svg_rouge);}
+ }
+ else /* ..sinon, lancer la procédure de contrôle */
+ {
+ $ini = parse_ini_file("./". escape( $_GET['check'] ) ."/vvb.ini") or die;
+
+ if(strpos(strtolower($ini['SITE_TITLE']), 'twitter') !== FALSE) { die($svg_twitter); } /* Twitter */
+ if(strpos(strtolower($ini['SITE_TITLE']), 'identica') !== FALSE) { die($svg_identica); } /* Identica */
+ if(strpos(strtolower($ini['SITE_TYPE']), 'microblog') !== FALSE) { die($svg_statusnet); } /* Statusnet */
+
+ $headers = get_headers($ini['FEED_URL']);
+ /* le flux est indisponible (typiquement: erreur DNS ou possible censure) - à vérifier */
+ if(empty($headers) || $headers === FALSE ) {
+ if( $oldvalue !== null && $oldvalue != '..' ) {
+ require_once('class_rssfeed.php');
+ $rss = new AutoblogRSS(RSS_FILE);
+ $rss->addUnavailable($ini['SITE_TITLE'], escape($_GET['check']), $ini['SITE_URL'], $ini['FEED_URL']);
+ updateXML('unavailable', 'nxdomain', escape($_GET['check']), $ini['SITE_TITLE'], $ini['SITE_URL'], $ini['FEED_URL']);
+ }
+ file_put_contents($errorlog, '..');
+ die($svg_rouge);
+ }
+ $code=explode(" ", $headers[0]);
+ /* code retour 200: flux disponible */
+ if($code[1] == "200") {
+ if( $oldvalue !== null && $oldvalue != '' ) {
+ require_once('class_rssfeed.php');
+ $rss = new AutoblogRSS(RSS_FILE);
+ $rss->addAvailable($ini['SITE_TITLE'], escape($_GET['check']), $ini['SITE_URL'], $ini['FEED_URL']);
+ updateXML('available', '200', escape($_GET['check']), $ini['SITE_TITLE'], $ini['SITE_URL'], $ini['FEED_URL']);
+ }
+ file_put_contents($errorlog, '');
+ die($svg_vert);
+ }
+ /* autre code retour: un truc a changé (redirection, changement de CMS, .. bref vvb.ini doit être corrigé) */
+ else {
+ if( $oldvalue !== null && $oldvalue != '.' ) {
+ require_once('class_rssfeed.php');
+ $rss = new AutoblogRSS(RSS_FILE);
+ $rss->addCodeChanged($ini['SITE_TITLE'], escape($_GET['check']), $ini['SITE_URL'], $ini['FEED_URL'], $code[1]);
+ updateXML('moved', '3xx', escape($_GET['check']), $ini['SITE_TITLE'], $ini['SITE_URL'], $ini['FEED_URL']);
+ }
+ file_put_contents($errorlog, '.');
+ die($svg_jaune);
+ }
+ }
+}
+
+/**
+ * JSON Export
+ **/
+if (isset($_GET['export'])) {
+ header('Content-Type: application/json');
+ $subdirs = glob(AUTOBLOGS_FOLDER . "*");
+
+ foreach($subdirs as $unit) {
+ if(is_dir($unit)) {
+ $unit=substr($unit, 2);
+ $ini = parse_ini_file($unit.'/vvb.ini');
+ $config = new stdClass;
+
+ foreach ($ini as $key=>$value) {
+ $key = strtolower($key);
+ $config->$key = $value;
+ }
+ unset($ini);
+
+ $feed=$config->feed_url;
+ $type=$config->site_type;
+ $title=$config->site_title;
+ $url=$config->site_url;
+ $reponse[$unit] = array("SITE_TYPE"=>"$type", "SITE_TITLE"=>"$title", "SITE_URL"=>"$url", "FEED_URL"=>"$feed");
+
+ }
+ }
+ echo json_encode( array( "meta"=> array("xsaf-version"=>XSAF_VERSION,"xsaf-db_transfer"=>"true","xsaf-media_transfer"=>"true"),
+ "autoblogs"=>$reponse));
+ die;
+}
+
+/**
+ * JSON Allowed Twitter accounts export
+ **/
+if (isset($_GET['export_twitter'])) {
+ header('Content-Type: application/json');
+ $subdirs = glob(AUTOBLOGS_FOLDER . "*");
+ $response = array();
+
+ foreach($subdirs as $unit) {
+ if(is_dir($unit)) {
+ $unit=substr($unit, 2);
+ $ini = parse_ini_file($unit.'/vvb.ini');
+ if( $ini['SITE_TYPE'] == 'twitter' ) {
+ preg_match('#twitter\.com/(.+)#', $ini['SITE_URL'], $username);
+ $response[] = $username[1];
+ }
+ unset($ini);
+ }
+ }
+ echo json_encode( $response );
+ die;
+}
+
+/**
+ * OPML Full Export
+ **/
+if (isset($_GET['exportopml'])) // OPML
+{
+ //header('Content-Type: application/octet-stream');
+ header('Content-type: text/xml');
+ header('Content-Disposition: attachment; filename="autoblogs-'. $_SERVER['SERVER_NAME'] .'.xml"');
+
+ $opmlfile = new SimpleXMLElement(' ');
+ $opmlfile->addAttribute('version', '1.0');
+ $opmlhead = $opmlfile->addChild('head');
+ $opmlhead->addChild('title', 'Autoblog OPML export from '. $_SERVER['SERVER_NAME'] );
+ $opmlhead->addChild('dateCreated', date('r', time()));
+ $opmlbody = $opmlfile->addChild('body');
+
+ $subdirs = glob(AUTOBLOGS_FOLDER . "*");
+
+ foreach($subdirs as $unit) {
+ if(is_dir($unit)) {
+ $unit=substr($unit, 2);
+ $ini = parse_ini_file($unit.'/vvb.ini');
+ $config = new stdClass;
+
+ foreach ($ini as $key=>$value) {
+ $key = strtolower($key);
+ $config->$key = $value;
+ }
+ unset($ini);
+
+ $outline = $opmlbody->addChild('outline');
+ $outline->addAttribute('title', escape($config->site_title));
+ $outline->addAttribute('text', escape($config->site_type));
+ $outline->addAttribute('htmlUrl', escape($config->site_url));
+ $outline->addAttribute('xmlUrl', escape($config->feed_url));
+ }
+ }
+ echo $opmlfile->asXML();
+ exit;
+}
+
+/**
+ * Site map
+ * NEW AUTOBLOG FOLDER - Need update
+ **/
+if (isset($_GET['sitemap']))
+{
+ header('Content-Type: application/xml');
+ $proto=(!empty($_SERVER['HTTPS']) && strtolower($_SERVER['HTTPS'])=='on')?"https://":"http://";
+ echo '';
+ echo ''.$proto."{$_SERVER['HTTP_HOST']}".str_replace('?sitemap', '', $_SERVER['REQUEST_URI'])." \n";
+ echo ''.date('c', time())." \n";
+ echo 'daily ';
+ $subdirs = glob(AUTOBLOGS_FOLDER . "*");
+ foreach($subdirs as $unit) {
+ if(is_dir($unit)) {
+ $unit=substr($unit, 2);
+ echo ''.$proto.$_SERVER['SERVER_NAME'].substr($_SERVER['PHP_SELF'], 0, -9)."$unit/"." \n";
+ echo ''.date('c', filemtime($unit))." \n";
+ echo 'hourly ';
+ }
+ }
+ echo ' ';
+ die;
+}
+
+/**
+ * Update ALL autblogs (except .disabled)
+ * This action can be very slow and consume CPU if you have a lot of autoblogs
+ **/
+if( isset($_GET['updateall']) && ALLOW_FULL_UPDATE) {
+
+ $expire = time() - 84600 ; // 23h30 en secondes
+ $lockfile = ".updatealllock";
+ if (file_exists($lockfile) && filemtime($lockfile) > $expire) {
+ echo "too early";
+ die;
+ }
+ else {
+ if( file_exists($lockfile) )
+ unlink($lockfile);
+
+ if( file_put_contents($lockfile, date(DATE_RFC822)) ===FALSE) {
+ echo "Merci d'ajouter des droits d'écriture sur le fichier.";
+ die;
+ }
+ }
+
+ $subdirs = glob(AUTOBLOGS_FOLDER . "*");
+ foreach($subdirs as $unit) {
+ if(is_dir($unit)) {
+ if( !file_exists(ROOT_DIR . '/' . $unit . '/.disabled')) {
+ file_get_contents(serverUrl() . substr($_SERVER['PHP_SELF'], 0, -9) . $unit . '/index.php');
+ }
+ }
+ }
+}
+
+$antibot = generate_antibot();
+$form = '';
+
+/**
+ * ADD BY BOOKMARK BUTTON
+ **/
+if(!empty($_GET['via_button']) && $_GET['number'] === '17' && ALLOW_NEW_AUTOBLOGS && ALLOW_NEW_AUTOBLOGS_BY_BUTTON )
+{
+ $form = '';
+
+ if( empty($_GET['rssurl']) ) {
+ $form .= 'URL du flux RSS incorrect.Fermer la fenêtre.
';
+ }
+ else {
+ if(isset($_GET['add']) && $_GET['add'] === '1' && !empty($_GET['siteurl']) && !empty($_GET['sitename'])) {
+ try {
+ $rssurl = DetectRedirect(escape($_GET['rssurl']));
+
+ $siteurl = escape($_GET['siteurl']);
+ $sitename = escape($_GET['sitename']);
+ $sitetype = updateType($siteurl); // Disabled input doesn't send POST data
+ $sitetype = $sitetype['type'];
+
+ $error = array_merge( $error, createAutoblog($sitetype, $sitename, $siteurl, $rssurl, $error));
+ if( empty($error)) {
+ $form .= '';
+ $form .= 'Autoblog '. $sitename .' ajouté avec succès. ';
+ }
+ else {
+ $form .= '
';
+ foreach ( $error AS $value )
+ $form .= ''. $value .' ';
+ $form .= ' ';
+ }
+ }
+ catch (Exception $e) {
+ $form .= $e->getMessage();
+ }
+ $form .= 'Fermer la fenêtre.
';
+ }
+ else {
+ try {
+ $rssurl = DetectRedirect(escape($_GET['rssurl']));
+ $datafeed = file_get_contents($rssurl);
+ if( $datafeed !== false ) {
+ $siteurl = get_link_from_datafeed($datafeed);
+ $sitename = get_title_from_datafeed($datafeed);
+ $sitetype = updateType($siteurl);
+ $sitetype = $sitetype['type'];
+
+ $form .= 'Merci de vérifier les informations suivantes, corrigez si nécessaire.
+ ';
+ }
+ else {
+ $form .= 'URL du flux RSS incorrecte.Fermer la fenêtre.
';
+ }
+ }
+ catch (Exception $e) {
+ $form .= $e->getMessage() .'Fermer la fenêtre. ';
+ }
+ }
+ }
+ $form .= '';
+ echo $form; die;
+}
+
+/**
+ * ADD BY SOCIAL / SHAARLI
+ **/
+if(!empty($_POST['socialaccount']) && !empty($_POST['socialinstance']) && ALLOW_NEW_AUTOBLOGS && ALLOW_NEW_AUTOBLOGS_BY_SOCIAL)
+{
+ if( !empty($_POST['number']) && !empty($_POST['antibot']) && check_antibot($_POST['number'], $_POST['antibot']) ) {
+
+ $socialaccount = strtolower(escape($_POST['socialaccount']));
+ $socialinstance = strtolower(escape($_POST['socialinstance']));
+
+ if($socialinstance === 'twitter') {
+ if( API_TWITTER !== FALSE ) {
+ $sitetype = 'twitter';
+ $siteurl = "http://twitter.com/$socialaccount";
+ $rssurl = API_TWITTER.$socialaccount;
+ }
+ else
+ $error[] = "Twitter veut mettre à mort son API ouverte. Du coup on peut plus faire ça comme ça.";
+ }
+ elseif($socialinstance === 'identica') {
+ $sitetype = 'identica';
+ $siteurl = "http://identi.ca/$socialaccount";
+ $rssurl = "http://identi.ca/api/statuses/user_timeline/$socialaccount.rss";
+ }
+ elseif($socialinstance === 'statusnet' && !empty($_POST['statusneturl'])) {
+ $sitetype = 'microblog';
+ $siteurl= NoProtocolSiteURL(escape($_POST['statusneturl']));
+ try {
+ $rssurl = DetectRedirect("http://".$siteurl."/api/statuses/user_timeline/$socialaccount.rss");
+ $siteurl = DetectRedirect("http://".$siteurl."/$socialaccount");
+ }
+ catch (Exception $e) {
+ echo $error[] = $e->getMessage();
+ }
+ }
+ elseif($socialinstance === 'shaarli' && !empty($_POST['shaarliurl'])) {
+ $sitetype = 'shaarli';
+ $siteurl = NoProtocolSiteURL(escape($_POST['shaarliurl']));
+ try {
+ $siteurl = DetectRedirect("http://".$siteurl."/");
+ }
+ catch (Exception $e) {
+ echo $error[] = $e->getMessage();
+ }
+ $rssurl = $siteurl."?do=rss";
+ $socialaccount = get_title_from_feed($rssurl);
+ }
+
+ if( empty($error) ) {
+ // Twitterbridge do NOT allow this user yet => No check
+ if( $sitetype != 'twitter' ) {
+ $headers = get_headers($rssurl, 1);
+ if (strpos($headers[0], '200') == FALSE) {
+ $error[] = "Flux inaccessible (compte inexistant ?)";
+ }
+ }
+ if( empty($error) ) {
+ $error = array_merge( $error, createAutoblog($sitetype, ucfirst($socialinstance) .' - '. $socialaccount, $siteurl, $rssurl, $error));
+ if( empty($error))
+ $success[] = ''.ucfirst($socialinstance) .' - '. $socialaccount.' ajouté avec succès . ';
+ }
+ }
+ }
+ else
+ $error[] = 'Antibot : Chiffres incorrects.';
+}
+
+/**
+ * ADD BY GENERIC LINK
+ **/
+if( !empty($_POST['generic']) && ALLOW_NEW_AUTOBLOGS && ALLOW_NEW_AUTOBLOGS_BY_LINKS) {
+ if(empty($_POST['rssurl']))
+ {$error[] = "Veuillez entrer l'adresse du flux.";}
+ if(empty($_POST['number']) || empty($_POST['antibot']) )
+ {$error[] = "Vous êtes un bot ?";}
+ elseif(! check_antibot($_POST['number'], $_POST['antibot']))
+ {$error[] = "Antibot : Ce n'est pas le bon nombre.";}
+
+ if(empty($error)) {
+ try {
+ $rssurl = DetectRedirect(escape($_POST['rssurl']));
+
+ if(!empty($_POST['siteurl'])) {
+
+ $siteurl = escape($_POST['siteurl']);
+ $sitename = get_title_from_feed($rssurl);
+
+ $error = array_merge( $error, createAutoblog('generic', $sitename, $siteurl, $rssurl, $error));
+
+ if( empty($error))
+ $success[] = 'Autoblog '. $sitename .' crée avec succès. → afficher l\'autoblog ';
+ }
+ else {
+ // checking procedure
+
+ $datafeed = file_get_contents($rssurl);
+ if( $datafeed === false ) {
+ $error[] = 'URL "'. $rssurl .'" inaccessible.';
+ }
+ $sitetype = 'generic';
+ $siteurl = get_link_from_datafeed($datafeed);
+ $sitename = get_title_from_datafeed($datafeed);
+
+ $form = 'Merci de vérifier les informations suivantes, corrigez si nécessaire.
+ ';
+
+ }
+ }
+ catch (Exception $e) {
+ echo $error[] = $e->getMessage();
+ }
+ }
+}
+
+/**
+ * ADD BY OPML File
+ **/
+if( !empty($_POST['opml_file']) && ALLOW_NEW_AUTOBLOGS && ALLOW_NEW_AUTOBLOGS_BY_OPML_FILE) {
+ if(empty($_POST['number']) || empty($_POST['antibot']) )
+ {$error[] = "Vous êtes un bot ?";}
+ elseif(! check_antibot($_POST['number'], $_POST['antibot']))
+ {$error[] = "Antibot : Ce n'est pas le bon nombre.";}
+
+ if( empty( $error)) {
+ if (is_uploaded_file($_FILES['file']['tmp_name'])) {
+ $opml = null;
+ if( ($opml = simplexml_load_file( $_FILES['file']['tmp_name'])) !== false ) {
+ create_from_opml($opml);
+ }
+ else
+ $error[] = "Impossible de lire le contenu du fichier OPML.";
+ unlink($_FILES['file']['tmp_name']);
+ } else {
+ $error[] = "Le fichier n'a pas été envoyé.";
+ }
+ }
+}
+
+/**
+ * ADD BY OPML Link
+ **/
+ if( !empty($_POST['opml_link']) && ALLOW_NEW_AUTOBLOGS && ALLOW_NEW_AUTOBLOGS_BY_OPML_LINK) {
+ if(empty($_POST['number']) || empty($_POST['antibot']) )
+ {$error[] = "Vous êtes un bot ?";}
+ elseif(! check_antibot($_POST['number'], $_POST['antibot']))
+ {$error[] = "Antibot : Ce n'est pas le bon nombre.";}
+ if( empty( $_POST['opml_url'] ))
+ {$error[] = 'Le lien est incorrect.';}
+
+ if( empty( $error)) {
+ $opml_url = escape($_POST['opml_url']);
+ if(parse_url($opml_url, PHP_URL_HOST)==FALSE) {
+ $error[] = "URL du fichier OPML non valide.";
+ } else {
+ if ( ($opml = simplexml_load_file( $opml_url )) !== false ) {
+ create_from_opml($opml);
+ } else {
+ $error[] = "Impossible de lire le contenu du fichier OPML ou d'accéder à l'URL donnée.";
+ }
+ }
+
+ }
+}
+
+?>
+
+
+
+
+ Projet Autoblog0) echo " | " . HEAD_TITLE; ?>
+
+
+ ';
+ }
+ ?>
+
+
+
+
+
+ ';
+ ?>
+
Présentation
+
+
+ Le Projet Autoblog a pour objectif de répliquer les articles d'un blog ou d'un site site web.
+ Si l'article source est supprimé, et même si le site d'origine disparaît, les articles restent lisibles sur l'autoblog.
+ L'objectif premier de ce projet est de lutter contre la censure et toute sorte de pression...
+
+
+
+ Voici une liste d'autoblogs hébergés sur
+ (plus d'infos sur le projet ).
+
+
+
+
+
+
+
+
+
+
+
Ajouter un autoblog
+
+ Message'. (count($error) ? 's' : '') .' :
';
+ foreach ( $error AS $value ) {
+ echo ''. $value .' ';
+ }
+ foreach ( $success AS $value ) {
+ echo ''. $value .' ';
+ }
+ echo ' ';
+ }
+
+ $button_list = '
Ajouter un autoblog via : ';
+ if(ALLOW_NEW_AUTOBLOGS_BY_LINKS)
+ $button_list .= 'Flux RSS ';
+ if(ALLOW_NEW_AUTOBLOGS_BY_SOCIAL) {
+ $button_list .= 'Compte réseau social ';
+ $button_list .= 'Shaarli ';
+ }
+ if(ALLOW_NEW_AUTOBLOGS_BY_OPML_FILE)
+ $button_list .= 'Fichier OPML ';
+ if(ALLOW_NEW_AUTOBLOGS_BY_OPML_LINK)
+ $button_list .= 'Lien vers OPML ';
+ if(ALLOW_NEW_AUTOBLOGS_BY_BUTTON)
+ $button_list .= 'Marque page ';
+ $button_list .= '
';
+ echo $button_list;
+
+ if(ALLOW_NEW_AUTOBLOGS_BY_LINKS == TRUE) { ?>
+
+
+
+
Ajouter un compte social
+
+
+
+
+
+
Ajouter un Shaarli
+
+
+
+
+
+
Ajouter par fichier OPML
+
+
+
+
+
+
+
Ajouter par lien OPML
+
+
+
+
+
+
+
+
+
+
+ '. substr($unit, (strrpos($unit, '/')) + 1 ) .'';
+ }
+ }
+ }
+ if(!empty( $docs )) {
+ echo 'Autres documents ';
+ foreach( $docs as $value )
+ echo ''. $value .' ';
+ echo ' ';
+ }
+ ?>
+
+
+
Autoblogs hébergés
+
+ Autres fermes
+ → Rechercher
+
+
+
+
+ $value)
+ {
+ $key = strtolower($key);
+ $config->$key = $value;
+ }
+ $autoblogs[$unit] = $config;
+ unset($ini);
+ }
+ }
+ }
+ }
+ }
+
+ uasort($autoblogs, "objectCmp");
+ $autoblogs_display = '';
+
+ if(!empty($autoblogs)){
+ foreach ($autoblogs as $key => $autoblog) {
+ $opml_link='
opml ';
+ $autoblogs_display .= '
';
+ }
+ }
+ echo $autoblogs_display;
+ ?>
+
+
+
+ ".count($autoblogs)." autoblogs hébergés"; ?>
+
+ Propulsé par Projet Autoblog 0.3 de Mitsu , Oros et Arthur Hoaro (Domaine Public)
+ 0 ){ echo " ".FOOTER; } ?>
+
+
+
+
+
+
+
diff --git a/resources/autoblog.css b/resources/autoblog.css
new file mode 100644
index 0000000..259e2e8
--- /dev/null
+++ b/resources/autoblog.css
@@ -0,0 +1,48 @@
+/**
+ * autoblog.css
+ * ------------
+ * Please do NOT edit this file. Updating your Autoblogs farm will be easier.
+ * If you want to add your own CSS, use the file user.css
+ *
+ */
+
+body {background-color:#efefef;text-align:center;color:#333;font-family:sans-serif;}
+a {color:black;text-decoration:none;font-weight:bold;}
+a:hover {color:darkred;}
+h1 {text-align:center;font-size:40pt;text-shadow: #ccc 0px 5px 5px;}
+h2 {text-align:center;font-size: 16pt;margin:0 0 1em 0;font-style:italic;text-shadow: #ccc 0px 5px 5px; }
+.pbloc {background-color:white;padding: 12px 10px 12px 10px;border:1px solid #aaa;max-width:70em;margin:1em auto;text-align:justify;box-shadow:0px 5px 7px #aaa;}
+input[type="text"]{width:20em;}
+input[type="radio"] {width:1em;}
+input[type="submit"] {width:8em;}
+div.form {padding:0.2em;border:1px solid #fff;}
+div.form:hover {background-color:#FAF4DA;border:1px dotted;}
+#contentVignette {text-align: center;}
+.vignette {width:27%;height:2em;display: inline-block;text-align:justify;margin:0; padding:20px;background-color:#eee;border: 1px solid #888;}
+.vignette:hover {background-color:#fff;}
+.vignette .title {font-size: 14pt;text-shadow: #ccc 0px 5px 5px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;}
+.vignette .title a:hover {color:darkred; text-decoration:none;}
+.vignette .source {font-size:x-small;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;}
+.vignette .source a:hover {color:darkred; text-decoration:none;}
+.clear {clear:both;text-align:right;font-size:small;}
+#logo {float: right;}
+.bouton{background: -moz-linear-gradient(center top , #EDEDED 5%, #DFDFDF 100%) repeat scroll 0 0 #EDEDED;border: 1px none;padding: 10px;border: 1px solid #7777777;border-radius: 8px 8px 8px 8px;box-shadow: 0 1px 0 0 #FFFFFF inset;display: inline-block;}
+.success {color: green;}
+.error {color: red;}
+.button_list{display:none;}
+.button{-moz-box-shadow:inset 0 1px 0 0 #d9fbbe;-webkit-box-shadow:inset 0 1px 0 0 #d9fbbe;box-shadow:inset 0 1px 0 0 #d9fbbe;background:0;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#b8e356',endColorstr='#a5cc52');background-color:#b8e356;-moz-border-radius:6px;-webkit-border-radius:6px;border-radius:6px;border:1px solid #83c41a;display:inline-block;color:#fff;font-family:arial;font-size:14px;font-weight:700;text-decoration:none;text-shadow:1px 1px 0 #86ae47;padding:6px 24px;}
+.button:hover{background:0;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#a5cc52',endColorstr='#b8e356');background-color:#a5cc52;}
+.button:active{position:relative;top:1px;}
+.buttonactive{background-color:#aaa;-moz-border-radius:6px;-webkit-border-radius:6px;border-radius:6px;border:1px solid #83c41a;display:inline-block;color:#fff;font-family:arial;font-size:14px;font-weight:700;text-decoration:none;text-shadow:1px 1px 0 #86ae47;padding:6px 24px;}
+@media screen and (max-width:1024px) {
+ .vignette { width: 40%; }
+}
+@media screen and (max-width:640px) {
+ h1 { font-size:20pt; }
+ .button, .button:hover, .button:active, .buttonactive { display: block; margin: auto; text-align:center; }
+ .vignette { width: 80%; }
+}
+@media screen and (max-width:480px) {
+ #logo { max-width: 250px; }
+ input[type="text"]{width:15em;}
+}
\ No newline at end of file
diff --git a/resources/icon-logo.svg b/resources/icon-logo.svg
new file mode 100644
index 0000000..e3045dd
--- /dev/null
+++ b/resources/icon-logo.svg
@@ -0,0 +1,218 @@
+
+
+
+
+
+
+
+
+ image/svg+xml
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/resources/rss.png b/resources/rss.png
new file mode 100644
index 0000000000000000000000000000000000000000..315c4f4fa62cb720326ba3f54259666ba3999e42
GIT binary patch
literal 691
zcmV;k0!;mhP)bpQb1=l6TxbDZwj&S={?7%qx-u`rsG(Zp`-rh=e^=%((1yvsuf5d=&62Zj)Y
zH&JviNS_F4_Hj|T(1j4$p-!}kixP9&dB4uv^MveG?dGf%sUCoc2!IFxD6wHRA2^dX
zXRVk!-qSfk(jcaUKn#RP48(whfPlJUpApdrA!TQi_4D+fVoM;3I0gZ8{=Xv~Po;geVA+Em9@0Wq2
zr>OTZEGR05L=gf1T;ucCxq6Q6EgJiH@@-lVaAlQyw`jIF^c=&IVnj|95hHbE_cnt|
zTzZQ?F4Ne@(bH(~&3nM%m)I@ID{@jJ2qZPjr)jhpe9hViOwH5k&|T#EmmL3(vHeUQ
zq^!t^Al6JD;=mHq^Bg?J-8-zG2Od7gZbknG;K9czYjPqG*xjPo0k(c4%lPXTpw(qq
z@aGMnxtFS(np+2kC}
z7P02O874ZkJH$v#nCUVx$({yDN`IX@o2wyvTD#e`qN`_w5<}$3F+_ $expire) {
+ echo "too early";
+ die;
+}
+else {
+ if( file_exists($lockfile) )
+ unlink($lockfile);
+
+ if( file_put_contents($lockfile, date(DATE_RFC822)) ===FALSE) {
+ echo "Merci d'ajouter des droits d'écriture sur le dossier.";
+ die;
+ }
+}
+
+define('ROOT_DIR', __DIR__);
+if(file_exists("functions.php")){
+ include "functions.php";
+}else{
+ echo "functions.php not found !";
+ die;
+}
+
+if(file_exists("config.php")){
+ include "config.php";
+}else{
+ echo "config.php not found !";
+ die;
+}
+
+function serverUrl() {
+ $https = (!empty($_SERVER['HTTPS']) && (strtolower($_SERVER['HTTPS'])=='on')) || $_SERVER["SERVER_PORT"]=='443'; // HTTPS detection.
+ $serverport = ($_SERVER["SERVER_PORT"]=='80' || ($https && $_SERVER["SERVER_PORT"]=='443') ? '' : ':'.$_SERVER["SERVER_PORT"]);
+ return 'http'.($https?'s':'').'://'.$_SERVER["SERVER_NAME"].$serverport;
+}
+
+libxml_use_internal_errors(true);
+
+// $max_exec_time = temps max d'exécution en seconde
+function xsafimport($xsafremote, $max_exec_time) {
+ if( DEBUG )
+ echo "\n*Traitement $xsafremote en maximum $max_exec_time secondes";
+
+ $max_exec_time+=time()-1; // -1 car l'import prend environ 1 seconde
+
+ /* détection de ferme autoblog */
+ $json_import = file_get_contents($xsafremote);
+ if(!empty($json_import)) {
+ $to_update=array();
+ $json_import = json_decode($json_import, true);
+
+ if(!isset($json_import['meta']) || !isset($json_import['meta']['xsaf-version']) || $json_import['meta']['xsaf-version'] != XSAF_VERSION){
+ if(DEBUG){
+ echo "\nxsaf-version différentes !";
+ }
+ return false;
+ }
+
+ $get_remote_db = ($json_import['meta']['xsaf-db_transfer'] == "true") ? true : false;
+ $get_remote_media = ($json_import['meta']['xsaf-media_transfer'] == "true") ? true : false;
+
+ if(!empty($json_import['autoblogs'])) {
+ foreach ($json_import['autoblogs'] as $value) {
+
+ if(count($value)==4 && !empty($value['SITE_TYPE']) && !empty($value['SITE_TITLE']) && !empty($value['SITE_URL']) && !empty($value['FEED_URL'])) {
+ $sitetype = escape($value['SITE_TYPE']);
+ $sitename = escape($value['SITE_TITLE']);
+ $siteurl = escape($value['SITE_URL']);
+ // Do not use DetectRedirect because it's slow and it has been used when the feed was added
+ //$rssurl = DetectRedirect(escape($value['FEED_URL']));
+ $rssurl = escape($value['FEED_URL']);
+ }
+
+
+ /* TOO SLOW
+ $xml = simplexml_load_file($rssurl); // quick feed check
+ // ATOM feed && RSS 1.0 /RDF && RSS 2.0
+ $result = (!isset($xml->entry) && !isset($xml->item) && !isset($xml->channel->item)) ? false : true; */
+ $result = true;
+
+ /* autoblog */
+ if( $result === true ) {
+ $foldername = urlToFolderSlash($siteurl);
+
+ $errors = createAutoblog($sitetype, $sitename, $siteurl, $rssurl);
+ foreach( $errors AS $value) {
+ if( DEBUG )
+ echo ''. $value .'
';
+ }
+ if( empty($errors) && DEBUG ) {
+ echo 'autoblog '. $sitename .' crée avec succès (DL DB : '. var_dump($get_remote_db) .' - DL media : '. var_dump($get_remote_media) .') : '. $foldername .'
';
+ if( !ALLOW_REMOTE_DB_DL && !ALLOW_REMOTE_MEDIA_DL )
+ echo '';
+ }
+
+ /* ============================================================================================================================================================================== */
+ /* récupération de la DB distante */
+ if($get_remote_db == true && ALLOW_REMOTE_DB_DL ) {
+ $remote_db = str_replace("?export", $foldername."/articles.db", $xsafremote);
+ copy($remote_db, './'. $foldername .'/articles.db');
+ }
+
+ if($get_remote_media == true && ALLOW_REMOTE_MEDIA_DL ) {
+ $remote_media=str_replace("?export", $foldername."/?media", $xsafremote);
+ $json_media_import = file_get_contents($remote_media);
+ if(!empty($json_media_import))
+ {
+ mkdir('./'.$foldername.'/media/');
+ $json_media_import = json_decode($json_media_import, true);
+ $media_path=$json_media_import['url'];
+ if(!empty($json_media_import['files'])) {
+ foreach ($json_media_import['files'] as $value) {
+ copy($media_path.$value, './'.$foldername.'/media/'.$value);
+ }
+ }
+ }
+ }
+
+ /* ============================================================================================================================================================================== */
+ //TODO : tester si articles.db est une DB valide
+ //$to_update[] = serverUrl().preg_replace("/(.*)\/(.*)$/i","$1/".$foldername , $_SERVER['SCRIPT_NAME']); // url of the new autoblog
+ }
+
+ if( DEBUG )
+ echo 'time : '.($max_exec_time - time()) .'
';
+ if(time() >= $max_exec_time) {
+ if( DEBUG )
+ echo "Time out !
";
+ break;
+ }
+ }
+ }
+ else {
+ if( DEBUG )
+ echo "Format JSON incorrect.";
+ return false;
+ }
+ }
+ return;
+}
+
+if( DEBUG ) echo '';
+if( ALLOW_NEW_AUTOBLOGS and ALLOW_NEW_AUTOBLOGS_BY_XSAF && !empty($friends_autoblog_farm) ) {
+ foreach( $friends_autoblog_farm AS $value ) {
+ if( !empty($value) )
+ xsafimport($value, EXEC_TIME);
+ }
+ if(DEBUG) echo "XSAF import finished
";
+}
+elseif( DEBUG )
+ echo "XSAF désactivé. Positionnez les variables ALLOW_NEW_AUTOBLOGS et ALLOW_NEW_AUTOBLOGS_BY_XSAF à TRUE dans le fichier config.php pour l'activer.
";
+
+if( DEBUG ) echo '';
+?>