2013-04-22 12:00:26 +02:00
< ? php
/*
VroumVroumBlog 0.3 . 0
This blog automatically publishes articles from an external RSS 2.0 or ATOM feed .
Requirement for the source RSS feed :
- Source feed MUST be a valid RSS 2.0 , RDF 1.0 or ATOM 1.0 feed .
- Source feed MUST be valid UTF - 8
- Source feed MUST contain article body
This program is public domain . COPY COPY COPY !
*/
$vvbversion = '0.3.0' ;
if ( ! version_compare ( phpversion (), '5.3.0' , '>=' ))
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
2013-06-02 21:40:29 +02:00
define ( 'LOCAL_URL' , 'http' . ( isset ( $_SERVER [ 'HTTPS' ]) && $_SERVER [ 'HTTPS' ] == 'on' ? 's' : '' ) . " :// { $_SERVER [ 'HTTP_HOST' ] } { $_SERVER [ 'REQUEST_URI' ] } " );
2013-04-22 12:00:26 +02:00
}
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 '<h3>' . $e -> getMessage () . '</h3>' ;
exit ;
}
$error = " Error happened ! \n \n " .
$e -> getCode () . " - " . $e -> getMessage () . " \n \n In: " .
$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 ) . ' % \ '
2013-06-02 21:52:24 +02:00
OR title LIKE \ '%' . $this -> articles -> escapeString ( $query ) . ' % \ '
2013-04-22 12:00:26 +02:00
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' ] = '' ;
}
2013-04-25 13:02:33 +02:00
preg_match_all ( '!(src|href)\s*=\s*[\'"]?([^"\'<>\s]+\.(?:' . $extensions . ')[\'"])[\'"]?!i' , $content , $match , PREG_SET_ORDER );
2013-04-22 12:00:26 +02:00
foreach ( $match as $m )
{
2013-04-25 13:02:33 +02:00
$url = parse_url ( substr ( $m [ 2 ], 0 , - 1 ));
2013-04-22 12:00:26 +02:00
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 ;
}
}
2013-06-17 12:22:29 +02:00
// MEDIA IMPORT PROCESSING
if ( file_exists ( 'import.json' ))
{
if ( ! file_exists ( 'import.lock' ))
{
$json = json_decode ( file_get_contents ( 'import.json' ), true );
$count = count ( $json [ 'files' ]);
file_put_contents ( 'import.lock' , $count ); /* one-process locking */
$remoteurl = $json [ 'url' ];
if ( ! file_exists ( 'media' )) { mkdir ( 'media' ); }
$time = time ();
$maxtime = $time + 3 ; /* max exec time: 3 seconds */
while ( $time <= $maxtime )
{
$file = array_shift ( $json [ 'files' ]); /* get first element while unstacking */
if ( ! empty ( $file ))
{ copy ( $remoteurl . $file , " media/ $file " ); file_put_contents ( 'import.json' , json_encode ( $json )); } /* TOCHECK: get_headers() & filesize() when header "content-lenght" */
2013-06-30 18:19:21 +02:00
else { unlink ( 'import.json' ); break ; } /* first element empty: import finished */
2013-06-17 12:22:29 +02:00
$time = time ();
}
$count = count ( $json [ 'files' ]);
unlink ( 'import.lock' );
}
/* return import information page */ ?>
<! DOCTYPE html >
< html lang = " en " dir = " ltr " >
< head >
< meta charset = " utf-8 " >
< meta http - equiv = " Refresh " content = " 1 " >
< title > Autoblog media import </ title >
</ head >
< body >
Import running : < ? php if ( isset ( $count )) { echo $count ; } else { echo file_get_contents ( 'import.lock' ); } ?> files remaining.<br>
The page should refresh every second . If not , < a href = " javascript:window.location.reload() " > refresh manually </ a >.
</ body >
</ html >
< ? php exit ;}
2013-04-22 12:00:26 +02:00
// 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 ' < ? xml version = " 1.0 " encoding = " UTF-8 " ?>
< feed xmlns = " http://www.w3.org/2005/Atom " xmlns : thr = " http://purl.org/syndication/thread/1.0 " xml : lang = " fr-FR " >
< title type = " text " > '.escape($config->site_title).' </ title >
< subtitle type = " text " > '.escape(html_entity_decode(strip_tags($config->site_description), ENT_COMPAT, ' UTF - 8 ')).' </ subtitle >
< updated > '.date(DATE_ATOM, filemtime(ARTICLES_DB_FILE)).' </ updated >
< link rel = " alternate " type = " text/html " href = " '.str_replace('?feed./', '', LOCAL_URL).' " />
< id > '.LOCAL_URL.' </ id >
< link rel = " self " type = " application/atom+xml " href = " '.LOCAL_URL.' " />
< generator uri = " https://github.com/mitsukarenai/Projet-Autoblog " version = " 3 " > Projet Autoblog </ generator > ' ;
foreach ( $vvb -> listLastArticles () as $art )
{
echo '
< entry >
< author >
< name > '.escape($config->site_title).' </ name >
< uri > '.escape($config->site_url).' </ uri >
</ author >
< title type = " html " ><! [ CDATA [ '.escape($art[' title ']).' ]] ></ title >
< link rel = " alternate " type = " text/html " href = " '.str_replace('?feed', '?', LOCAL_URL).urlencode(str_replace('./?', '', $vvb->getLocalURL ( $art ))).' " />
< id > '.str_replace(' ? feed ', ' ? ', LOCAL_URL).urlencode(str_replace(' ./ ? ', ' ', $vvb->getLocalURL($art))).' </ id >
< updated > '.date(DATE_ATOM, $art[' date ']).' </ updated >
< content type = " html " >
2013-06-28 11:33:17 +02:00
<! [ CDATA [( < a href = " '.escape( $art['url'] ).' " > source </ a > ) < br /> '.escape_content($art[' content ']).' ]] >
2013-04-22 12:00:26 +02:00
</ content >
</ entry > ' ;
}
echo '
</ feed > ' ;
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 ( '<opml></opml>' );
$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 : 30 px 3 % ; max - width : 70 em ; margin : 0 auto ; }
. article . title { margin - bottom : 1 em ; }
. 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 : 12 px 10 px 12 px 10 px ; border : 1 px solid #aaa;max-width:70em;margin:1em auto;box-shadow:0px 5px 7px #aaa; }
. pagination b { font - size : 1.2 em ; 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 : 2 em ; }
. 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.8 em ; }
. content pre , . content blockquote { background : #ddd; border: 1px solid #999; padding: 0.2em; max-width: 100%; overflow: auto; }
. content h1 { font - size : 1.5 em ; }
. content h2 { font - size : 1.4 em ; color : #000; }
. result h3 a { color : darkblue ; text - decoration : none ; text - shadow : 1 px 1 px 1 px #fff; }
#error { position: fixed; top: 0; left: 0; right: 0; padding: 1%; background: #fff; border-bottom: 2px solid red; color: darkred; }
' ;
2013-06-30 16:40:02 +02:00
if ( $site_type == 'generic' || $site_type == 'youtube' ) // custom CSS for generic
2013-04-22 12:00:26 +02:00
{
$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.8 em ; color : #666; }
. article { background - color : white ; padding : 12 px 10 px 12 px 10 px ; border : 1 px 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 : 10 em ; white - space : nowrap ; overflow : hidden ; text - overflow : ellipsis ; font - size : 0.7 em ; margin : 0 ; color : #333; text-shadow: 1px 1px 1px #fff; }
. article . title h2 a { color : #333; text-decoration:none; }
. article { background - color : white ; padding : 12 px 10 px 12 px 10 px ; border : 1 px solid #aaa;max-width:70em;margin:0 auto;box-shadow:0px 5px 7px #aaa; }
. article . source { font - size : 0.8 em ; color : #666; }
. footer { margin - top : 1 em ; text - align : center ; font - size : small ; color : #333; clear: both; }
. content { font - size : 0.9 em ; 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 : 12 px 10 px 12 px 10 px ; border : 1 px solid #aaa;max-width:70em;margin:1em auto;box-shadow:0px 5px 7px #aaa; }
. article . source { margin - top : 1 em ; font - size : 0.8 em ; color : #666; }
. footer { text - align : center ; font - size : small ; color : #333; clear: both; }';
}
// HTML HEADER
echo '
<! DOCTYPE html >
< html lang = " en " dir = " ltr " >
< head >
< meta http - equiv = " Content-Type " content = " text/html; charset=UTF-8 " >
< title > '.escape($config->site_title).' </ title >
< link rel = " canonical " href = " '.escape( $config->site_url ).' " >
< link rel = " alternate " type = " application/atom+xml " title = " '.__('ATOM Feed').' " href = " ?feed " >
< style type = " text/css " media = " screen,projection " >
'.$css.'
</ style >
</ head >
< body >
< div class = " header " >
< h1 >< a href = " ../../ " style = " font-size:0.8em; " > PROJET AUTOBLOG '. (strlen(HEAD_TITLE) > 0 ? ' ~ '. HEAD_TITLE : ' ') .' </ a ></ h1 >
< hr >
< h1 >< a href = " ./ " > '.escape($config->site_title).' </ a ></ h1 > ' ;
if ( ! empty ( $config -> site_description ))
echo '<p>' . $config -> site_description . '<br><a href="../../">⇐ retour index</a></p>' ;
echo '
< form method = " get " action = " '.escape(LOCAL_URL).' " class = " searchForm " >
< div >
< input type = " text " name = " q " value = " '.escape( $search ).' " >
< input type = " submit " value = " '.__('Search').' " >
</ div >
</ form >
</ div >
' ;
if ( $vvb -> mustUpdate ())
{
echo '
< div class = " article " >
< div class = " title " >
< h2 > '.__(' Update ').' </ h2 >
</ div >
< div class = " content " id = " update " >
'.__(' Updating database ... Please wait . ').'
</ div >
</ div > ' ;
}
if ( ! empty ( $search ))
{
$results = $vvb -> searchArticles ( $search );
$text = sprintf ( __ ( '<b>%d</b> results for <i>%s</i>' ), count ( $results ), escape ( $search ));
echo '
< div class = " article " >
< div class = " title " >
< h2 > '.__(' Search ').' </ h2 >
'.$text.'
</ div >
</ div > ' ;
foreach ( $results as $art )
{
echo '
< div class = " article result " >
< h3 >< a href = " ./?'.escape( $art['uri'] ).' " > '.escape($art[' title ']).' </ a ></ h3 >
< p > '.$art[' content '].' </ p >
</ div > ' ;
}
}
elseif ( ! is_null ( $article ))
{
if ( ! $article )
{
echo '
< div class = " article " >
< div class = " title " >
< h2 > '.__(' Not Found ').' </ h2 >
'.(!empty($uri) ? ' < p >< tt > '.escape($vvb->getLocalURL($uri)) . ' </ tt ></ p > ' : ' ').'
'.__(' Article not found . ').'
</ div >
</ div > ' ;
}
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 '<div class="pagination">' ;
if ( $page > 1 )
echo '<a href="' . $vvb -> getLocalURL ( $page - 1 ) . '">← ' . __ ( 'Newer' ) . '</a> ' ;
$last = ceil ( $max / $config -> articles_per_page );
for ( $i = 1 ; $i <= $last ; $i ++ )
{
echo '<a href="' . $vvb -> getLocalURL ( $i ) . '">' . ( $i == $page ? '<b>' . $i . '</b>' : $i ) . '</a> ' ;
}
if ( $page < $last )
echo '<a href="' . $vvb -> getLocalURL ( $page + 1 ) . '">' . __ ( 'Older' ) . ' →</a> ' ;
echo '</div>' ;
}
}
echo '
< div class = " footer " >
< p > Propulsé par < a href = " https://github.com/mitsukarenai/Projet-Autoblog " > Projet Autoblog '.$vvbversion.' </ a > - < a href = " ?feed " > '.__(' ATOM Feed ').' </ a ></ p >
< p > '.__(' Download : ').' < a href = " ./'.basename(CONFIG_FILE).' " > '.__(' configuration ').' </ a > ( < a href = " ?opml " > OPML </ a > )
- < a href = " ./'.basename(ARTICLES_DB_FILE).' " > '.__(' articles ').' </ a >< p />
< p >< a href = " ./?media " > '.__(' Media export ').' < sup > JSON </ sup ></ a ></ p >
</ div > ' ;
if ( $vvb -> mustUpdate ())
{
try {
ob_end_flush ();
flush ();
}
catch ( Exception $e )
{
// Silent, not critical
}
try {
$updated = $vvb -> update ();
}
catch ( VroumVroum_Feed_Exception $e )
{
echo '
< div id = " error " >
'.escape($e->getMessage()).'
</ div > ' ;
$updated = 0 ;
}
if ( $updated > 0 )
{
echo '
< script type = " text/javascript " >
window . onload = function () {
document . getElementById ( " update " ) . innerHTML = " '.__('Update complete!').' <a href= \\ " #reload\\" onclick=\\"window.location.reload();\\">'.__('Click here to reload this webpage.').'</a>";
};
</ script > ' ;
}
else
{
echo '
< script type = " text/javascript " >
window . onload = function () {
document . body . removeChild ( document . getElementById ( " update " ) . parentNode );
};
</ script > ' ;
}
}
echo '
</ body >
</ html > ' ;
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 '
< div class = " article " >
< div class = " title " >
< h2 >< a href = " '. $vvb->getLocalURL ( $article ).' " > '.escape($article[' title ']).' </ a ></ h2 >
'.strftime(__(' _date_format '), $article[' date ']).'
</ div >
< div class = " content " > '.escape_content($article[' content ']).' </ div >
< p class = " source " > '.__(' Source : ').' < a href = " '.escape( $article['url'] ).' " > '.escape($article[' url ']).' </ a ></ p >
< br style = " clear: both; " />
</ div > ' ;
}
?>