summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gitattributes2
-rw-r--r--config/twitter.json (renamed from config.json)bin235 -> 235 bytes
-rw-r--r--http/.htaccess2
-rw-r--r--http/index.php157
-rw-r--r--providers/Provider.php54
-rw-r--r--providers/Twitter.php117
-rw-r--r--spamlinks.dbbin16384 -> 53248 bytes
7 files changed, 205 insertions, 127 deletions
diff --git a/.gitattributes b/.gitattributes
index 7daec9b..18ef3a0 100644
--- a/.gitattributes
+++ b/.gitattributes
@@ -1 +1 @@
-config.json filter=git-crypt diff=git-crypt
+config/*.json filter=git-crypt diff=git-crypt
diff --git a/config.json b/config/twitter.json
index f293625..f293625 100644
--- a/config.json
+++ b/config/twitter.json
Binary files differ
diff --git a/http/.htaccess b/http/.htaccess
index 9f57019..e3378e5 100644
--- a/http/.htaccess
+++ b/http/.htaccess
@@ -1,2 +1,2 @@
RewriteEngine On
-RewriteRule (.*)/(.*).xml index.php?user=$1&format=$2
+RewriteRule (.*)/(.*).xml /index.php?format=$2&query=$1
diff --git a/http/index.php b/http/index.php
index 572f857..0c7ad7a 100644
--- a/http/index.php
+++ b/http/index.php
@@ -1,146 +1,53 @@
<?php
-$config = json_decode(file_get_contents('../config.json'), TRUE);
+$format = $_REQUEST['format'];
-require_once('../lib/codebird-php/src/codebird.php');
-
-\Codebird\Codebird::setConsumerKey($config['key'], $config['secret']);
-\Codebird\Codebird::setBearerToken($config['token']);
-
-$cb = \Codebird\Codebird::getInstance();
-
-$user = $_GET['user'];
-$spamFilter = FALSE;
-
-$filterMatch = [];
-if (preg_match('/^(.*)\/spamfilter$/', $user, $filterMatch)) {
- $user = $filterMatch[1];
- $spamFilter = TRUE;
+if (!in_array($format, ['atom', 'rss'])) {
+ header('HTTP/1.1 400');
+ die('Invalid feed format.');
}
-if ($user) {
-
- $cacheFile = '../cache/'.$user.'.json';
- $cacheTime = file_exists($cacheFile) ? filemtime($cacheFile) : 0;
+$params = explode('/', $_REQUEST['query']);
- $content = '';
- if ($cacheTime > strtotime('-15 minutes')) {
- $content = json_decode(file_get_contents($cacheFile));
- }
- else {
- $content = $cb->statuses_userTimeline([
- 'screen_name' => $user,
- 'count' => 200,
- 'exclude_replies' => TRUE
- ], TRUE);
- if (isset($content->rate)) {
- unset($content->rate);
- }
- file_put_contents($cacheFile, json_encode($content));
- $cacheTime = time();
- }
-
- if ($content->httpstatus !== 200) {
- header('HTTP/1.1 '.$content->httpstatus);
- if (isset($content->error)) {
- print $content->error;
- die();
- }
- if (isset($content->errors)) {
- foreach ($content->errors as $error) {
- print $error->message.' ('.$error->code.')<br />';
- }
- die();
- }
- }
-
- unset($content->httpstatus);
+if (count($params) < 2) {
+ header('HTTP/1.1 400');
+ die('Not enough parameters.');
+}
- if ($spamFilter) {
- $db = new PDO('sqlite:../spamlinks.db');
- $spamQuery = $db->prepare('SELECT id FROM spamlinks WHERE username = :name');
- $spamQuery->bindParam(':name', $user);
- $spamQuery->execute();
- $spamContent = array_map(
- function($row) {
- return $row[0];
- },
- $spamQuery->fetchAll()
- );
- $spamHashes = [];
- $filteredContent = [];
- foreach ($content as $c) {
- if (!in_array($c->id_str, $spamContent)) {
- $twitterURLs = FALSE;
- $urls = array_filter(
- array_map(
- function($url) {
- return $url->expanded_url;
- },
- $c->entities->urls
- ),
- function($url) use(&$twitterURLs) {
- $urlParts = parse_url($url);
- if ($urlParts['host'] == 'twitter.com') {
- $twitterURLs = TRUE;
- return FALSE;
- }
- return TRUE;
- }
- );
- if (!$urls) {
- if (!$twitterURLs) {
- $filteredContent[] = $c;
- }
- } else {
- sort($urls);
- $urlHash = md5(implode('|', $urls));
- if (isset($filteredContent[$urlHash])) {
- $spamHashes[] = $c->id_str;
- }
- $filteredContent[$urlHash] = $c;
- }
- }
- }
- usort($filteredContent, function($c1, $c2) { return strcmp($c1->id_str, $c2->id_str); });
- $content = $filteredContent;
- if ($spamHashes) {
- foreach ($spamHashes as $hash) {
- $insertQuery = $db->prepare(
- 'INSERT INTO spamlinks(id, username) VALUES (?, ?)'
- );
- $insertQuery->bindParam(1, $hash);
- $insertQuery->bindParam(2, $user);
- $insertQuery->execute();
- }
- }
- }
+$provider = ucfirst(array_shift($params));
+$feed = array_shift($params);
+$parsedParams = [];
+foreach ($params as $param) {
+ $splitParam = explode(':', $param, 2);
+ $parsedParams[$splitParam[0]] = count($splitParam) > 1 ? $plitParam[1] : TRUE;
+}
- require_once('../lib/smarty3/Smarty.class.php');
+require_once('../providers/' . $provider . '.php');
+$provider = '\\Providers\\' . $provider;
+$provider = new $provider($feed, $parsedParams);
+$content = $provider->get();
- $smarty = new Smarty();
- $smarty->setCacheDir('../cache/smarty');
- $smarty->setCompileDir('../cache/smarty/compile');
- $smarty->setTemplateDir('../templates');
+require_once('../lib/smarty3/Smarty.class.php');
- $smarty->assign('cacheTime', $cacheTime);
- $smarty->assign('user', $user);
- $smarty->assign('content', $content);
+$smarty = new Smarty();
+$smarty->setCacheDir('../cache/smarty');
+$smarty->setCompileDir('../cache/smarty/compile');
+$smarty->setTemplateDir('../templates');
- $format = $_GET['format'];
+$smarty->assign('cacheTime', $provider->cacheTime());
+$smarty->assign('user', $feed);
+$smarty->assign('content', $provider->get());
- switch ($format) {
- case 'rss':
+switch ($format) {
+case 'rss':
header('Content-Type: application/rss+xml');
$smarty->display('rss.tpl');
break;
- case 'atom':
- default:
+case 'atom':
+default:
header('Content-Type: application/atom+xml');
$smarty->display('atom.tpl');
break;
- }
-
}
?>
diff --git a/providers/Provider.php b/providers/Provider.php
new file mode 100644
index 0000000..0c3f344
--- /dev/null
+++ b/providers/Provider.php
@@ -0,0 +1,54 @@
+<?php
+
+namespace Providers;
+
+abstract class Provider {
+
+ protected $_options = [];
+ protected $_feed = NULL;
+ protected $_cacheTimeout = '15 minutes';
+ protected $_cacheTime;
+
+ public function __construct($feed, $options=[]) {
+ $this->_feed = $feed;
+ $this->_options = $options;
+ }
+
+ abstract protected function _getCachePath();
+
+ protected function _getCache($path) {
+ return file_get_contents($path);
+ }
+
+ abstract protected function _fetchItems();
+
+ abstract protected function _spamFilter($items);
+
+ protected function _getItems() {
+ $cacheFile = sprintf($this->_getCachePath(), $this->_feed);
+ $this->_cacheTime = file_exists($cacheFile) ? filemtime($cacheFile) : 0;
+ if ($this->_cacheTime > strtotime('-' . $this->_cacheTimeout)) {
+ return json_decode($this->_getCache($cacheFile));
+ } else {
+ $content = $this->_fetchItems();
+ file_put_contents($cacheFile, json_encode($content));
+ $this->_cacheTime = time();
+ return $content;
+ }
+ }
+
+ public function get() {
+ $items = $this->_getItems();
+ if (isset($this->_options['spamfilter'])) {
+ $items = $this->_spamFilter($items);
+ }
+ return $items;
+ }
+
+ public function cacheTime() {
+ return $this->_cacheTime;
+ }
+
+}
+
+?>
diff --git a/providers/Twitter.php b/providers/Twitter.php
new file mode 100644
index 0000000..868bb28
--- /dev/null
+++ b/providers/Twitter.php
@@ -0,0 +1,117 @@
+<?php
+
+namespace Providers;
+
+require_once('Provider.php');
+require_once('../lib/codebird-php/src/codebird.php');
+
+
+class Twitter extends \Providers\Provider {
+
+ private $_api;
+
+ public function __construct($feed, $options=[]) {
+ parent::__construct($feed, $options);
+ $config = json_decode(file_get_contents('../config/twitter.json'), TRUE);
+ \Codebird\Codebird::setConsumerKey($config['key'], $config['secret']);
+ \Codebird\Codebird::setBearerToken($config['token']);
+ $this->_api = \Codebird\Codebird::getInstance();
+ }
+
+ protected function _getCachePath() {
+ return '../cache/twitter.%s.json';
+ }
+
+ protected function _fetchItems() {
+ $content = $this->_api->statuses_userTimeline([
+ 'screen_name' => $this->_feed,
+ 'count' => 200,
+ 'exclude_replies' => TRUE
+ ], TRUE);
+ if (isset($content->rate)) {
+ unset($content->rate);
+ }
+
+ if ($content->httpstatus !== 200) {
+ $errorString = '';
+ if (isset($content->error)) {
+ $errorString = $content->error;
+ }
+ if (isset($content->errors)) {
+ $errorString = implode('\n', array_map(
+ function($error) {
+ return $error->message . ' (' . $error->code . ')';
+ }, $content->errors
+ ));
+ }
+ throw new Exception($errorString);
+ }
+ unset($content->httpstatus);
+
+ return $content;
+ }
+
+ protected function _spamFilter($items) {
+ $db = new \PDO('sqlite:../spamlinks.db');
+ $spamQuery = $db->prepare('SELECT id FROM twitter WHERE username = :name');
+ $spamQuery->bindParam(':name', $user);
+ $spamQuery->execute();
+ $spamContent = array_map(
+ function($row) {
+ return $row[0];
+ },
+ $spamQuery->fetchAll()
+ );
+ $spamHashes = [];
+ $filteredContent = [];
+ foreach ($items as $c) {
+ if (!in_array($c->id_str, $spamContent)) {
+ $twitterURLs = FALSE;
+ $urls = array_filter(
+ array_map(
+ function($url) {
+ return $url->expanded_url;
+ },
+ $c->entities->urls
+ ),
+ function($url) use(&$twitterURLs) {
+ $urlParts = parse_url($url);
+ if ($urlParts['host'] == 'twitter.com') {
+ $twitterURLs = TRUE;
+ return FALSE;
+ }
+ return TRUE;
+ }
+ );
+ if (!$urls) {
+ if (!$twitterURLs) {
+ $filteredContent[] = $c;
+ }
+ } else {
+ sort($urls);
+ $urlHash = md5(implode('|', $urls));
+ if (isset($filteredContent[$urlHash])) {
+ $spamHashes[] = $c->id_str;
+ }
+ $filteredContent[$urlHash] = $c;
+ }
+ }
+ }
+ usort($filteredContent, function($c1, $c2) { return strcmp($c1->id_str, $c2->id_str); });
+ $content = $filteredContent;
+ if ($spamHashes) {
+ foreach ($spamHashes as $hash) {
+ $insertQuery = $db->prepare(
+ 'INSERT INTO twitter(id, username) VALUES (?, ?)'
+ );
+ $insertQuery->bindParam(1, $hash);
+ $insertQuery->bindParam(2, $user);
+ $insertQuery->execute();
+ }
+ }
+ return $content;
+ }
+
+}
+
+?>
diff --git a/spamlinks.db b/spamlinks.db
index d26a64f..cdd3e1e 100644
--- a/spamlinks.db
+++ b/spamlinks.db
Binary files differ