update 1.14
|
@ -4,7 +4,7 @@ Tiny Tiny RSS
|
|||
Web-based news feed aggregator, designed to allow you to read news from
|
||||
any location, while feeling as close to a real desktop application as possible.
|
||||
|
||||
http://tt-rss.org
|
||||
http://tt-rss.org (http://mirror.tt-rss.org)
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
|
|
0
source/cache/export/.empty
vendored
Executable file
0
source/cache/images/.empty
vendored
Executable file
0
source/cache/js/.empty
vendored
Executable file
0
source/cache/simplepie/.empty
vendored
Executable file
0
source/cache/upload/.empty
vendored
Normal file
|
@ -2,7 +2,7 @@
|
|||
|
||||
class API extends Handler {
|
||||
|
||||
const API_LEVEL = 7;
|
||||
const API_LEVEL = 9;
|
||||
|
||||
const STATUS_OK = 0;
|
||||
const STATUS_ERR = 1;
|
||||
|
@ -77,6 +77,7 @@ class API extends Handler {
|
|||
$this->wrap(self::STATUS_OK, array("session_id" => session_id(),
|
||||
"api_level" => self::API_LEVEL));
|
||||
} else { // else we are not logged in
|
||||
user_error("Failed login attempt for $login from {$_SERVER['REMOTE_ADDR']}", E_USER_WARNING);
|
||||
$this->wrap(self::STATUS_ERR, array("error" => "LOGIN_ERROR"));
|
||||
}
|
||||
} else {
|
||||
|
@ -199,9 +200,13 @@ class API extends Handler {
|
|||
$include_nested = sql_bool_to_bool($_REQUEST["include_nested"]);
|
||||
$sanitize_content = !isset($_REQUEST["sanitize"]) ||
|
||||
sql_bool_to_bool($_REQUEST["sanitize"]);
|
||||
$force_update = sql_bool_to_bool($_REQUEST["force_update"]);
|
||||
|
||||
$override_order = false;
|
||||
switch ($_REQUEST["order_by"]) {
|
||||
case "title":
|
||||
$override_order = "ttrss_entries.title";
|
||||
break;
|
||||
case "date_reverse":
|
||||
$override_order = "score DESC, date_entered, updated";
|
||||
break;
|
||||
|
@ -218,7 +223,7 @@ class API extends Handler {
|
|||
$headlines = $this->api_get_headlines($feed_id, $limit, $offset,
|
||||
$filter, $is_cat, $show_excerpt, $show_content, $view_mode, $override_order,
|
||||
$include_attachments, $since_id, $search, $search_mode,
|
||||
$include_nested, $sanitize_content);
|
||||
$include_nested, $sanitize_content, $force_update);
|
||||
|
||||
$this->wrap(self::STATUS_OK, $headlines);
|
||||
} else {
|
||||
|
@ -310,7 +315,7 @@ class API extends Handler {
|
|||
if ($article_id) {
|
||||
|
||||
$query = "SELECT id,title,link,content,feed_id,comments,int_id,
|
||||
marked,unread,published,score,
|
||||
marked,unread,published,score,note,lang,
|
||||
".SUBSTRING_FOR_DATE."(updated,1,16) as updated,
|
||||
author,(SELECT title FROM ttrss_feeds WHERE id = feed_id) AS feed_title
|
||||
FROM ttrss_entries,ttrss_user_entries
|
||||
|
@ -342,7 +347,9 @@ class API extends Handler {
|
|||
"feed_id" => $line["feed_id"],
|
||||
"attachments" => $attachments,
|
||||
"score" => (int)$line["score"],
|
||||
"feed_title" => $line["feed_title"]
|
||||
"feed_title" => $line["feed_title"],
|
||||
"note" => $line["note"],
|
||||
"lang" => $line["lang"]
|
||||
);
|
||||
|
||||
foreach (PluginHost::getInstance()->get_hooks(PluginHost::HOOK_RENDER_ARTICLE_API) as $p) {
|
||||
|
@ -423,7 +430,7 @@ class API extends Handler {
|
|||
|
||||
$checked = false;
|
||||
foreach ($article_labels as $al) {
|
||||
if ($al[0] == $line['id']) {
|
||||
if (feed_to_label_id($al[0]) == $line['id']) {
|
||||
$checked = true;
|
||||
break;
|
||||
}
|
||||
|
@ -447,7 +454,7 @@ class API extends Handler {
|
|||
$assign = (bool) $this->dbh->escape_string($_REQUEST['assign']) == "true";
|
||||
|
||||
$label = $this->dbh->escape_string(label_find_caption(
|
||||
$label_id, $_SESSION["uid"]));
|
||||
feed_to_label_id($label_id), $_SESSION["uid"]));
|
||||
|
||||
$num_updated = 0;
|
||||
|
||||
|
@ -511,7 +518,7 @@ class API extends Handler {
|
|||
if ($unread || !$unread_only) {
|
||||
|
||||
$row = array(
|
||||
"id" => $cv["id"],
|
||||
"id" => (int) $cv["id"],
|
||||
"title" => $cv["description"],
|
||||
"unread" => $cv["counter"],
|
||||
"cat_id" => -2,
|
||||
|
@ -557,7 +564,7 @@ class API extends Handler {
|
|||
|
||||
if ($unread || !$unread_only) {
|
||||
$row = array(
|
||||
"id" => $line["id"],
|
||||
"id" => (int) $line["id"],
|
||||
"title" => $line["title"],
|
||||
"unread" => $unread,
|
||||
"is_cat" => true,
|
||||
|
@ -626,7 +633,28 @@ class API extends Handler {
|
|||
$filter, $is_cat, $show_excerpt, $show_content, $view_mode, $order,
|
||||
$include_attachments, $since_id,
|
||||
$search = "", $search_mode = "",
|
||||
$include_nested = false, $sanitize_content = true) {
|
||||
$include_nested = false, $sanitize_content = true, $force_update = false) {
|
||||
|
||||
if ($force_update && $feed_id > 0 && is_numeric($feed_id)) {
|
||||
// Update the feed if required with some basic flood control
|
||||
|
||||
$result = db_query(
|
||||
"SELECT cache_images,".SUBSTRING_FOR_DATE."(last_updated,1,19) AS last_updated
|
||||
FROM ttrss_feeds WHERE id = '$feed_id'");
|
||||
|
||||
if (db_num_rows($result) != 0) {
|
||||
$last_updated = strtotime(db_fetch_result($result, 0, "last_updated"));
|
||||
$cache_images = sql_bool_to_bool(db_fetch_result($result, 0, "cache_images"));
|
||||
|
||||
if (!$cache_images && time() - $last_updated > 120) {
|
||||
include "rssfuncs.php";
|
||||
update_rss_feed($feed_id, true, true);
|
||||
} else {
|
||||
db_query("UPDATE ttrss_feeds SET last_updated = '1970-01-01', last_update_started = '1970-01-01'
|
||||
WHERE id = '$feed_id'");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$qfh_ret = queryFeedHeadlines($feed_id, $limit,
|
||||
$view_mode, $is_cat, $search, $search_mode,
|
||||
|
@ -638,7 +666,7 @@ class API extends Handler {
|
|||
$headlines = array();
|
||||
|
||||
while ($line = db_fetch_assoc($result)) {
|
||||
$line["content_preview"] = truncate_string(strip_tags($line["content_preview"]), 100);
|
||||
$line["content_preview"] = truncate_string(strip_tags($line["content"]), 100);
|
||||
foreach (PluginHost::getInstance()->get_hooks(PluginHost::HOOK_QUERY_HEADLINES) as $p) {
|
||||
$line = $p->hook_query_headlines($line, 100, true);
|
||||
}
|
||||
|
@ -700,6 +728,8 @@ class API extends Handler {
|
|||
$headline_row["author"] = $line["author"];
|
||||
|
||||
$headline_row["score"] = (int)$line["score"];
|
||||
$headline_row["note"] = $line["note"];
|
||||
$headline_row["lang"] = $line["lang"];
|
||||
|
||||
foreach (PluginHost::getInstance()->get_hooks(PluginHost::HOOK_RENDER_ARTICLE_API) as $p) {
|
||||
$headline_row = $p->hook_render_article_api(array("headline" => $headline_row));
|
||||
|
|
|
@ -30,7 +30,6 @@ class Article extends Handler_Protected {
|
|||
$id = $this->dbh->escape_string($_REQUEST["id"]);
|
||||
$cids = explode(",", $this->dbh->escape_string($_REQUEST["cids"]));
|
||||
$mode = $this->dbh->escape_string($_REQUEST["mode"]);
|
||||
$omode = $this->dbh->escape_string($_REQUEST["omode"]);
|
||||
|
||||
// in prefetch mode we only output requested cids, main article
|
||||
// just gets marked as read (it already exists in client cache)
|
||||
|
@ -108,7 +107,7 @@ class Article extends Handler_Protected {
|
|||
|
||||
// only check for our user data here, others might have shared this with different content etc
|
||||
$result = db_query("SELECT id FROM ttrss_entries, ttrss_user_entries WHERE
|
||||
link = '$url' AND ref_id = id AND owner_uid = '$owner_uid' LIMIT 1");
|
||||
guid = '$guid' AND ref_id = id AND owner_uid = '$owner_uid' LIMIT 1");
|
||||
|
||||
if (db_num_rows($result) != 0) {
|
||||
$ref_id = db_fetch_result($result, 0, "id");
|
||||
|
|
|
@ -16,7 +16,6 @@ class Dlg extends Handler_Protected {
|
|||
print __("If you have imported labels and/or filters, you might need to reload preferences to see your new data.") . "</p>";
|
||||
|
||||
print "<div class=\"prefFeedOPMLHolder\">";
|
||||
$owner_uid = $_SESSION["uid"];
|
||||
|
||||
$this->dbh->query("BEGIN");
|
||||
|
||||
|
@ -176,7 +175,7 @@ class Dlg extends Handler_Protected {
|
|||
|
||||
while ($row = $this->dbh->fetch_assoc($result)) {
|
||||
$tmp = htmlspecialchars($row["tag_name"]);
|
||||
print "<option value=\"" . str_replace(" ", "%20", $tmp) . "\">$tmp</option>";
|
||||
print "<option value=\"$tmp\">$tmp</option>";
|
||||
}
|
||||
|
||||
print "</select>";
|
||||
|
|
|
@ -4,5 +4,7 @@ class FeedEnclosure {
|
|||
public $type;
|
||||
public $length;
|
||||
public $title;
|
||||
public $height;
|
||||
public $width;
|
||||
}
|
||||
?>
|
||||
|
|
|
@ -43,9 +43,9 @@ class FeedItem_Atom extends FeedItem_Common {
|
|||
$base = $this->xpath->evaluate("string(ancestor-or-self::*[@xml:base][1]/@xml:base)", $link);
|
||||
|
||||
if ($base)
|
||||
return rewrite_relative_url($base, $link->getAttribute("href"));
|
||||
return rewrite_relative_url($base, trim($link->getAttribute("href")));
|
||||
else
|
||||
return $link->getAttribute("href");
|
||||
return trim($link->getAttribute("href"));
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -55,7 +55,7 @@ class FeedItem_Atom extends FeedItem_Common {
|
|||
$title = $this->elem->getElementsByTagName("title")->item(0);
|
||||
|
||||
if ($title) {
|
||||
return $title->nodeValue;
|
||||
return trim($title->nodeValue);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -106,13 +106,13 @@ class FeedItem_Atom extends FeedItem_Common {
|
|||
|
||||
foreach ($categories as $cat) {
|
||||
if ($cat->hasAttribute("term"))
|
||||
array_push($cats, $cat->getAttribute("term"));
|
||||
array_push($cats, trim($cat->getAttribute("term")));
|
||||
}
|
||||
|
||||
$categories = $this->xpath->query("dc:subject", $this->elem);
|
||||
|
||||
foreach ($categories as $cat) {
|
||||
array_push($cats, $cat->nodeValue);
|
||||
array_push($cats, trim($cat->nodeValue));
|
||||
}
|
||||
|
||||
return $cats;
|
||||
|
@ -137,7 +137,7 @@ class FeedItem_Atom extends FeedItem_Common {
|
|||
}
|
||||
}
|
||||
|
||||
$enclosures = $this->xpath->query("media:content | media:group/media:content", $this->elem);
|
||||
$enclosures = $this->xpath->query("media:content", $this->elem);
|
||||
|
||||
foreach ($enclosures as $enclosure) {
|
||||
$enc = new FeedEnclosure();
|
||||
|
@ -145,6 +145,8 @@ class FeedItem_Atom extends FeedItem_Common {
|
|||
$enc->type = $enclosure->getAttribute("type");
|
||||
$enc->link = $enclosure->getAttribute("url");
|
||||
$enc->length = $enclosure->getAttribute("length");
|
||||
$enc->height = $enclosure->getAttribute("height");
|
||||
$enc->width = $enclosure->getAttribute("width");
|
||||
|
||||
$desc = $this->xpath->query("media:description", $enclosure)->item(0);
|
||||
if ($desc) $enc->title = strip_tags($desc->nodeValue);
|
||||
|
@ -152,6 +154,46 @@ class FeedItem_Atom extends FeedItem_Common {
|
|||
array_push($encs, $enc);
|
||||
}
|
||||
|
||||
|
||||
$enclosures = $this->xpath->query("media:group", $this->elem);
|
||||
|
||||
foreach ($enclosures as $enclosure) {
|
||||
$enc = new FeedEnclosure();
|
||||
|
||||
$content = $this->xpath->query("media:content", $enclosure)->item(0);
|
||||
|
||||
if ($content) {
|
||||
$enc->type = $content->getAttribute("type");
|
||||
$enc->link = $content->getAttribute("url");
|
||||
$enc->length = $content->getAttribute("length");
|
||||
$enc->height = $content->getAttribute("height");
|
||||
$enc->width = $content->getAttribute("width");
|
||||
|
||||
$desc = $this->xpath->query("media:description", $content)->item(0);
|
||||
if ($desc) {
|
||||
$enc->title = strip_tags($desc->nodeValue);
|
||||
} else {
|
||||
$desc = $this->xpath->query("media:description", $enclosure)->item(0);
|
||||
if ($desc) $enc->title = strip_tags($desc->nodeValue);
|
||||
}
|
||||
|
||||
array_push($encs, $enc);
|
||||
}
|
||||
}
|
||||
|
||||
$enclosures = $this->xpath->query("media:thumbnail", $this->elem);
|
||||
|
||||
foreach ($enclosures as $enclosure) {
|
||||
$enc = new FeedEnclosure();
|
||||
|
||||
$enc->type = "image/generic";
|
||||
$enc->link = $enclosure->getAttribute("url");
|
||||
$enc->height = $enclosure->getAttribute("height");
|
||||
$enc->width = $enclosure->getAttribute("width");
|
||||
|
||||
array_push($encs, $enc);
|
||||
}
|
||||
|
||||
return $encs;
|
||||
}
|
||||
|
||||
|
|
|
@ -44,13 +44,26 @@ abstract class FeedItem_Common extends FeedItem {
|
|||
}
|
||||
}
|
||||
|
||||
// todo
|
||||
function get_comments_url() {
|
||||
//RSS only. Use a query here to avoid namespace clashes (e.g. with slash).
|
||||
//might give a wrong result if a default namespace was declared (possible with XPath 2.0)
|
||||
$com_url = $this->xpath->query("comments", $this->elem)->item(0);
|
||||
|
||||
if($com_url)
|
||||
return $com_url->nodeValue;
|
||||
|
||||
//Atom Threading Extension (RFC 4685) stuff. Could be used in RSS feeds, so it's in common.
|
||||
//'text/html' for type is too restrictive?
|
||||
$com_url = $this->xpath->query("atom:link[@rel='replies' and contains(@type,'text/html')]/@href", $this->elem)->item(0);
|
||||
|
||||
if($com_url)
|
||||
return $com_url->nodeValue;
|
||||
}
|
||||
|
||||
function get_comments_count() {
|
||||
$comments = $this->xpath->query("slash:comments", $this->elem)->item(0);
|
||||
//also query for ATE stuff here
|
||||
$query = "slash:comments|thread:total|atom:link[@rel='replies']/@thread:count";
|
||||
$comments = $this->xpath->query($query, $this->elem)->item(0);
|
||||
|
||||
if ($comments) {
|
||||
return $comments->nodeValue;
|
||||
|
|
|
@ -33,20 +33,20 @@ class FeedItem_RSS extends FeedItem_Common {
|
|||
|| $link->getAttribute("rel") == "alternate"
|
||||
|| $link->getAttribute("rel") == "standout")) {
|
||||
|
||||
return $link->getAttribute("href");
|
||||
return trim($link->getAttribute("href"));
|
||||
}
|
||||
}
|
||||
|
||||
$link = $this->elem->getElementsByTagName("guid")->item(0);
|
||||
|
||||
if ($link && $link->hasAttributes() && $link->getAttribute("isPermaLink") == "true") {
|
||||
return $link->nodeValue;
|
||||
return trim($link->nodeValue);
|
||||
}
|
||||
|
||||
$link = $this->elem->getElementsByTagName("link")->item(0);
|
||||
|
||||
if ($link) {
|
||||
return $link->nodeValue;
|
||||
return trim($link->nodeValue);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -54,21 +54,26 @@ class FeedItem_RSS extends FeedItem_Common {
|
|||
$title = $this->elem->getElementsByTagName("title")->item(0);
|
||||
|
||||
if ($title) {
|
||||
return $title->nodeValue;
|
||||
return trim($title->nodeValue);
|
||||
}
|
||||
}
|
||||
|
||||
function get_content() {
|
||||
$content = $this->xpath->query("content:encoded", $this->elem)->item(0);
|
||||
$contentA = $this->xpath->query("content:encoded", $this->elem)->item(0);
|
||||
$contentB = $this->elem->getElementsByTagName("description")->item(0);
|
||||
|
||||
if ($content) {
|
||||
return $content->nodeValue;
|
||||
if ($contentA && !$contentB) {
|
||||
return $contentA->nodeValue;
|
||||
}
|
||||
|
||||
$content = $this->elem->getElementsByTagName("description")->item(0);
|
||||
|
||||
if ($content) {
|
||||
return $content->nodeValue;
|
||||
if ($contentB && !$contentA) {
|
||||
return $contentB->nodeValue;
|
||||
}
|
||||
|
||||
if ($contentA && $contentB) {
|
||||
return mb_strlen($contentA->nodeValue) > mb_strlen($contentB->nodeValue) ?
|
||||
$contentA->nodeValue : $contentB->nodeValue;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -85,13 +90,13 @@ class FeedItem_RSS extends FeedItem_Common {
|
|||
$cats = array();
|
||||
|
||||
foreach ($categories as $cat) {
|
||||
array_push($cats, $cat->nodeValue);
|
||||
array_push($cats, trim($cat->nodeValue));
|
||||
}
|
||||
|
||||
$categories = $this->xpath->query("dc:subject", $this->elem);
|
||||
|
||||
foreach ($categories as $cat) {
|
||||
array_push($cats, $cat->nodeValue);
|
||||
array_push($cats, trim($cat->nodeValue));
|
||||
}
|
||||
|
||||
return $cats;
|
||||
|
@ -108,11 +113,13 @@ class FeedItem_RSS extends FeedItem_Common {
|
|||
$enc->type = $enclosure->getAttribute("type");
|
||||
$enc->link = $enclosure->getAttribute("url");
|
||||
$enc->length = $enclosure->getAttribute("length");
|
||||
$enc->height = $enclosure->getAttribute("height");
|
||||
$enc->width = $enclosure->getAttribute("width");
|
||||
|
||||
array_push($encs, $enc);
|
||||
}
|
||||
|
||||
$enclosures = $this->xpath->query("media:content | media:group/media:content", $this->elem);
|
||||
$enclosures = $this->xpath->query("media:content", $this->elem);
|
||||
|
||||
foreach ($enclosures as $enclosure) {
|
||||
$enc = new FeedEnclosure();
|
||||
|
@ -120,6 +127,8 @@ class FeedItem_RSS extends FeedItem_Common {
|
|||
$enc->type = $enclosure->getAttribute("type");
|
||||
$enc->link = $enclosure->getAttribute("url");
|
||||
$enc->length = $enclosure->getAttribute("length");
|
||||
$enc->height = $enclosure->getAttribute("height");
|
||||
$enc->width = $enclosure->getAttribute("width");
|
||||
|
||||
$desc = $this->xpath->query("media:description", $enclosure)->item(0);
|
||||
if ($desc) $enc->title = strip_tags($desc->nodeValue);
|
||||
|
@ -127,6 +136,46 @@ class FeedItem_RSS extends FeedItem_Common {
|
|||
array_push($encs, $enc);
|
||||
}
|
||||
|
||||
|
||||
$enclosures = $this->xpath->query("media:group", $this->elem);
|
||||
|
||||
foreach ($enclosures as $enclosure) {
|
||||
$enc = new FeedEnclosure();
|
||||
|
||||
$content = $this->xpath->query("media:content", $enclosure)->item(0);
|
||||
|
||||
if ($content) {
|
||||
$enc->type = $content->getAttribute("type");
|
||||
$enc->link = $content->getAttribute("url");
|
||||
$enc->length = $content->getAttribute("length");
|
||||
$enc->height = $content->getAttribute("height");
|
||||
$enc->width = $content->getAttribute("width");
|
||||
|
||||
$desc = $this->xpath->query("media:description", $content)->item(0);
|
||||
if ($desc) {
|
||||
$enc->title = strip_tags($desc->nodeValue);
|
||||
} else {
|
||||
$desc = $this->xpath->query("media:description", $enclosure)->item(0);
|
||||
if ($desc) $enc->title = strip_tags($desc->nodeValue);
|
||||
}
|
||||
|
||||
array_push($encs, $enc);
|
||||
}
|
||||
}
|
||||
|
||||
$enclosures = $this->xpath->query("media:thumbnail", $this->elem);
|
||||
|
||||
foreach ($enclosures as $enclosure) {
|
||||
$enc = new FeedEnclosure();
|
||||
|
||||
$enc->type = "image/generic";
|
||||
$enc->link = $enclosure->getAttribute("url");
|
||||
$enc->height = $enclosure->getAttribute("height");
|
||||
$enc->width = $enclosure->getAttribute("width");
|
||||
|
||||
array_push($encs, $enc);
|
||||
}
|
||||
|
||||
return $encs;
|
||||
}
|
||||
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
class FeedParser {
|
||||
private $doc;
|
||||
private $error;
|
||||
private $libxml_errors = array();
|
||||
private $items;
|
||||
private $link;
|
||||
private $title;
|
||||
|
@ -12,6 +13,16 @@ class FeedParser {
|
|||
const FEED_RSS = 1;
|
||||
const FEED_ATOM = 2;
|
||||
|
||||
function normalize_encoding($data) {
|
||||
if (preg_match('/^(<\?xml[\t\n\r ].*?encoding[\t\n\r ]*=[\t\n\r ]*["\'])(.+?)(["\'].*?\?>)/s', $data, $matches) === 1) {
|
||||
$data = mb_convert_encoding($data, 'UTF-8', $matches[2]);
|
||||
|
||||
$data = preg_replace('/^<\?xml[\t\n\r ].*?\?>/s', $matches[1] . "UTF-8" . $matches[3] , $data);
|
||||
}
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
function __construct($data) {
|
||||
libxml_use_internal_errors(true);
|
||||
libxml_clear_errors();
|
||||
|
@ -23,32 +34,8 @@ class FeedParser {
|
|||
$error = libxml_get_last_error();
|
||||
|
||||
// libxml compiled without iconv?
|
||||
if ($error && ($error->code == 32 || $error->code == 9)) {
|
||||
if (preg_match('/^(<\?xml[\t\n\r ].*?encoding=["\'])(.+?)(["\'].*?\?>)/s', $data, $matches) === 1) {
|
||||
$enc = $matches[2];
|
||||
|
||||
$data = mb_convert_encoding($data, 'UTF-8', $enc);
|
||||
|
||||
$data = preg_replace('/^<\?xml[\t\n\r ].*?\?>/s', $matches[1] . "UTF-8" . $matches[3] , $data);
|
||||
|
||||
|
||||
// apparently not all UTF-8 characters are valid for XML
|
||||
$data = preg_replace('/[^\x{0009}\x{000a}\x{000d}\x{0020}-\x{D7FF}\x{E000}-\x{FFFD}]+/u', ' ', $data);
|
||||
|
||||
if ($data) {
|
||||
libxml_clear_errors();
|
||||
|
||||
$this->doc = new DOMDocument();
|
||||
$this->doc->loadXML($data);
|
||||
|
||||
$error = libxml_get_last_error();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// some terrible invalid unicode entity?
|
||||
if ($error && $error->code == 9) {
|
||||
$data = mb_convert_encoding($data, 'UTF-8', 'UTF-8');
|
||||
if ($error && $error->code == 32) {
|
||||
$data = $this->normalize_encoding($data);
|
||||
|
||||
if ($data) {
|
||||
libxml_clear_errors();
|
||||
|
@ -60,7 +47,41 @@ class FeedParser {
|
|||
}
|
||||
}
|
||||
|
||||
$this->error = $this->format_error($error);
|
||||
// some terrible invalid unicode entity?
|
||||
if ($error) {
|
||||
foreach (libxml_get_errors() as $err) {
|
||||
if ($err->code == 9) {
|
||||
// if the source feed is not in utf8, next conversion will fail
|
||||
$data = $this->normalize_encoding($data);
|
||||
|
||||
// remove dangling bytes
|
||||
$data = mb_convert_encoding($data, 'UTF-8', 'UTF-8');
|
||||
|
||||
// apparently not all UTF-8 characters are valid for XML
|
||||
$data = preg_replace('/[^\x{0009}\x{000a}\x{000d}\x{0020}-\x{D7FF}\x{E000}-\x{FFFD}]+/u', ' ', $data);
|
||||
|
||||
if ($data) {
|
||||
libxml_clear_errors();
|
||||
|
||||
$this->doc = new DOMDocument();
|
||||
$this->doc->loadXML($data);
|
||||
|
||||
$error = libxml_get_last_error();
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ($error) {
|
||||
foreach (libxml_get_errors() as $error) {
|
||||
if ($error->level == LIBXML_ERR_FATAL) {
|
||||
if(!isset($this->error)) //currently only the first error is reported
|
||||
$this->error = $this->format_error($error);
|
||||
$this->libxml_errors [] = $this->format_error($error);
|
||||
}
|
||||
}
|
||||
}
|
||||
libxml_clear_errors();
|
||||
|
||||
$this->items = array();
|
||||
|
@ -76,12 +97,13 @@ class FeedParser {
|
|||
$xpath->registerNamespace('slash', 'http://purl.org/rss/1.0/modules/slash/');
|
||||
$xpath->registerNamespace('dc', 'http://purl.org/dc/elements/1.1/');
|
||||
$xpath->registerNamespace('content', 'http://purl.org/rss/1.0/modules/content/');
|
||||
$xpath->registerNamespace('thread', 'http://purl.org/syndication/thread/1.0');
|
||||
|
||||
$this->xpath = $xpath;
|
||||
|
||||
$root = $xpath->query("(//atom03:feed|//atom:feed|//channel|//rdf:rdf|//rdf:RDF)");
|
||||
|
||||
if ($root) {
|
||||
if ($root && $root->length > 0) {
|
||||
$root = $root->item(0);
|
||||
|
||||
if ($root) {
|
||||
|
@ -183,6 +205,10 @@ class FeedParser {
|
|||
break;
|
||||
|
||||
}
|
||||
|
||||
if ($this->title) $this->title = trim($this->title);
|
||||
if ($this->link) $this->link = trim($this->link);
|
||||
|
||||
} else {
|
||||
if( !isset($this->error) ){
|
||||
$this->error = "Unknown/unsupported feed type";
|
||||
|
@ -205,6 +231,10 @@ class FeedParser {
|
|||
return $this->error;
|
||||
}
|
||||
|
||||
function errors() {
|
||||
return $this->libxml_errors;
|
||||
}
|
||||
|
||||
function get_link() {
|
||||
return $this->link;
|
||||
}
|
||||
|
@ -226,7 +256,7 @@ class FeedParser {
|
|||
|
||||
foreach ($links as $link) {
|
||||
if (!$rel || $link->hasAttribute('rel') && $link->getAttribute('rel') == $rel) {
|
||||
array_push($rv, $link->getAttribute('href'));
|
||||
array_push($rv, trim($link->getAttribute('href')));
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
@ -235,7 +265,7 @@ class FeedParser {
|
|||
|
||||
foreach ($links as $link) {
|
||||
if (!$rel || $link->hasAttribute('rel') && $link->getAttribute('rel') == $rel) {
|
||||
array_push($rv, $link->getAttribute('href'));
|
||||
array_push($rv, trim($link->getAttribute('href')));
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
|
|
@ -13,12 +13,6 @@ class Feeds extends Handler_Protected {
|
|||
$feed_id, $is_cat, $search,
|
||||
$search_mode, $view_mode, $error, $feed_last_updated) {
|
||||
|
||||
$page_prev_link = "viewFeedGoPage(-1)";
|
||||
$page_next_link = "viewFeedGoPage(1)";
|
||||
$page_first_link = "viewFeedGoPage(0)";
|
||||
|
||||
$catchup_page_link = "catchupPage()";
|
||||
$catchup_feed_link = "catchupCurrentFeed()";
|
||||
$catchup_sel_link = "catchupSelection()";
|
||||
|
||||
$archive_sel_link = "archiveSelection()";
|
||||
|
@ -43,6 +37,8 @@ class Feeds extends Handler_Protected {
|
|||
$search_q = "";
|
||||
}
|
||||
|
||||
$reply .= "<span class=\"holder\">";
|
||||
|
||||
$rss_link = htmlspecialchars(get_self_url_prefix() .
|
||||
"/public.php?op=rss&id=$feed_id$cat_q$search_q");
|
||||
|
||||
|
@ -50,8 +46,14 @@ class Feeds extends Handler_Protected {
|
|||
|
||||
$error_class = $error ? "error" : "";
|
||||
|
||||
$reply .= "<span class='r'>";
|
||||
$reply .= "<span id='selected_prompt'></span>";
|
||||
$reply .= "<span class='r'>
|
||||
<a href=\"#\"
|
||||
title=\"".__("View as RSS feed")."\"
|
||||
onclick=\"displayDlg('".__("View as RSS")."','generatedFeed', '$feed_id:$is_cat:$rss_link')\">
|
||||
<img class=\"noborder\" src=\"images/pub_set.png\"></a>";
|
||||
|
||||
|
||||
# $reply .= "<span>";
|
||||
$reply .= "<span id='feed_title' class='$error_class'>";
|
||||
|
||||
if ($feed_site_url) {
|
||||
|
@ -60,11 +62,11 @@ class Feeds extends Handler_Protected {
|
|||
|
||||
$target = "target=\"_blank\"";
|
||||
$reply .= "<a title=\"$last_updated\" $target href=\"$feed_site_url\">".
|
||||
truncate_string($feed_title,30)."</a>";
|
||||
truncate_string($feed_title, 30)."</a>";
|
||||
|
||||
if ($error) {
|
||||
$error = htmlspecialchars($error);
|
||||
$reply .= " <img title=\"$error\" src='images/error.png' alt='error' class=\"noborder\" style=\"vertical-align : middle\">";
|
||||
$reply .= " <img title=\"$error\" src='images/error.png' alt='error' class=\"noborder\">";
|
||||
}
|
||||
|
||||
} else {
|
||||
|
@ -73,17 +75,16 @@ class Feeds extends Handler_Protected {
|
|||
|
||||
$reply .= "</span>";
|
||||
|
||||
$reply .= "
|
||||
<a href=\"#\"
|
||||
title=\"".__("View as RSS feed")."\"
|
||||
onclick=\"displayDlg('".__("View as RSS")."','generatedFeed', '$feed_id:$is_cat:$rss_link')\">
|
||||
<img class=\"noborder\" style=\"vertical-align : middle\" src=\"images/pub_set.png\"></a>";
|
||||
|
||||
$reply .= "</span>";
|
||||
|
||||
# $reply .= "</span>";
|
||||
|
||||
// left part
|
||||
|
||||
$reply .= __('Select:')."
|
||||
$reply .= "<span class=\"main\">";
|
||||
$reply .= "<span id='selected_prompt'></span>";
|
||||
|
||||
$reply .= "
|
||||
<a href=\"#\" onclick=\"$sel_all_link\">".__('All')."</a>,
|
||||
<a href=\"#\" onclick=\"$sel_unread_link\">".__('Unread')."</a>,
|
||||
<a href=\"#\" onclick=\"$sel_inv_link\">".__('Invert')."</a>,
|
||||
|
@ -132,14 +133,14 @@ class Feeds extends Handler_Protected {
|
|||
|
||||
$reply .= "</select>";
|
||||
|
||||
//$reply .= "</div>";
|
||||
|
||||
//$reply .= "</h2";
|
||||
|
||||
foreach (PluginHost::getInstance()->get_hooks(PluginHost::HOOK_HEADLINE_TOOLBAR_BUTTON) as $p) {
|
||||
echo $p->hook_headline_toolbar_button($feed_id, $is_cat);
|
||||
$reply .= $p->hook_headline_toolbar_button($feed_id, $is_cat);
|
||||
}
|
||||
|
||||
$reply .= "</span></span>";
|
||||
|
||||
return $reply;
|
||||
}
|
||||
|
||||
|
@ -148,7 +149,7 @@ class Feeds extends Handler_Protected {
|
|||
$override_order = false, $include_children = false) {
|
||||
|
||||
if (isset($_REQUEST["DevForceUpdate"]))
|
||||
header("Content-Type: text/plain");
|
||||
header("Content-Type: text/plain; charset=utf-8");
|
||||
|
||||
$disable_cache = false;
|
||||
|
||||
|
@ -247,6 +248,8 @@ class Feeds extends Handler_Protected {
|
|||
false, 0, $include_children);
|
||||
}
|
||||
|
||||
$vfeed_group_enabled = get_pref("VFEED_GROUP_BY_FEED") && $feed != -6;
|
||||
|
||||
if ($_REQUEST["debug"]) $timing_info = print_checkpoint("H1", $timing_info);
|
||||
|
||||
$result = $qfh_ret[0];
|
||||
|
@ -278,6 +281,12 @@ class Feeds extends Handler_Protected {
|
|||
}
|
||||
} */
|
||||
|
||||
if ($offset == 0) {
|
||||
foreach (PluginHost::getInstance()->get_hooks(PluginHost::HOOK_HEADLINES_BEFORE) as $p) {
|
||||
$reply['content'] .= $p->hook_headlines_before($feed, $cat_view, $qfh_ret);
|
||||
}
|
||||
}
|
||||
|
||||
if ($this->dbh->num_rows($result) > 0) {
|
||||
|
||||
$lnum = $offset;
|
||||
|
@ -285,14 +294,12 @@ class Feeds extends Handler_Protected {
|
|||
$num_unread = 0;
|
||||
$cur_feed_title = '';
|
||||
|
||||
$fresh_intl = get_pref("FRESH_ARTICLE_MAX_AGE") * 60 * 60;
|
||||
|
||||
if ($_REQUEST["debug"]) $timing_info = print_checkpoint("PS", $timing_info);
|
||||
|
||||
$expand_cdm = get_pref('CDM_EXPANDED');
|
||||
|
||||
while ($line = $this->dbh->fetch_assoc($result)) {
|
||||
$line["content_preview"] = "— " . truncate_string(strip_tags($line["content_preview"]), 250);
|
||||
$line["content_preview"] = "— " . truncate_string(strip_tags($line["content"]), 250);
|
||||
|
||||
foreach (PluginHost::getInstance()->get_hooks(PluginHost::HOOK_QUERY_HEADLINES) as $p) {
|
||||
$line = $p->hook_query_headlines($line, 250, false);
|
||||
|
@ -422,7 +429,7 @@ class Feeds extends Handler_Protected {
|
|||
|
||||
if (!get_pref('COMBINED_DISPLAY_MODE')) {
|
||||
|
||||
if (get_pref('VFEED_GROUP_BY_FEED')) {
|
||||
if ($vfeed_group_enabled) {
|
||||
if ($feed_id != $vgroup_last_feed && $line["feed_title"]) {
|
||||
|
||||
$cur_feed_title = $line["feed_title"];
|
||||
|
@ -430,12 +437,12 @@ class Feeds extends Handler_Protected {
|
|||
|
||||
$cur_feed_title = htmlspecialchars($cur_feed_title);
|
||||
|
||||
$vf_catchup_link = "(<a class='catchup' onclick='catchupFeedInGroup($feed_id);' href='#'>".__('Mark as read')."</a>)";
|
||||
$vf_catchup_link = "<a class='catchup' onclick='catchupFeedInGroup($feed_id);' href='#'>".__('mark feed as read')."</a>";
|
||||
|
||||
$reply['content'] .= "<div class='cdmFeedTitle'>".
|
||||
"<div style=\"float : right\">$feed_icon_img</div>".
|
||||
"<a class='title' href=\"#\" onclick=\"viewfeed($feed_id)\">".
|
||||
$line["feed_title"]."</a> $vf_catchup_link</div>";
|
||||
$reply['content'] .= "<div id='FTITLE-$feed_id' class='cdmFeedTitle'>".
|
||||
"<div style='float : right'>$feed_icon_img</div>".
|
||||
"<a class='title' href=\"#\" onclick=\"viewfeed($feed_id)\">". $line["feed_title"]."</a>
|
||||
$vf_catchup_link</div>";
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -443,7 +450,7 @@ class Feeds extends Handler_Protected {
|
|||
$mouseover_attrs = "onmouseover='postMouseIn(event, $id)'
|
||||
onmouseout='postMouseOut($id)'";
|
||||
|
||||
$reply['content'] .= "<div class='hl $class' id='RROW-$id' $mouseover_attrs>";
|
||||
$reply['content'] .= "<div class='hl $class' orig-feed-id='$feed_id' id='RROW-$id' $mouseover_attrs>";
|
||||
|
||||
$reply['content'] .= "<div class='hlLeft'>";
|
||||
|
||||
|
@ -473,17 +480,18 @@ class Feeds extends Handler_Protected {
|
|||
|
||||
$reply['content'] .= "</div>";
|
||||
|
||||
$reply['content'] .= "<span class=\"hlUpdated\">";
|
||||
|
||||
if (!get_pref('VFEED_GROUP_BY_FEED')) {
|
||||
if (!$vfeed_group_enabled) {
|
||||
if (@$line["feed_title"]) {
|
||||
$rgba = @$rgba_cache[$feed_id];
|
||||
|
||||
$reply['content'] .= "<a class=\"hlFeed\" style=\"background : rgba($rgba, 0.3)\" href=\"#\" onclick=\"viewfeed($feed_id)\">".
|
||||
truncate_string($line["feed_title"],30)."</a>";
|
||||
$reply['content'] .= "<span class=\"hlFeed\"><a style=\"background : rgba($rgba, 0.3)\" href=\"#\" onclick=\"viewfeed($feed_id)\">".
|
||||
truncate_string($line["feed_title"],30)."</a></span>";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
$reply['content'] .= "<span class=\"hlUpdated\">";
|
||||
|
||||
$reply['content'] .= "<div title='$date_entered_fmt'>$updated_fmt</div>
|
||||
</span>";
|
||||
|
||||
|
@ -491,12 +499,12 @@ class Feeds extends Handler_Protected {
|
|||
|
||||
$reply['content'] .= $score_pic;
|
||||
|
||||
if ($line["feed_title"] && !get_pref('VFEED_GROUP_BY_FEED')) {
|
||||
if ($line["feed_title"] && !$vfeed_group_enabled) {
|
||||
|
||||
$reply['content'] .= "<span onclick=\"viewfeed($feed_id)\"
|
||||
style=\"cursor : pointer\"
|
||||
title=\"".htmlspecialchars($line['feed_title'])."\">
|
||||
$feed_icon_img<span>";
|
||||
$feed_icon_img</span>";
|
||||
}
|
||||
|
||||
$reply['content'] .= "</div>";
|
||||
|
@ -516,7 +524,7 @@ class Feeds extends Handler_Protected {
|
|||
$line = $p->hook_render_article_cdm($line);
|
||||
}
|
||||
|
||||
if (get_pref('VFEED_GROUP_BY_FEED') && $line["feed_title"]) {
|
||||
if ($vfeed_group_enabled && $line["feed_title"]) {
|
||||
if ($feed_id != $vgroup_last_feed) {
|
||||
|
||||
$cur_feed_title = $line["feed_title"];
|
||||
|
@ -524,7 +532,7 @@ class Feeds extends Handler_Protected {
|
|||
|
||||
$cur_feed_title = htmlspecialchars($cur_feed_title);
|
||||
|
||||
$vf_catchup_link = "(<a class='catchup' onclick='javascript:catchupFeedInGroup($feed_id);' href='#'>".__('mark as read')."</a>)";
|
||||
$vf_catchup_link = "<a class='catchup' onclick='catchupFeedInGroup($feed_id);' href='#'>".__('mark feed as read')."</a>";
|
||||
|
||||
$has_feed_icon = feed_has_icon($feed_id);
|
||||
|
||||
|
@ -534,7 +542,7 @@ class Feeds extends Handler_Protected {
|
|||
//$feed_icon_img = "<img class=\"tinyFeedIcon\" src=\"images/blank_icon.gif\" alt=\"\">";
|
||||
}
|
||||
|
||||
$reply['content'] .= "<div class='cdmFeedTitle'>".
|
||||
$reply['content'] .= "<div id='FTITLE-$feed_id' class='cdmFeedTitle'>".
|
||||
"<div style=\"float : right\">$feed_icon_img</div>".
|
||||
"<a href=\"#\" class='title' onclick=\"viewfeed($feed_id)\">".
|
||||
$line["feed_title"]."</a> $vf_catchup_link</div>";
|
||||
|
@ -547,9 +555,9 @@ class Feeds extends Handler_Protected {
|
|||
$expanded_class = $expand_cdm ? "expanded" : "expandable";
|
||||
|
||||
$reply['content'] .= "<div class=\"cdm $hlc_suffix $expanded_class $class\"
|
||||
id=\"RROW-$id\" $mouseover_attrs>";
|
||||
id=\"RROW-$id\" orig-feed-id='$feed_id' $mouseover_attrs>";
|
||||
|
||||
$reply['content'] .= "<div class=\"cdmHeader\" style=\"$row_background\">";
|
||||
$reply['content'] .= "<div class=\"cdmHeader\">";
|
||||
$reply['content'] .= "<div style=\"vertical-align : middle\">";
|
||||
|
||||
$reply['content'] .= "<input dojoType=\"dijit.form.CheckBox\"
|
||||
|
@ -592,7 +600,7 @@ class Feeds extends Handler_Protected {
|
|||
|
||||
$reply['content'] .= "</span>";
|
||||
|
||||
if (!get_pref('VFEED_GROUP_BY_FEED')) {
|
||||
if (!$vfeed_group_enabled) {
|
||||
if (@$line["feed_title"]) {
|
||||
$rgba = @$rgba_cache[$feed_id];
|
||||
|
||||
|
@ -725,7 +733,7 @@ class Feeds extends Handler_Protected {
|
|||
$reply['content'] .= "</div>";
|
||||
$reply['content'] .= "</div>";
|
||||
|
||||
$reply['content'] .= "</div><hr/>";
|
||||
$reply['content'] .= "</div>";
|
||||
|
||||
$reply['content'] .= "</div>";
|
||||
|
||||
|
@ -803,8 +811,6 @@ class Feeds extends Handler_Protected {
|
|||
|
||||
if ($_REQUEST["debug"]) $timing_info = print_checkpoint("0", $timing_info);
|
||||
|
||||
$omode = $this->dbh->escape_string($_REQUEST["omode"]);
|
||||
|
||||
$feed = $this->dbh->escape_string($_REQUEST["feed"]);
|
||||
$method = $this->dbh->escape_string($_REQUEST["m"]);
|
||||
$view_mode = $this->dbh->escape_string($_REQUEST["view_mode"]);
|
||||
|
@ -897,7 +903,7 @@ class Feeds extends Handler_Protected {
|
|||
|
||||
//$topmost_article_ids = $ret[0];
|
||||
$headlines_count = $ret[1];
|
||||
$returned_feed = $ret[2];
|
||||
/* $returned_feed = $ret[2]; */
|
||||
$disable_cache = $ret[3];
|
||||
$vgroup_last_feed = $ret[4];
|
||||
|
||||
|
@ -978,6 +984,10 @@ class Feeds extends Handler_Protected {
|
|||
print "<input dojoType=\"dijit.form.TextBox\" style=\"display : none\" name=\"op\" value=\"rpc\">";
|
||||
print "<input dojoType=\"dijit.form.TextBox\" style=\"display : none\" name=\"method\" value=\"addfeed\">";
|
||||
|
||||
print "<div id='fadd_multiple_notify' style='display : none'>";
|
||||
print_notice("Provided URL is a HTML page referencing multiple feeds, please select required feed from the dropdown menu below.");
|
||||
print "<p></div>";
|
||||
|
||||
print "<div class=\"dlgSec\">".__("Feed or site URL")."</div>";
|
||||
print "<div class=\"dlgSecCont\">";
|
||||
|
||||
|
@ -1073,20 +1083,18 @@ class Feeds extends Handler_Protected {
|
|||
print " <select dojoType=\"dijit.form.Select\" name=\"limit\" onchange=\"dijit.byId('feedBrowserDlg').update()\">";
|
||||
|
||||
foreach (array(25, 50, 100, 200) as $l) {
|
||||
$issel = ($l == $limit) ? "selected=\"1\"" : "";
|
||||
print "<option $issel value=\"$l\">$l</option>";
|
||||
//$issel = ($l == $limit) ? "selected=\"1\"" : "";
|
||||
print "<option value=\"$l\">$l</option>";
|
||||
}
|
||||
|
||||
print "</select> ";
|
||||
|
||||
print "</div>";
|
||||
|
||||
$owner_uid = $_SESSION["uid"];
|
||||
|
||||
require_once "feedbrowser.php";
|
||||
|
||||
print "<ul class='browseFeedList' id='browseFeedList'>";
|
||||
print make_feed_browser($search, 25);
|
||||
print make_feed_browser("", 25);
|
||||
print "</ul>";
|
||||
|
||||
print "<div align='center'>
|
||||
|
@ -1145,7 +1153,7 @@ class Feeds extends Handler_Protected {
|
|||
|
||||
print "<div class=\"dlgButtons\">";
|
||||
|
||||
if (!SPHINX_ENABLED) {
|
||||
if (count(PluginHost::getInstance()->get_hooks(PluginHost::HOOK_SEARCH)) == 0) {
|
||||
print "<div style=\"float : left\">
|
||||
<a class=\"visibleLink\" target=\"_blank\" href=\"http://tt-rss.org/wiki/SearchSyntax\">".__("Search syntax")."</a>
|
||||
</div>";
|
||||
|
|
|
@ -3,7 +3,7 @@ class Handler_Public extends Handler {
|
|||
|
||||
private function generate_syndicated_feed($owner_uid, $feed, $is_cat,
|
||||
$limit, $offset, $search, $search_mode,
|
||||
$view_mode = false, $format = 'atom', $order = false, $orig_guid = false) {
|
||||
$view_mode = false, $format = 'atom', $order = false, $orig_guid = false, $start_ts = false) {
|
||||
|
||||
require_once "lib/MiniTemplator.class.php";
|
||||
|
||||
|
@ -15,11 +15,15 @@ class Handler_Public extends Handler {
|
|||
if (!$limit) $limit = 60;
|
||||
|
||||
$date_sort_field = "date_entered DESC, updated DESC";
|
||||
$date_check_field = "date_entered";
|
||||
|
||||
if ($feed == -2)
|
||||
if ($feed == -2 && !$is_cat) {
|
||||
$date_sort_field = "last_published DESC";
|
||||
else if ($feed == -1)
|
||||
$date_check_field = "last_published";
|
||||
} else if ($feed == -1 && !$is_cat) {
|
||||
$date_sort_field = "last_marked DESC";
|
||||
$date_check_field = "last_marked";
|
||||
}
|
||||
|
||||
switch ($order) {
|
||||
case "title":
|
||||
|
@ -33,15 +37,18 @@ class Handler_Public extends Handler {
|
|||
break;
|
||||
}
|
||||
|
||||
//function queryFeedHeadlines($feed, $limit, $view_mode, $cat_view, $search, $search_mode, $override_order = false, $offset = 0, $owner_uid = 0, $filter = false, $since_id = 0, $include_children = false, $ignore_vfeed_group = false, $override_strategy = false, $override_vfeed = false, $start_ts = false) {
|
||||
|
||||
$qfh_ret = queryFeedHeadlines($feed,
|
||||
1, $view_mode, $is_cat, $search, $search_mode,
|
||||
$date_sort_field, $offset, $owner_uid,
|
||||
false, 0, false, true);
|
||||
false, 0, true, true, false, false, $start_ts);
|
||||
|
||||
$result = $qfh_ret[0];
|
||||
|
||||
if ($this->dbh->num_rows($result) != 0) {
|
||||
$ts = strtotime($this->dbh->fetch_result($result, 0, "date_entered"));
|
||||
|
||||
$ts = strtotime($this->dbh->fetch_result($result, 0, $date_check_field));
|
||||
|
||||
if (isset($_SERVER['HTTP_IF_MODIFIED_SINCE']) &&
|
||||
strtotime($_SERVER['HTTP_IF_MODIFIED_SINCE']) >= $ts) {
|
||||
|
@ -56,13 +63,13 @@ class Handler_Public extends Handler {
|
|||
$qfh_ret = queryFeedHeadlines($feed,
|
||||
$limit, $view_mode, $is_cat, $search, $search_mode,
|
||||
$date_sort_field, $offset, $owner_uid,
|
||||
false, 0, false, true);
|
||||
false, 0, true, true, false, false, $start_ts);
|
||||
|
||||
|
||||
$result = $qfh_ret[0];
|
||||
$feed_title = htmlspecialchars($qfh_ret[1]);
|
||||
$feed_site_url = $qfh_ret[2];
|
||||
$last_error = $qfh_ret[3];
|
||||
/* $last_error = $qfh_ret[3]; */
|
||||
|
||||
$feed_self_url = get_self_url_prefix() .
|
||||
"/public.php?op=rss&id=$feed&key=" .
|
||||
|
@ -86,7 +93,7 @@ class Handler_Public extends Handler {
|
|||
|
||||
$tpl->setVariable('SELF_URL', htmlspecialchars(get_self_url_prefix()), true);
|
||||
while ($line = $this->dbh->fetch_assoc($result)) {
|
||||
$line["content_preview"] = truncate_string(strip_tags($line["content_preview"]), 100, '...');
|
||||
$line["content_preview"] = truncate_string(strip_tags($line["content"]), 100, '...');
|
||||
|
||||
foreach (PluginHost::getInstance()->get_hooks(PluginHost::HOOK_QUERY_HEADLINES) as $p) {
|
||||
$line = $p->hook_query_headlines($line);
|
||||
|
@ -100,7 +107,8 @@ class Handler_Public extends Handler {
|
|||
$tpl->setVariable('ARTICLE_TITLE', htmlspecialchars($line['title']), true);
|
||||
$tpl->setVariable('ARTICLE_EXCERPT', $line["content_preview"], true);
|
||||
|
||||
$content = sanitize($line["content"], false, $owner_uid);
|
||||
$content = sanitize($line["content"], false, $owner_uid,
|
||||
$feed_site_url);
|
||||
|
||||
if ($line['note']) {
|
||||
$content = "<div style=\"$note_style\">Article note: " . $line['note'] . "</div>" .
|
||||
|
@ -118,7 +126,7 @@ class Handler_Public extends Handler {
|
|||
$tpl->setVariable('ARTICLE_AUTHOR', htmlspecialchars($line['author']), true);
|
||||
|
||||
$tpl->setVariable('ARTICLE_SOURCE_LINK', htmlspecialchars($line['site_url']), true);
|
||||
$tpl->setVariable('ARTICLE_SOURCE_TITLE', htmlspecialchars($line['feed_title']), true);
|
||||
$tpl->setVariable('ARTICLE_SOURCE_TITLE', htmlspecialchars($line['feed_title'] ? $line['feed_title'] : $feed_title), true);
|
||||
|
||||
$tags = get_article_tags($line["id"], $owner_uid);
|
||||
|
||||
|
@ -269,16 +277,22 @@ class Handler_Public extends Handler {
|
|||
|
||||
function pubsub() {
|
||||
$mode = $this->dbh->escape_string($_REQUEST['hub_mode']);
|
||||
if (!$mode) $mode = $this->dbh->escape_string($_REQUEST['hub.mode']);
|
||||
|
||||
$feed_id = (int) $this->dbh->escape_string($_REQUEST['id']);
|
||||
$feed_url = $this->dbh->escape_string($_REQUEST['hub_topic']);
|
||||
|
||||
if (!$feed_url) $feed_url = $this->dbh->escape_string($_REQUEST['hub.topic']);
|
||||
|
||||
if (!PUBSUBHUBBUB_ENABLED) {
|
||||
header('HTTP/1.0 404 Not Found');
|
||||
echo "404 Not found";
|
||||
echo "404 Not found (Disabled by server)";
|
||||
return;
|
||||
}
|
||||
|
||||
// TODO: implement hub_verifytoken checking
|
||||
// TODO: store requested rel=self or whatever for verification
|
||||
// (may be different from stored feed url) e.g. http://url/ or http://url
|
||||
|
||||
$result = $this->dbh->query("SELECT feed_url FROM ttrss_feeds
|
||||
WHERE id = '$feed_id'");
|
||||
|
@ -287,7 +301,8 @@ class Handler_Public extends Handler {
|
|||
|
||||
$check_feed_url = $this->dbh->fetch_result($result, 0, "feed_url");
|
||||
|
||||
if ($check_feed_url && ($check_feed_url == $feed_url || !$feed_url)) {
|
||||
// ignore url checking for the time being
|
||||
if ($check_feed_url && (true || $check_feed_url == $feed_url || !$feed_url)) {
|
||||
if ($mode == "subscribe") {
|
||||
|
||||
$this->dbh->query("UPDATE ttrss_feeds SET pubsub_state = 2
|
||||
|
@ -316,11 +331,11 @@ class Handler_Public extends Handler {
|
|||
}
|
||||
} else {
|
||||
header('HTTP/1.0 404 Not Found');
|
||||
echo "404 Not found";
|
||||
echo "404 Not found (URL check failed)";
|
||||
}
|
||||
} else {
|
||||
header('HTTP/1.0 404 Not Found');
|
||||
echo "404 Not found";
|
||||
echo "404 Not found (Feed not found)";
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -363,9 +378,10 @@ class Handler_Public extends Handler {
|
|||
$search_mode = $this->dbh->escape_string($_REQUEST["smode"]);
|
||||
$view_mode = $this->dbh->escape_string($_REQUEST["view-mode"]);
|
||||
$order = $this->dbh->escape_string($_REQUEST["order"]);
|
||||
$start_ts = $this->dbh->escape_string($_REQUEST["ts"]);
|
||||
|
||||
$format = $this->dbh->escape_string($_REQUEST['format']);
|
||||
$orig_guid = !sql_bool_to_bool($_REQUEST["no_orig_guid"]);
|
||||
$orig_guid = sql_bool_to_bool($_REQUEST["orig_guid"]);
|
||||
|
||||
if (!$format) $format = 'atom';
|
||||
|
||||
|
@ -385,24 +401,24 @@ class Handler_Public extends Handler {
|
|||
|
||||
if ($owner_id) {
|
||||
$this->generate_syndicated_feed($owner_id, $feed, $is_cat, $limit,
|
||||
$offset, $search, $search_mode, $view_mode, $format, $order, $orig_guid);
|
||||
$offset, $search, $search_mode, $view_mode, $format, $order, $orig_guid, $start_ts);
|
||||
} else {
|
||||
header('HTTP/1.1 403 Forbidden');
|
||||
}
|
||||
}
|
||||
|
||||
function updateTask() {
|
||||
PluginHost::getInstance()->run_hooks(PluginHost::HOOK_UPDATE_TASK, "hook_update_task", $op);
|
||||
PluginHost::getInstance()->run_hooks(PluginHost::HOOK_UPDATE_TASK, "hook_update_task", false);
|
||||
}
|
||||
|
||||
function housekeepingTask() {
|
||||
PluginHost::getInstance()->run_hooks(PluginHost::HOOK_HOUSE_KEEPING, "hook_house_keeping", $op);
|
||||
PluginHost::getInstance()->run_hooks(PluginHost::HOOK_HOUSE_KEEPING, "hook_house_keeping", false);
|
||||
}
|
||||
|
||||
function globalUpdateFeeds() {
|
||||
RPC::updaterandomfeed_real($this->dbh);
|
||||
|
||||
PluginHost::getInstance()->run_hooks(PluginHost::HOOK_UPDATE_TASK, "hook_update_task", $op);
|
||||
PluginHost::getInstance()->run_hooks(PluginHost::HOOK_UPDATE_TASK, "hook_update_task", false);
|
||||
}
|
||||
|
||||
function sharepopup() {
|
||||
|
@ -411,11 +427,14 @@ class Handler_Public extends Handler {
|
|||
}
|
||||
|
||||
header('Content-Type: text/html; charset=utf-8');
|
||||
print "<html><head><title>Tiny Tiny RSS</title>";
|
||||
print "<html><head><title>Tiny Tiny RSS</title>
|
||||
<link rel=\"shortcut icon\" type=\"image/png\" href=\"images/favicon.png\">
|
||||
<link rel=\"icon\" type=\"image/png\" sizes=\"72x72\" href=\"images/favicon-72px.png\">";
|
||||
|
||||
stylesheet_tag("css/utility.css");
|
||||
javascript_tag("lib/prototype.js");
|
||||
javascript_tag("lib/scriptaculous/scriptaculous.js?load=effects,dragdrop,controls");
|
||||
echo stylesheet_tag("css/utility.css");
|
||||
echo stylesheet_tag("css/dijit.css");
|
||||
echo javascript_tag("lib/prototype.js");
|
||||
echo javascript_tag("lib/scriptaculous/scriptaculous.js?load=effects,controls");
|
||||
print "<meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\"/>
|
||||
</head><body id='sharepopup'>";
|
||||
|
||||
|
@ -561,7 +580,7 @@ class Handler_Public extends Handler {
|
|||
}
|
||||
} else {
|
||||
$_SESSION["login_error_msg"] = __("Incorrect username or password");
|
||||
user_error("Failed login attempt from {$_SERVER['REMOTE_ADDR']}", E_USER_WARNING);
|
||||
user_error("Failed login attempt for $login from {$_SERVER['REMOTE_ADDR']}", E_USER_WARNING);
|
||||
}
|
||||
|
||||
if ($_REQUEST['return']) {
|
||||
|
@ -572,6 +591,18 @@ class Handler_Public extends Handler {
|
|||
}
|
||||
}
|
||||
|
||||
/* function subtest() {
|
||||
header("Content-type: text/plain; charset=utf-8");
|
||||
|
||||
$url = $_REQUEST["url"];
|
||||
|
||||
print "$url\n\n";
|
||||
|
||||
|
||||
print_r(get_feeds_from_html($url, fetch_file_contents($url)));
|
||||
|
||||
} */
|
||||
|
||||
function subscribe() {
|
||||
if (SINGLE_USER_MODE) {
|
||||
login_sequence();
|
||||
|
@ -587,6 +618,9 @@ class Handler_Public extends Handler {
|
|||
<title>Tiny Tiny RSS</title>
|
||||
<link rel=\"stylesheet\" type=\"text/css\" href=\"css/utility.css\">
|
||||
<meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\"/>
|
||||
<link rel=\"shortcut icon\" type=\"image/png\" href=\"images/favicon.png\">
|
||||
<link rel=\"icon\" type=\"image/png\" sizes=\"72x72\" href=\"images/favicon-72px.png\">
|
||||
|
||||
</head>
|
||||
<body>
|
||||
<img class=\"floatingLogo\" src=\"images/logo_small.png\"
|
||||
|
@ -671,93 +705,6 @@ class Handler_Public extends Handler {
|
|||
}
|
||||
}
|
||||
|
||||
function subscribe2() {
|
||||
$feed_url = $this->dbh->escape_string(trim($_REQUEST["feed_url"]));
|
||||
$cat_id = $this->dbh->escape_string($_REQUEST["cat_id"]);
|
||||
$from = $this->dbh->escape_string($_REQUEST["from"]);
|
||||
$feed_urls = array();
|
||||
|
||||
/* only read authentication information from POST */
|
||||
|
||||
$auth_login = $this->dbh->escape_string(trim($_POST["auth_login"]));
|
||||
$auth_pass = $this->dbh->escape_string(trim($_POST["auth_pass"]));
|
||||
|
||||
$rc = subscribe_to_feed($feed_url, $cat_id, $auth_login, $auth_pass);
|
||||
|
||||
switch ($rc) {
|
||||
case 1:
|
||||
print_notice(T_sprintf("Subscribed to <b>%s</b>.", $feed_url));
|
||||
break;
|
||||
case 2:
|
||||
print_error(T_sprintf("Could not subscribe to <b>%s</b>.", $feed_url));
|
||||
break;
|
||||
case 3:
|
||||
print_error(T_sprintf("No feeds found in <b>%s</b>.", $feed_url));
|
||||
break;
|
||||
case 0:
|
||||
print_warning(T_sprintf("Already subscribed to <b>%s</b>.", $feed_url));
|
||||
break;
|
||||
case 4:
|
||||
print_notice(__("Multiple feed URLs found."));
|
||||
$contents = @fetch_file_contents($url, false, $auth_login, $auth_pass);
|
||||
if (is_html($contents)) {
|
||||
$feed_urls = get_feeds_from_html($url, $contents);
|
||||
}
|
||||
break;
|
||||
case 5:
|
||||
print_error(T_sprintf("Could not subscribe to <b>%s</b>.<br>Can't download the Feed URL.", $feed_url));
|
||||
break;
|
||||
}
|
||||
|
||||
if ($feed_urls) {
|
||||
print "<form action=\"backend.php\">";
|
||||
print "<input type=\"hidden\" name=\"op\" value=\"pref-feeds\">";
|
||||
print "<input type=\"hidden\" name=\"quiet\" value=\"1\">";
|
||||
print "<input type=\"hidden\" name=\"method\" value=\"add\">";
|
||||
|
||||
print "<select name=\"feed_url\">";
|
||||
|
||||
foreach ($feed_urls as $url => $name) {
|
||||
$url = htmlspecialchars($url);
|
||||
$name = htmlspecialchars($name);
|
||||
print "<option value=\"$url\">$name</option>";
|
||||
}
|
||||
|
||||
print "<input type=\"submit\" value=\"".__("Subscribe to selected feed")."\">";
|
||||
print "</form>";
|
||||
}
|
||||
|
||||
$tp_uri = get_self_url_prefix() . "/prefs.php";
|
||||
$tt_uri = get_self_url_prefix();
|
||||
|
||||
if ($rc <= 2){
|
||||
$result = $this->dbh->query("SELECT id FROM ttrss_feeds WHERE
|
||||
feed_url = '$feed_url' AND owner_uid = " . $_SESSION["uid"]);
|
||||
|
||||
$feed_id = $this->dbh->fetch_result($result, 0, "id");
|
||||
} else {
|
||||
$feed_id = 0;
|
||||
}
|
||||
|
||||
print "<p>";
|
||||
|
||||
if ($feed_id) {
|
||||
print "<form method=\"GET\" style='display: inline'
|
||||
action=\"$tp_uri\">
|
||||
<input type=\"hidden\" name=\"tab\" value=\"feedConfig\">
|
||||
<input type=\"hidden\" name=\"method\" value=\"editFeed\">
|
||||
<input type=\"hidden\" name=\"methodparam\" value=\"$feed_id\">
|
||||
<input type=\"submit\" value=\"".__("Edit subscription options")."\">
|
||||
</form>";
|
||||
}
|
||||
|
||||
print "<form style='display: inline' method=\"GET\" action=\"$tt_uri\">
|
||||
<input type=\"submit\" value=\"".__("Return to Tiny Tiny RSS")."\">
|
||||
</form></p>";
|
||||
|
||||
print "</body></html>";
|
||||
}
|
||||
|
||||
function index() {
|
||||
header("Content-Type: text/plain");
|
||||
print json_encode(array("error" => array("code" => 7)));
|
||||
|
@ -766,11 +713,15 @@ class Handler_Public extends Handler {
|
|||
function forgotpass() {
|
||||
startup_gettext();
|
||||
|
||||
header('Content-Type: text/html; charset=utf-8');
|
||||
print "<html><head><title>Tiny Tiny RSS</title>";
|
||||
@$hash = $_REQUEST["hash"];
|
||||
|
||||
stylesheet_tag("css/utility.css");
|
||||
javascript_tag("lib/prototype.js");
|
||||
header('Content-Type: text/html; charset=utf-8');
|
||||
print "<html><head><title>Tiny Tiny RSS</title>
|
||||
<link rel=\"shortcut icon\" type=\"image/png\" href=\"images/favicon.png\">
|
||||
<link rel=\"icon\" type=\"image/png\" sizes=\"72x72\" href=\"images/favicon-72px.png\">";
|
||||
|
||||
echo stylesheet_tag("css/utility.css");
|
||||
echo javascript_tag("lib/prototype.js");
|
||||
|
||||
print "<meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\"/>
|
||||
</head><body id='forgotpass'>";
|
||||
|
@ -781,8 +732,45 @@ class Handler_Public extends Handler {
|
|||
|
||||
@$method = $_POST['method'];
|
||||
|
||||
if (!$method) {
|
||||
print_notice(__("You will need to provide valid account name and email. New password will be sent on your email address."));
|
||||
if ($hash) {
|
||||
$login = $_REQUEST["login"];
|
||||
|
||||
if ($login) {
|
||||
$result = $this->dbh->query("SELECT id, resetpass_token FROM ttrss_users
|
||||
WHERE login = '$login'");
|
||||
|
||||
if ($this->dbh->num_rows($result) != 0) {
|
||||
$id = $this->dbh->fetch_result($result, 0, "id");
|
||||
$resetpass_token_full = $this->dbh->fetch_result($result, 0, "resetpass_token");
|
||||
list($timestamp, $resetpass_token) = explode(":", $resetpass_token_full);
|
||||
|
||||
if ($timestamp && $resetpass_token &&
|
||||
$timestamp >= time() - 15*60*60 &&
|
||||
$resetpass_token == $hash) {
|
||||
|
||||
$result = $this->dbh->query("UPDATE ttrss_users SET resetpass_token = NULL
|
||||
WHERE id = $id");
|
||||
|
||||
Pref_Users::resetUserPassword($id, true);
|
||||
|
||||
print "<p>"."Completed."."</p>";
|
||||
|
||||
} else {
|
||||
print_error("Some of the information provided is missing or incorrect.");
|
||||
}
|
||||
} else {
|
||||
print_error("Some of the information provided is missing or incorrect.");
|
||||
}
|
||||
} else {
|
||||
print_error("Some of the information provided is missing or incorrect.");
|
||||
}
|
||||
|
||||
print "<form method=\"GET\" action=\"index.php\">
|
||||
<input type=\"submit\" value=\"".__("Return to Tiny Tiny RSS")."\">
|
||||
</form>";
|
||||
|
||||
} else if (!$method) {
|
||||
print_notice(__("You will need to provide valid account name and email. A password reset link will be sent to your email address."));
|
||||
|
||||
print "<form method='POST' action='public.php'>";
|
||||
print "<input type='hidden' name='method' value='do'>";
|
||||
|
@ -823,17 +811,57 @@ class Handler_Public extends Handler {
|
|||
|
||||
} else {
|
||||
|
||||
print_notice("Password reset instructions are being sent to your email address.");
|
||||
|
||||
$result = $this->dbh->query("SELECT id FROM ttrss_users
|
||||
WHERE login = '$login' AND email = '$email'");
|
||||
|
||||
if ($this->dbh->num_rows($result) != 0) {
|
||||
$id = $this->dbh->fetch_result($result, 0, "id");
|
||||
|
||||
Pref_Users::resetUserPassword($id, false);
|
||||
if ($id) {
|
||||
$resetpass_token = sha1(get_random_bytes(128));
|
||||
$resetpass_link = get_self_url_prefix() . "/public.php?op=forgotpass&hash=" . $resetpass_token .
|
||||
"&login=" . urlencode($login);
|
||||
|
||||
print "<p>";
|
||||
require_once 'classes/ttrssmailer.php';
|
||||
require_once "lib/MiniTemplator.class.php";
|
||||
|
||||
print "<p>"."Completed."."</p>";
|
||||
$tpl = new MiniTemplator;
|
||||
|
||||
$tpl->readTemplateFromFile("templates/resetpass_link_template.txt");
|
||||
|
||||
$tpl->setVariable('LOGIN', $login);
|
||||
$tpl->setVariable('RESETPASS_LINK', $resetpass_link);
|
||||
|
||||
$tpl->addBlock('message');
|
||||
|
||||
$message = "";
|
||||
|
||||
$tpl->generateOutputToString($message);
|
||||
|
||||
$mail = new ttrssMailer();
|
||||
|
||||
$rc = $mail->quickMail($email, $login,
|
||||
__("[tt-rss] Password reset request"),
|
||||
$message, false);
|
||||
|
||||
if (!$rc) print_error($mail->ErrorInfo);
|
||||
|
||||
$resetpass_token_full = $this->dbh->escape_string(time() . ":" . $resetpass_token);
|
||||
|
||||
$result = $this->dbh->query("UPDATE ttrss_users
|
||||
SET resetpass_token = '$resetpass_token_full'
|
||||
WHERE login = '$login' AND email = '$email'");
|
||||
|
||||
//Pref_Users::resetUserPassword($id, false);
|
||||
|
||||
print "<p>";
|
||||
|
||||
print "<p>"."Completed."."</p>";
|
||||
} else {
|
||||
print_error("User ID not found.");
|
||||
}
|
||||
|
||||
print "<form method=\"GET\" action=\"index.php\">
|
||||
<input type=\"submit\" value=\"".__("Return to Tiny Tiny RSS")."\">
|
||||
|
@ -872,6 +900,8 @@ class Handler_Public extends Handler {
|
|||
<title>Database Updater</title>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
|
||||
<link rel="stylesheet" type="text/css" href="css/utility.css"/>
|
||||
<link rel=\"shortcut icon\" type=\"image/png\" href=\"images/favicon.png\">
|
||||
<link rel=\"icon\" type=\"image/png\" sizes=\"72x72\" href=\"images/favicon-72px.png\">
|
||||
</head>
|
||||
<style type="text/css">
|
||||
span.ok { color : #009000; font-weight : bold; }
|
||||
|
|
|
@ -257,8 +257,8 @@ class Opml extends Handler_Protected {
|
|||
$feed_title = $this->dbh->escape_string(mb_substr($attrs->getNamedItem('text')->nodeValue, 0, 250));
|
||||
if (!$feed_title) $feed_title = $this->dbh->escape_string(mb_substr($attrs->getNamedItem('title')->nodeValue, 0, 250));
|
||||
|
||||
$feed_url = $this->dbh->escape_string(mb_substr($attrs->getNamedItem('xmlUrl')->nodeValue, 0, 250));
|
||||
if (!$feed_url) $feed_url = $this->dbh->escape_string(mb_substr($attrs->getNamedItem('xmlURL')->nodeValue, 0, 250));
|
||||
$feed_url = $this->dbh->escape_string($attrs->getNamedItem('xmlUrl')->nodeValue);
|
||||
if (!$feed_url) $feed_url = $this->dbh->escape_string($attrs->getNamedItem('xmlURL')->nodeValue);
|
||||
|
||||
$site_url = $this->dbh->escape_string(mb_substr($attrs->getNamedItem('htmlUrl')->nodeValue, 0, 250));
|
||||
|
||||
|
|
|
@ -39,6 +39,10 @@ class PluginHost {
|
|||
const HOOK_FETCH_FEED = 22;
|
||||
const HOOK_QUERY_HEADLINES = 23;
|
||||
const HOOK_HOUSE_KEEPING = 24;
|
||||
const HOOK_SEARCH = 25;
|
||||
const HOOK_FORMAT_ENCLOSURES = 26;
|
||||
const HOOK_SUBSCRIBE_FEED = 27;
|
||||
const HOOK_HEADLINES_BEFORE = 28;
|
||||
|
||||
const KIND_ALL = 1;
|
||||
const KIND_SYSTEM = 2;
|
||||
|
@ -75,6 +79,16 @@ class PluginHost {
|
|||
return $this->dbh;
|
||||
}
|
||||
|
||||
function get_plugin_names() {
|
||||
$names = array();
|
||||
|
||||
foreach ($this->plugins as $p) {
|
||||
array_push($names, get_class($p));
|
||||
}
|
||||
|
||||
return $names;
|
||||
}
|
||||
|
||||
function get_plugins() {
|
||||
return $this->plugins;
|
||||
}
|
||||
|
@ -99,7 +113,7 @@ class PluginHost {
|
|||
|
||||
function del_hook($type, $sender) {
|
||||
if (is_array($this->hooks[$type])) {
|
||||
$key = array_Search($this->hooks[$type], $sender);
|
||||
$key = array_Search($sender, $this->hooks[$type]);
|
||||
if ($key !== FALSE) {
|
||||
unset($this->hooks[$type][$key]);
|
||||
}
|
||||
|
|
|
@ -55,6 +55,7 @@ class Pref_Feeds extends Handler_Protected {
|
|||
$cat['unread'] = 0;
|
||||
$cat['child_unread'] = 0;
|
||||
$cat['auxcounter'] = 0;
|
||||
$cat['parent_id'] = $cat_id;
|
||||
|
||||
$cat['items'] = $this->get_category_items($line['id']);
|
||||
|
||||
|
@ -395,7 +396,7 @@ class Pref_Feeds extends Handler_Protected {
|
|||
# print_r($data['items']);
|
||||
|
||||
if (is_array($data) && is_array($data['items'])) {
|
||||
$cat_order_id = 0;
|
||||
# $cat_order_id = 0;
|
||||
|
||||
$data_map = array();
|
||||
$root_item = false;
|
||||
|
@ -494,7 +495,7 @@ class Pref_Feeds extends Handler_Protected {
|
|||
$feed_id = $this->dbh->escape_string($_REQUEST["feed_id"]);
|
||||
|
||||
if (is_file($icon_file) && $feed_id) {
|
||||
if (filesize($icon_file) < 20000) {
|
||||
if (filesize($icon_file) < 65535) {
|
||||
|
||||
$result = $this->dbh->query("SELECT id FROM ttrss_feeds
|
||||
WHERE id = '$feed_id' AND owner_uid = ". $_SESSION["uid"]);
|
||||
|
@ -737,9 +738,9 @@ class Pref_Feeds extends Handler_Protected {
|
|||
<input type=\"hidden\" name=\"op\" value=\"pref-feeds\">
|
||||
<input type=\"hidden\" name=\"feed_id\" value=\"$feed_id\">
|
||||
<input type=\"hidden\" name=\"method\" value=\"uploadicon\">
|
||||
<button dojoType=\"dijit.form.Button\" onclick=\"return uploadFeedIcon();\"
|
||||
<button class=\"small\" dojoType=\"dijit.form.Button\" onclick=\"return uploadFeedIcon();\"
|
||||
type=\"submit\">".__('Replace')."</button>
|
||||
<button dojoType=\"dijit.form.Button\" onclick=\"return removeFeedIcon($feed_id);\"
|
||||
<button class=\"small\" dojoType=\"dijit.form.Button\" onclick=\"return removeFeedIcon($feed_id);\"
|
||||
type=\"submit\">".__('Remove')."</button>
|
||||
</form>";
|
||||
|
||||
|
@ -962,7 +963,7 @@ class Pref_Feeds extends Handler_Protected {
|
|||
|
||||
if (!$batch) {
|
||||
|
||||
$result = $this->dbh->query("UPDATE ttrss_feeds SET
|
||||
$this->dbh->query("UPDATE ttrss_feeds SET
|
||||
$category_qpart
|
||||
title = '$feed_title', feed_url = '$feed_link',
|
||||
update_interval = '$upd_intl',
|
||||
|
@ -1259,13 +1260,18 @@ class Pref_Feeds extends Handler_Protected {
|
|||
$interval_qpart = "DATE_SUB(NOW(), INTERVAL 3 MONTH)";
|
||||
}
|
||||
|
||||
$result = $this->dbh->query("SELECT COUNT(*) AS num_inactive FROM ttrss_feeds WHERE
|
||||
// could be performance-intensive and prevent feeds pref-panel from showing
|
||||
if (!defined('_DISABLE_INACTIVE_FEEDS') || !_DISABLE_INACTIVE_FEEDS) {
|
||||
$result = $this->dbh->query("SELECT COUNT(*) AS num_inactive FROM ttrss_feeds WHERE
|
||||
(SELECT MAX(updated) FROM ttrss_entries, ttrss_user_entries WHERE
|
||||
ttrss_entries.id = ref_id AND
|
||||
ttrss_user_entries.feed_id = ttrss_feeds.id) < $interval_qpart AND
|
||||
ttrss_feeds.owner_uid = ".$_SESSION["uid"]);
|
||||
|
||||
$num_inactive = $this->dbh->fetch_result($result, 0, "num_inactive");
|
||||
$num_inactive = $this->dbh->fetch_result($result, 0, "num_inactive");
|
||||
} else {
|
||||
$num_inactive = 0;
|
||||
}
|
||||
|
||||
if ($num_inactive > 0) {
|
||||
$inactive_button = "<button dojoType=\"dijit.form.Button\"
|
||||
|
@ -1573,8 +1579,6 @@ class Pref_Feeds extends Handler_Protected {
|
|||
# class needed for selectTableRows()
|
||||
print "<tr class=\"placeholder\" $this_row_id>";
|
||||
|
||||
$edit_title = htmlspecialchars($line["title"]);
|
||||
|
||||
# id needed for selectTableRows()
|
||||
print "<td width='5%' align='center'><input
|
||||
onclick='toggleSelectRow2(this);' dojoType=\"dijit.form.CheckBox\"
|
||||
|
@ -1639,8 +1643,6 @@ class Pref_Feeds extends Handler_Protected {
|
|||
# class needed for selectTableRows()
|
||||
print "<tr class=\"placeholder\" $this_row_id>";
|
||||
|
||||
$edit_title = htmlspecialchars($line["title"]);
|
||||
|
||||
# id needed for selectTableRows()
|
||||
print "<td width='5%' align='center'><input
|
||||
onclick='toggleSelectRow2(this);' dojoType=\"dijit.form.CheckBox\"
|
||||
|
@ -1891,7 +1893,7 @@ class Pref_Feeds extends Handler_Protected {
|
|||
AND owner_uid = " . $owner_uid);
|
||||
|
||||
if ($this->dbh->num_rows($result) == 1) {
|
||||
$key = $this->dbh->escape_string(sha1(uniqid(rand(), true)));
|
||||
$key = $this->dbh->escape_string(uniqid(base_convert(rand(), 10, 36)));
|
||||
|
||||
$this->dbh->query("UPDATE ttrss_access_keys SET access_key = '$key'
|
||||
WHERE feed_id = '$feed_id' AND is_cat = $sql_is_cat
|
||||
|
|
|
@ -88,7 +88,6 @@ class Pref_Filters extends Handler_Protected {
|
|||
|
||||
$result = $qfh_ret[0];
|
||||
|
||||
$articles = array();
|
||||
$found = 0;
|
||||
|
||||
print __("Articles matching this filter:");
|
||||
|
@ -97,15 +96,12 @@ class Pref_Filters extends Handler_Protected {
|
|||
print "<table width=\"100%\" cellspacing=\"0\" id=\"prefErrorFeedList\">";
|
||||
|
||||
while ($line = $this->dbh->fetch_assoc($result)) {
|
||||
$line["content_preview"] = truncate_string(strip_tags($line["content_preview"]), 100, '...');
|
||||
$line["content_preview"] = truncate_string(strip_tags($line["content"]), 100, '...');
|
||||
|
||||
foreach (PluginHost::getInstance()->get_hooks(PluginHost::HOOK_QUERY_HEADLINES) as $p) {
|
||||
$line = $p->hook_query_headlines($line, 100);
|
||||
}
|
||||
|
||||
$entry_timestamp = strtotime($line["updated"]);
|
||||
$entry_tags = get_article_tags($line["id"], $_SESSION["uid"]);
|
||||
|
||||
$content_preview = $line["content_preview"];
|
||||
|
||||
if ($line["feed_title"])
|
||||
|
@ -151,6 +147,40 @@ class Pref_Filters extends Handler_Protected {
|
|||
|
||||
}
|
||||
|
||||
private function getfilterrules_concise($filter_id) {
|
||||
$result = $this->dbh->query("SELECT reg_exp,
|
||||
inverse,
|
||||
feed_id,
|
||||
cat_id,
|
||||
cat_filter,
|
||||
ttrss_filter_types.description AS field
|
||||
FROM
|
||||
ttrss_filters2_rules, ttrss_filter_types
|
||||
WHERE
|
||||
filter_id = '$filter_id' AND filter_type = ttrss_filter_types.id");
|
||||
|
||||
$rv = "";
|
||||
|
||||
while ($line = $this->dbh->fetch_assoc($result)) {
|
||||
|
||||
$where = sql_bool_to_bool($line["cat_filter"]) ?
|
||||
getCategoryTitle($line["cat_id"]) :
|
||||
($line["feed_id"] ?
|
||||
getFeedTitle($line["feed_id"]) : __("All feeds"));
|
||||
|
||||
# $where = $line["cat_id"] . "/" . $line["feed_id"];
|
||||
|
||||
$inverse = sql_bool_to_bool($line["inverse"]) ? "inverse" : "";
|
||||
|
||||
$rv .= "<span class='$inverse'>" . T_sprintf("%s on %s in %s %s",
|
||||
strip_tags($line["reg_exp"]),
|
||||
$line["field"],
|
||||
$where,
|
||||
sql_bool_to_bool($line["inverse"]) ? __("(inverse)") : "") . "</span>";
|
||||
}
|
||||
|
||||
return $rv;
|
||||
}
|
||||
|
||||
function getfiltertree() {
|
||||
$root = array();
|
||||
|
@ -174,24 +204,11 @@ class Pref_Filters extends Handler_Protected {
|
|||
owner_uid = ".$_SESSION["uid"]." ORDER BY order_id, title");
|
||||
|
||||
|
||||
$action_id = -1;
|
||||
$folder = array();
|
||||
$folder['items'] = array();
|
||||
|
||||
while ($line = $this->dbh->fetch_assoc($result)) {
|
||||
|
||||
/* if ($action_id != $line["action_id"]) {
|
||||
if (count($folder['items']) > 0) {
|
||||
array_push($root['items'], $folder);
|
||||
}
|
||||
|
||||
$folder = array();
|
||||
$folder['id'] = $line["action_id"];
|
||||
$folder['name'] = __($line["action_name"]);
|
||||
$folder['items'] = array();
|
||||
$action_id = $line["action_id"];
|
||||
} */
|
||||
|
||||
$name = $this->getFilterName($line["id"]);
|
||||
|
||||
$match_ok = false;
|
||||
|
@ -227,6 +244,7 @@ class Pref_Filters extends Handler_Protected {
|
|||
$filter['param'] = $name[1];
|
||||
$filter['checkbox'] = false;
|
||||
$filter['enabled'] = sql_bool_to_bool($line["enabled"]);
|
||||
$filter['rules'] = $this->getfilterrules_concise($line['id']);
|
||||
|
||||
if (!$filter_search || $match_ok) {
|
||||
array_push($folder['items'], $filter);
|
||||
|
@ -433,8 +451,11 @@ class Pref_Filters extends Handler_Protected {
|
|||
WHERE id = ".(int)$rule["filter_type"]);
|
||||
$filter_type = $this->dbh->fetch_result($result, 0, "description");
|
||||
|
||||
return T_sprintf("%s on %s in %s %s", strip_tags($rule["reg_exp"]),
|
||||
$filter_type, $feed, isset($rule["inverse"]) ? __("(inverse)") : "");
|
||||
$inverse = isset($rule["inverse"]) ? "inverse" : "";
|
||||
|
||||
return "<span class='filterRule $inverse'>" .
|
||||
T_sprintf("%s on %s in %s %s", strip_tags($rule["reg_exp"]),
|
||||
$filter_type, $feed, isset($rule["inverse"]) ? __("(inverse)") : "") . "</span>";
|
||||
}
|
||||
|
||||
function printRuleName() {
|
||||
|
@ -471,7 +492,7 @@ class Pref_Filters extends Handler_Protected {
|
|||
$inverse = checkbox_to_sql_bool($this->dbh->escape_string($_REQUEST["inverse"]));
|
||||
$title = $this->dbh->escape_string($_REQUEST["title"]);
|
||||
|
||||
$result = $this->dbh->query("UPDATE ttrss_filters2 SET enabled = $enabled,
|
||||
$this->dbh->query("UPDATE ttrss_filters2 SET enabled = $enabled,
|
||||
match_any_rule = $match_any_rule,
|
||||
inverse = $inverse,
|
||||
title = '$title'
|
||||
|
|
|
@ -181,7 +181,8 @@ class Pref_Prefs extends Handler_Protected {
|
|||
global $access_level_names;
|
||||
|
||||
$prefs_blacklist = array("STRIP_UNSAFE_TAGS", "REVERSE_HEADLINES",
|
||||
"SORT_HEADLINES_BY_FEED_DATE", "DEFAULT_ARTICLE_LIMIT");
|
||||
"SORT_HEADLINES_BY_FEED_DATE", "DEFAULT_ARTICLE_LIMIT",
|
||||
"FEEDS_SORT_BY_UNREAD");
|
||||
|
||||
/* "FEEDS_SORT_BY_UNREAD", "HIDE_READ_FEEDS", "REVERSE_HEADLINES" */
|
||||
|
||||
|
@ -887,8 +888,9 @@ class Pref_Prefs extends Handler_Protected {
|
|||
|
||||
if (!$otp_enabled) {
|
||||
$secret = $base32->encode(sha1($this->dbh->fetch_result($result, 0, "salt")));
|
||||
$topt = new \OTPHP\TOTP($secret);
|
||||
print QRcode::png($topt->provisioning_uri($login));
|
||||
print QRcode::png("otpauth://totp/".urlencode($login).
|
||||
"?secret=$secret&issuer=".urlencode("Tiny Tiny RSS"));
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -258,7 +258,7 @@ class Pref_Users extends Handler_Protected {
|
|||
|
||||
$pwd_hash = encrypt_password($tmp_user_pwd, $new_salt, true);
|
||||
|
||||
db_query("UPDATE ttrss_users SET pwd_hash = '$pwd_hash', salt = '$new_salt'
|
||||
db_query("UPDATE ttrss_users SET pwd_hash = '$pwd_hash', salt = '$new_salt', otp_enabled = false
|
||||
WHERE id = '$uid'");
|
||||
|
||||
if ($show_password) {
|
||||
|
|
|
@ -95,7 +95,7 @@ class RPC extends Handler_Protected {
|
|||
WHERE orig_feed_id = '$id') = 0 AND
|
||||
id = '$id' AND owner_uid = ".$_SESSION["uid"]);
|
||||
|
||||
$rc = $this->dbh->affected_rows($result);
|
||||
$this->dbh->affected_rows($result);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -138,7 +138,7 @@ class RPC extends Handler_Protected {
|
|||
$mark = "false";
|
||||
}
|
||||
|
||||
$result = $this->dbh->query("UPDATE ttrss_user_entries SET marked = $mark,
|
||||
$this->dbh->query("UPDATE ttrss_user_entries SET marked = $mark,
|
||||
last_marked = NOW()
|
||||
WHERE ref_id = '$id' AND owner_uid = " . $_SESSION["uid"]);
|
||||
|
||||
|
@ -148,8 +148,8 @@ class RPC extends Handler_Protected {
|
|||
function delete() {
|
||||
$ids = $this->dbh->escape_string($_REQUEST["ids"]);
|
||||
|
||||
$result = $this->dbh->query("DELETE FROM ttrss_user_entries
|
||||
WHERE ref_id IN ($ids) AND owner_uid = " . $_SESSION["uid"]);
|
||||
$this->dbh->query("DELETE FROM ttrss_user_entries
|
||||
WHERE ref_id IN ($ids) AND owner_uid = " . $_SESSION["uid"]);
|
||||
|
||||
purge_orphans();
|
||||
|
||||
|
@ -258,7 +258,6 @@ class RPC extends Handler_Protected {
|
|||
function publ() {
|
||||
$pub = $_REQUEST["pub"];
|
||||
$id = $this->dbh->escape_string($_REQUEST["id"]);
|
||||
$note = trim(strip_tags($this->dbh->escape_string($_REQUEST["note"])));
|
||||
|
||||
if ($pub == "1") {
|
||||
$pub = "true";
|
||||
|
@ -266,7 +265,7 @@ class RPC extends Handler_Protected {
|
|||
$pub = "false";
|
||||
}
|
||||
|
||||
$result = $this->dbh->query("UPDATE ttrss_user_entries SET
|
||||
$this->dbh->query("UPDATE ttrss_user_entries SET
|
||||
published = $pub, last_published = NOW()
|
||||
WHERE ref_id = '$id' AND owner_uid = " . $_SESSION["uid"]);
|
||||
|
||||
|
@ -620,7 +619,7 @@ class RPC extends Handler_Protected {
|
|||
|
||||
$p = new Publisher(PUBSUBHUBBUB_HUB);
|
||||
|
||||
$pubsub_result = $p->publish_update($rss_link);
|
||||
/* $pubsub_result = */ $p->publish_update($rss_link);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,64 +1,64 @@
|
|||
<?php
|
||||
/* @class ttrssMailer
|
||||
* @brief A TTRSS extension to the PHPMailer class
|
||||
* Configures default values through the __construct() function
|
||||
* @author Derek Murawsky
|
||||
* @version .1 (alpha)
|
||||
*
|
||||
*/
|
||||
require_once 'lib/phpmailer/class.phpmailer.php';
|
||||
require_once "config.php";
|
||||
|
||||
class ttrssMailer extends PHPMailer {
|
||||
|
||||
//define all items that we want to override with defaults in PHPMailer
|
||||
public $From = SMTP_FROM_ADDRESS;
|
||||
public $FromName = SMTP_FROM_NAME;
|
||||
public $CharSet = "UTF-8";
|
||||
public $PluginDir = "lib/phpmailer/";
|
||||
public $ContentType = "text/html"; //default email type is HTML
|
||||
|
||||
function __construct() {
|
||||
$this->SetLanguage("en", "lib/phpmailer/language/");
|
||||
|
||||
if (SMTP_SERVER) {
|
||||
$pair = explode(":", SMTP_SERVER, 2);
|
||||
$this->Mailer = "smtp";
|
||||
|
||||
$this->Host = $pair[0];
|
||||
$this->Port = $pair[1];
|
||||
|
||||
if (!$this->Port) $this->Port = 25;
|
||||
} else {
|
||||
$this->Host = '';
|
||||
$this->Port = '';
|
||||
}
|
||||
|
||||
|
||||
//if SMTP_LOGIN is specified, set credentials and enable auth
|
||||
if(SMTP_LOGIN){
|
||||
$this->SMTPAuth = true;
|
||||
$this->Username = SMTP_LOGIN;
|
||||
$this->Password = SMTP_PASSWORD;
|
||||
}
|
||||
<?php
|
||||
/* @class ttrssMailer
|
||||
* @brief A TTRSS extension to the PHPMailer class
|
||||
* Configures default values through the __construct() function
|
||||
* @author Derek Murawsky
|
||||
* @version .1 (alpha)
|
||||
*
|
||||
*/
|
||||
require_once 'lib/phpmailer/class.phpmailer.php';
|
||||
require_once "config.php";
|
||||
|
||||
class ttrssMailer extends PHPMailer {
|
||||
|
||||
//define all items that we want to override with defaults in PHPMailer
|
||||
public $From = SMTP_FROM_ADDRESS;
|
||||
public $FromName = SMTP_FROM_NAME;
|
||||
public $CharSet = "UTF-8";
|
||||
public $PluginDir = "lib/phpmailer/";
|
||||
public $ContentType = "text/html"; //default email type is HTML
|
||||
|
||||
function __construct() {
|
||||
$this->SetLanguage("en", "lib/phpmailer/language/");
|
||||
|
||||
if (SMTP_SERVER) {
|
||||
$pair = explode(":", SMTP_SERVER, 2);
|
||||
$this->Mailer = "smtp";
|
||||
|
||||
$this->Host = $pair[0];
|
||||
$this->Port = $pair[1];
|
||||
|
||||
if (!$this->Port) $this->Port = 25;
|
||||
} else {
|
||||
$this->Host = '';
|
||||
$this->Port = '';
|
||||
}
|
||||
|
||||
|
||||
//if SMTP_LOGIN is specified, set credentials and enable auth
|
||||
if(SMTP_LOGIN){
|
||||
$this->SMTPAuth = true;
|
||||
$this->Username = SMTP_LOGIN;
|
||||
$this->Password = SMTP_PASSWORD;
|
||||
}
|
||||
if(SMTP_SECURE)
|
||||
$this->SMTPSecure = SMTP_SECURE;
|
||||
}
|
||||
/* @brief a simple mail function to send email using the defaults
|
||||
* This will send an HTML email using the configured defaults
|
||||
* @param $toAddress A string with the recipients email address
|
||||
* @param $toName A string with the recipients name
|
||||
* @param $subject A string with the emails subject
|
||||
* @param $body A string containing the body of the email
|
||||
*/
|
||||
public function quickMail ($toAddress, $toName, $subject, $body, $altbody=""){
|
||||
$this->addAddress($toAddress, $toName);
|
||||
$this->Subject = $subject;
|
||||
$this->Body = $body;
|
||||
$this->IsHTML($altbody != '');
|
||||
$rc=$this->send();
|
||||
return $rc;
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
}
|
||||
/* @brief a simple mail function to send email using the defaults
|
||||
* This will send an HTML email using the configured defaults
|
||||
* @param $toAddress A string with the recipients email address
|
||||
* @param $toName A string with the recipients name
|
||||
* @param $subject A string with the emails subject
|
||||
* @param $body A string containing the body of the email
|
||||
*/
|
||||
public function quickMail ($toAddress, $toName, $subject, $body, $altbody=""){
|
||||
$this->addAddress($toAddress, $toName);
|
||||
$this->Subject = $subject;
|
||||
$this->Body = $body;
|
||||
$this->IsHTML($altbody != '');
|
||||
$rc=$this->send();
|
||||
return $rc;
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
|
|
|
@ -104,13 +104,9 @@
|
|||
// Enable client PubSubHubbub support in tt-rss. When disabled, tt-rss
|
||||
// won't try to subscribe to PUSH feed updates.
|
||||
|
||||
// *********************
|
||||
// *** Sphinx search ***
|
||||
// *********************
|
||||
|
||||
define('SPHINX_ENABLED', false);
|
||||
// Enable fulltext search using Sphinx (http://www.sphinxsearch.com)
|
||||
// Please see http://tt-rss.org/wiki/SphinxSearch for more information.
|
||||
// ****************************
|
||||
// *** Sphinx search plugin ***
|
||||
// ****************************
|
||||
|
||||
define('SPHINX_SERVER', 'localhost:9312');
|
||||
// Hostname:port combination for the Sphinx server.
|
||||
|
@ -184,6 +180,12 @@
|
|||
define('CHECK_FOR_NEW_VERSION', true);
|
||||
// Check for new versions of tt-rss automatically.
|
||||
|
||||
define('DETECT_ARTICLE_LANGUAGE', false);
|
||||
// Detect article language when updating feeds, presently this is only
|
||||
// used for hyphenation. This may increase amount of CPU time used by
|
||||
// update processes, disable if necessary (i.e. you are being billed
|
||||
// for CPU time).
|
||||
|
||||
define('ENABLE_GZIP_OUTPUT', false);
|
||||
// Selectively gzip output to improve wire performance. This requires
|
||||
// PHP Zlib extension on the server.
|
||||
|
@ -211,4 +213,3 @@
|
|||
// if necessary (after migrating all new options from this file).
|
||||
|
||||
// vim:ft=php
|
||||
?>
|
||||
|
|
|
@ -52,7 +52,8 @@ div.cdmHeader input {
|
|||
|
||||
div.cdmContentInner {
|
||||
margin : 10px;
|
||||
line-height : 20px;
|
||||
line-height : 1.5;
|
||||
font-size : 15px;
|
||||
}
|
||||
|
||||
div.cdmContentInner img {
|
||||
|
@ -61,6 +62,16 @@ div.cdmContentInner img {
|
|||
height : auto;
|
||||
}
|
||||
|
||||
div.cdmContentInner h1 {
|
||||
font-size : 16px;
|
||||
}
|
||||
|
||||
div.cdmContentInner h2,
|
||||
div.cdmContentInner h3,
|
||||
div.cdmContentInner h4 {
|
||||
font-size : 15px;
|
||||
}
|
||||
|
||||
div.cdmFooter {
|
||||
padding : 5px;
|
||||
font-weight : normal;
|
||||
|
@ -68,15 +79,25 @@ div.cdmFooter {
|
|||
clear : both;
|
||||
}
|
||||
|
||||
div.cdm {
|
||||
margin-right : 4px;
|
||||
}
|
||||
|
||||
div.cdm.expanded {
|
||||
margin-top : 4px;
|
||||
margin-bottom : 4px;
|
||||
}
|
||||
|
||||
div.cdm.expanded div.cdmFooter {
|
||||
border-style : solid;
|
||||
border-width : 0px 0px 1px 0px;
|
||||
border-color : #ddd;
|
||||
}
|
||||
|
||||
div.cdm.expandable {
|
||||
background-color : #f0f0f0;
|
||||
border-width : 0px 0px 1px 0px;
|
||||
border-color : #c0c0c0;
|
||||
border-color : #ddd;
|
||||
border-style : solid;
|
||||
}
|
||||
|
||||
|
@ -98,8 +119,6 @@ div.cdm.expandable.Selected {
|
|||
}
|
||||
|
||||
div.cdm.expandable.active {
|
||||
box-shadow : inset 0px 0px 3px 0px rgba(0,0,0,0.1);
|
||||
border-color : #88b0f0;
|
||||
background : white ! important;
|
||||
}
|
||||
|
||||
|
@ -115,10 +134,15 @@ div.cdm.expandable.active div.cdmHeader span.titleWrap {
|
|||
}
|
||||
|
||||
div.cdm.expandable div.cdmHeader a.title {
|
||||
font-weight : bold;
|
||||
font-weight : 600;
|
||||
color : #555;
|
||||
font-size : 14px;
|
||||
-webkit-transition : color 0.2s;
|
||||
transition : color 0.2s;
|
||||
text-rendering: optimizelegibility;
|
||||
font-family : "Segoe WP Semibold", "Segoe UI Semibold",
|
||||
"Segoe UI Web Semibold", "Segoe UI", Ubuntu, "DejaVu Sans", "Helvetica Neue",
|
||||
Helvetica, Arial, sans-serif;
|
||||
}
|
||||
|
||||
div.cdm.expandable.Unread div.cdmHeader a.title {
|
||||
|
@ -127,6 +151,12 @@ div.cdm.expandable.Unread div.cdmHeader a.title {
|
|||
|
||||
div.cdm.expandable.active div.cdmHeader a.title {
|
||||
color : #4684ff;
|
||||
font-size : 16px;
|
||||
font-weight : 600;
|
||||
text-rendering: optimizelegibility;
|
||||
font-family : "Segoe WP Semibold", "Segoe UI Semibold",
|
||||
"Segoe UI Web Semibold", "Segoe UI", Ubuntu, "DejaVu Sans", "Helvetica Neue",
|
||||
Helvetica, Arial, sans-serif;
|
||||
}
|
||||
|
||||
div.cdm.expanded div.cdmHeader {
|
||||
|
@ -134,11 +164,15 @@ div.cdm.expanded div.cdmHeader {
|
|||
}
|
||||
|
||||
div.cdm.expanded div.cdmHeader a.title {
|
||||
font-size : 14px;
|
||||
font-size : 16px;
|
||||
color : #999;
|
||||
font-weight : bold;
|
||||
font-weight : 600;
|
||||
-webkit-transition : color 0.2s;
|
||||
transition : color 0.2s;
|
||||
text-rendering: optimizelegibility;
|
||||
font-family : "Segoe WP Semibold", "Segoe UI Semibold",
|
||||
"Segoe UI Web Semibold", "Segoe UI", Ubuntu, "DejaVu Sans", "Helvetica Neue",
|
||||
Helvetica, Arial, sans-serif;
|
||||
}
|
||||
|
||||
div.cdm.expanded.active {
|
||||
|
@ -167,7 +201,7 @@ div.cdm.active div.cdmContent {
|
|||
|
||||
span.cdmExcerpt {
|
||||
font-size : 11px;
|
||||
color : #555;
|
||||
color : #999;
|
||||
font-weight : normal;
|
||||
cursor : pointer;
|
||||
}
|
||||
|
@ -222,7 +256,6 @@ div.cdm .hlFeed a {
|
|||
|
||||
div.cdmContentInner p {
|
||||
max-width : 650px;
|
||||
text-align : justify;
|
||||
-webkit-hyphens: auto;
|
||||
-moz-hyphens: auto;
|
||||
hyphens: auto;
|
||||
|
@ -242,15 +275,15 @@ div.cdmHeader span.author {
|
|||
div#floatingTitle {
|
||||
position : absolute;
|
||||
z-index : 5;
|
||||
top : 25px;
|
||||
top : 0px;
|
||||
right : 0px;
|
||||
left : 0px;
|
||||
border-color : #ccc;
|
||||
border-width : 1px 0px 1px 0px;
|
||||
border-color : #ddd;
|
||||
border-width : 0px 0px 1px 0px;
|
||||
border-style : solid;
|
||||
background : #fcfcfc;
|
||||
background : white;
|
||||
color : #555;
|
||||
box-shadow : 0px 1px 1px 0px rgba(0,0,0,0.1);
|
||||
box-shadow : 0px 1px 1px -1px rgba(0,0,0,0.1);
|
||||
}
|
||||
|
||||
div#floatingTitle > * {
|
||||
|
@ -272,11 +305,15 @@ div#floatingTitle span.author {
|
|||
}
|
||||
|
||||
div#floatingTitle a.title {
|
||||
font-size : 14px;
|
||||
font-size : 16px;
|
||||
color : #999;
|
||||
font-weight : bold;
|
||||
-webkit-transition : color 0.2s;
|
||||
transition : color 0.2s;
|
||||
font-weight : 600;
|
||||
text-rendering: optimizelegibility;
|
||||
font-family : "Segoe WP Semibold", "Segoe UI Semibold",
|
||||
"Segoe UI Web Semibold", "Segoe UI", Ubuntu, "DejaVu Sans", "Helvetica Neue",
|
||||
Helvetica, Arial, sans-serif;
|
||||
}
|
||||
|
||||
div#floatingTitle.Unread a.title {
|
||||
|
@ -284,7 +321,6 @@ div#floatingTitle.Unread a.title {
|
|||
}
|
||||
|
||||
div#floatingTitle img.anchor {
|
||||
margin-right : 1px;
|
||||
margin-left : 0px;
|
||||
}
|
||||
|
||||
|
@ -341,4 +377,24 @@ div#floatingTitle img.hlScorePic {
|
|||
text-decoration : line-through;
|
||||
}
|
||||
|
||||
div.cdmFeedTitle > * {
|
||||
display : table-cell;
|
||||
vertical-align : middle;
|
||||
}
|
||||
|
||||
div.cdmFeedTitle a.title {
|
||||
width : 100%;
|
||||
}
|
||||
|
||||
div.cdmFeedTitle a.catchup {
|
||||
text-align : right;
|
||||
color : #555;
|
||||
padding-right : 10px;
|
||||
font-size : 11px;
|
||||
white-space : nowrap;
|
||||
}
|
||||
|
||||
div.cdmFeedTitle a.catchup:hover {
|
||||
color : #4684ff;
|
||||
}
|
||||
|
||||
|
|
409
source/css/dijit.css
Normal file
|
@ -0,0 +1,409 @@
|
|||
/* Tree */
|
||||
|
||||
.claro .dijitTreeRow .dijitCheckBox {
|
||||
position : relative;
|
||||
top : -2px;
|
||||
}
|
||||
|
||||
.claro .dijitTreeLabel {
|
||||
outline : 0;
|
||||
}
|
||||
|
||||
.claro .dijitTree .feedParam {
|
||||
color : #555;
|
||||
float : right;
|
||||
margin-right : 1em;
|
||||
}
|
||||
|
||||
.claro .dijitTree .filterRules {
|
||||
display : block;
|
||||
color : #ccc;
|
||||
font-size : 10px;
|
||||
margin-left : 100px;
|
||||
}
|
||||
|
||||
.claro .dijitTree .filterRules span {
|
||||
display : block;
|
||||
color : green;
|
||||
}
|
||||
|
||||
#filterDlg_Matches span.filterRule {
|
||||
color : green;
|
||||
}
|
||||
|
||||
.claro .dijitTree .filterRules span.inverse,
|
||||
#filterDlg_Matches span.filterRule.inverse {
|
||||
color : red;
|
||||
}
|
||||
|
||||
|
||||
.claro .dijitTree .labelParam {
|
||||
float : right;
|
||||
margin-right : 1em;
|
||||
}
|
||||
|
||||
.claro .dijitTree .dijitTreeLabel.Disabled,
|
||||
.claro .dijitTree .labelParam.Disabled {
|
||||
color : #555;
|
||||
}
|
||||
|
||||
.claro .dijitTreeRow.Error {
|
||||
color : red;
|
||||
}
|
||||
|
||||
.claro .dijitTreeRow.Hidden {
|
||||
display : none;
|
||||
}
|
||||
|
||||
.claro .dijitTreeNode .loadingNode {
|
||||
margin-left : 3px;
|
||||
height : 9px;
|
||||
}
|
||||
|
||||
.claro .dijitFolderClosed,
|
||||
.claro .dijitFolderOpened {
|
||||
display : none;
|
||||
}
|
||||
|
||||
.claro .dijitTreeNode .dijitCheckBox {
|
||||
margin-left : 4px;
|
||||
}
|
||||
|
||||
.claro .dijitTreeIsRoot > .dijitTreeRow > .dijitTreeExpando {
|
||||
margin-left : 5px;
|
||||
}
|
||||
|
||||
.claro .dijitTree .dijitTreeExpando {
|
||||
margin-top : 0px;
|
||||
opacity : 0.6;
|
||||
}
|
||||
|
||||
.claro .dijitTree .dijitTreeNode {
|
||||
padding : 0px;
|
||||
border-width : 0px;
|
||||
}
|
||||
|
||||
.claro .dijitTree .dijitTreeRow {
|
||||
max-width: 100%;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
|
||||
.claro .dijitTree .dijitTreeRowSelected {
|
||||
background : white;
|
||||
}
|
||||
|
||||
.claro .dijitTree .dijitTreeRowHover {
|
||||
background : #f0f0f0;
|
||||
border-color : #ddd;
|
||||
}
|
||||
|
||||
.claro .dijitTree .dijitTreeRowSelected {
|
||||
background : white;
|
||||
border-color : #ddd;
|
||||
}
|
||||
|
||||
.claro .dijitTreeRowSelected .dijitTreeLabel {
|
||||
text-shadow : 1px 1px 2px #fff;
|
||||
}
|
||||
|
||||
.claro .dijitTreeRow .dijitTreeExpando {
|
||||
background-image: url("../images/treeExpandImages.png");
|
||||
position : relative;
|
||||
top : -1px;
|
||||
}
|
||||
|
||||
.claro .dijitTreeRow .dijitTreeExpandoLeaf {
|
||||
background : none;
|
||||
}
|
||||
|
||||
/* Toolbar */
|
||||
|
||||
.claro .dijitToolbar {
|
||||
background : #f5f5f5;
|
||||
border-color : #ddd;
|
||||
/* text-rendering: optimizelegibility;
|
||||
font-family : "Segoe WP Semibold", "Segoe UI Semibold",
|
||||
"Segoe UI Web Semibold", "Segoe UI", "Helvetica Neue",
|
||||
Helvetica, Arial, sans-serif; */
|
||||
}
|
||||
|
||||
/* .claro .dijitToolbar {
|
||||
text-shadow : 1px 1px 2px #fff;
|
||||
} */
|
||||
|
||||
.claro .dijitDialog .dijitToolbar {
|
||||
border : 1px solid #ddd;
|
||||
}
|
||||
|
||||
/* Dialog */
|
||||
|
||||
.claro .dijitDialog h2 {
|
||||
margin-top : 0px;
|
||||
margin-bottom : 4px;
|
||||
border-width : 0px;
|
||||
}
|
||||
|
||||
.claro .dijitMenuItemLabel {
|
||||
font-size : 13px;
|
||||
}
|
||||
|
||||
/* Checkbox */
|
||||
|
||||
.claro .dijitCheckBox {
|
||||
background-image : url("../images/untick.png");
|
||||
background-color : transparent;
|
||||
width : 15px;
|
||||
height : 15px;
|
||||
margin : 1px;
|
||||
opacity : 0.7;
|
||||
background-position : center center;
|
||||
transition : opacity 0.25s;
|
||||
-webkit-transition : opacity 0.25s;
|
||||
/* border : 1px solid #b5bcc7; */
|
||||
padding : 1px;
|
||||
}
|
||||
|
||||
.claro .dijitCheckBox:hover {
|
||||
opacity : 1;
|
||||
}
|
||||
|
||||
.claro .dijitCheckBox.dijitCheckBoxDisabled:hover {
|
||||
opacity : 0.7;
|
||||
}
|
||||
|
||||
.claro .dijitCheckBox.dijitCheckBoxChecked {
|
||||
border-color : #69C671;
|
||||
background-image : url("../images/tick.png");
|
||||
opacity : 1;
|
||||
}
|
||||
|
||||
/* Various buttons */
|
||||
|
||||
.claro .dijitButton .dijitButtonNode,
|
||||
.claro .dijitComboButton .dijitButtonNode,
|
||||
.claro .dijitToolbar .dijitDropDownButton .dijitButtonNode,
|
||||
.claro .dijitToolbar .dijitComboButton,
|
||||
.claro .dijitToolbar .dijitComboButton .dijitButtonNode {
|
||||
background : none;
|
||||
border-color : transparent;
|
||||
box-shadow : none;
|
||||
}
|
||||
|
||||
button,
|
||||
input[type="submit"] {
|
||||
font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
|
||||
font-size : 14px;
|
||||
}
|
||||
|
||||
button,
|
||||
input[type="submit"],
|
||||
.claro .dijitButton,
|
||||
.claro .dijitComboButton {
|
||||
display: inline-block;
|
||||
padding: 4px 12px;
|
||||
margin-bottom: 0;
|
||||
font-size: 14px;
|
||||
line-height: 20px;
|
||||
color: #333333;
|
||||
text-align: center;
|
||||
text-shadow: 0 1px 1px rgba(255, 255, 255, 0.75);
|
||||
vertical-align: middle;
|
||||
cursor: pointer;
|
||||
background-color: #f5f5f5;
|
||||
background-image: -moz-linear-gradient(top, #ffffff, #e6e6e6);
|
||||
background-image: -webkit-linear-gradient(top, #ffffff, #e6e6e6);
|
||||
background-image: linear-gradient(to bottom, #ffffff, #e6e6e6);
|
||||
background-repeat: repeat-x;
|
||||
border: 1px solid #cccccc;
|
||||
border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);
|
||||
border-bottom-color: #b3b3b3;
|
||||
-webkit-border-radius: 4px;
|
||||
border-radius: 4px;
|
||||
-webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05);
|
||||
box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05);
|
||||
}
|
||||
|
||||
button:hover,
|
||||
button:focus,
|
||||
button:active,
|
||||
input[type="submit"]:hover,
|
||||
input[type="submit"]:focus,
|
||||
input[type="submit"]:active,
|
||||
.claro .dijitButton:hover,
|
||||
.claro .dijitButton:focus,
|
||||
.claro .dijitButton:active,
|
||||
.claro .dijitComboButton:hover,
|
||||
.claro .dijitComboButton:focus,
|
||||
.claro .dijitComboButton:active,
|
||||
.claro .dijitButton.dijitButtonDisabled {
|
||||
color: #333333;
|
||||
background-color: #e6e6e6;
|
||||
}
|
||||
|
||||
button:active,
|
||||
input[type="submit"]:active,
|
||||
.claro .dijitButton:active,
|
||||
.claro .dijitComboButton:active {
|
||||
background-color: #cccccc \9;
|
||||
}
|
||||
|
||||
.claro .dijitToolbar .dijitButton,
|
||||
.claro .dijitToolbar .dijitButton.dijitHover,
|
||||
.claro .dijitToolbar .dijitComboButton,
|
||||
.claro .dijitToolbar .dijitComboButton.dijitHover {
|
||||
background : none;
|
||||
border-color : transparent;
|
||||
box-shadow : none;
|
||||
padding : 0px;
|
||||
margin : 0px;
|
||||
line-height : auto;
|
||||
text-shadow : none;
|
||||
}
|
||||
|
||||
.claro .dijitToolbar .dijitDropDownButton .dijitButtonText,
|
||||
.claro .dijitToolbar .dijitComboButton .dijitButtonText {
|
||||
padding : 0px;
|
||||
}
|
||||
|
||||
.claro .dijitToolbar .dijitDropDownButton .dijitButtonNode {
|
||||
border-radius : 4px;
|
||||
}
|
||||
|
||||
.claro .dijitToolbar .dijitButton.dijitHover,
|
||||
.claro .dijitToolbar .dijitDropDownButton.dijitHover .dijitButtonNode,
|
||||
.claro .dijitToolbar .dijitComboButton.dijitHover {
|
||||
border-color : #ccc;
|
||||
}
|
||||
|
||||
.claro .dijitToolbar .dijitButton.dijitHover .dijitButtonNode,
|
||||
.claro .dijitToolbar .dijitButton.dijitButtonActive .dijitButtonNode {
|
||||
background : none;
|
||||
}
|
||||
|
||||
.claro .dijitToolbar .dijitButton .dijitButtonContents,
|
||||
.claro .dijitToolbar .dijitDropDownButton .dijitButtonContents,
|
||||
.claro .dijitToolbar .dijitComboButton .dijitButtonContents {
|
||||
font-size : 13px;
|
||||
}
|
||||
|
||||
button:hover,
|
||||
button:focus,
|
||||
input[type="submit"]:hover,
|
||||
input[type="submit"]:focus,
|
||||
.claro .dijitButton:hover,
|
||||
.claro .dijitToolbar .dijitButton:hover .dijitButtonNode,
|
||||
.claro .dijitToolbar .dijitButton.dijitHover .dijitButtonNode,
|
||||
.claro .dijitButton:focus,
|
||||
.claro .dijitComboButton:hover,
|
||||
.claro .dijitComboButton:focus {
|
||||
color: #333333;
|
||||
text-decoration: none;
|
||||
background-position: 0 -15px;
|
||||
-webkit-transition: background-position 0.1s linear;
|
||||
transition: background-position 0.1s linear;
|
||||
}
|
||||
|
||||
button:focus,
|
||||
input[type="submit"]:focus,
|
||||
.claro .dijitButton:focus,
|
||||
.claro .dijitComboButton:focus {
|
||||
outline: thin dotted #333;
|
||||
outline: 5px auto -webkit-focus-ring-color;
|
||||
outline-offset: -2px;
|
||||
}
|
||||
|
||||
button:active,
|
||||
input[type="submit"]:active,
|
||||
.claro .dijitButton:active,
|
||||
.claro .dijitComboButton:active,
|
||||
.claro .dijitToolbar .dijitDropDownButton.dijitOpened,
|
||||
.claro .dijitToolbar .dijitComboButton.dijitOpened,
|
||||
.claro .dijitToolbar .dijitButton.dijitButtonActive .dijitButtonNode {
|
||||
background-image: none;
|
||||
outline: 0;
|
||||
-webkit-box-shadow: inset 0 2px 4px rgba(0, 0, 0, 0.15), 0 1px 2px rgba(0, 0, 0, 0.05);
|
||||
box-shadow: inset 0 2px 4px rgba(0, 0, 0, 0.15), 0 1px 2px rgba(0, 0, 0, 0.05);
|
||||
}
|
||||
|
||||
input[type="submit"][disabled],
|
||||
button[disabled],
|
||||
.claro .dijitButton[disabled],
|
||||
.claro .dijitButton.dijitButtonDisabled,
|
||||
.claro .dijitComboButton.dijitButtonDisabled {
|
||||
cursor: default;
|
||||
background-image: none;
|
||||
opacity: 0.65;
|
||||
filter: alpha(opacity=65);
|
||||
-webkit-box-shadow: none;
|
||||
box-shadow: none;
|
||||
}
|
||||
|
||||
.claro .dijitButton .dijitButtonContents,
|
||||
.claro .dijitComboButton .dijitButtonContents {
|
||||
font-size : 14px;
|
||||
font-weight : normal;
|
||||
line-height : 20px;
|
||||
}
|
||||
|
||||
.claro .dijitButton.small .dijitButtonText {
|
||||
font-size : 11px;
|
||||
}
|
||||
|
||||
.claro .dijitMenu {
|
||||
border-color : #ccc;
|
||||
}
|
||||
|
||||
.claro .dijitMenu .dijitMenuItem.dijitHover,
|
||||
.claro .dijitMenu .dijitMenuItem.dijitFocused,
|
||||
.claro .dijitMenuTable .dijitMenuItem.dijitHover .dijitMenuItemLabel,
|
||||
.claro .dijitMenuTable .dijitMenuItem.dijitFocused .dijitMenuItemLabel {
|
||||
background : #eee;
|
||||
border-color : transparent;
|
||||
}
|
||||
|
||||
.claro .dijitButton .dijitButtonNode,
|
||||
.claro .dijitComboButton .dijitButtonNode {
|
||||
padding : 0px;
|
||||
}
|
||||
|
||||
/* Other stuff */
|
||||
|
||||
/* .claro .dijitAccordionTitleFocus {
|
||||
text-shadow : 1px 1px 2px #fff;
|
||||
}
|
||||
|
||||
.claro .dijitAccordionTitle {
|
||||
text-rendering: optimizelegibility;
|
||||
font-family : "Segoe WP Semibold", "Segoe UI Semibold",
|
||||
"Segoe UI Web Semibold", "Segoe UI", "Helvetica Neue",
|
||||
Helvetica, Arial, sans-serif;
|
||||
} */
|
||||
|
||||
.claro .dijitAccordionInnerContainer.dijitAccordionInnerContainerSelected {
|
||||
border-color : #ccc;
|
||||
}
|
||||
|
||||
.claro .dijitAccordionContainer .dijitAccordionChildWrapper {
|
||||
border-color : #ddd;
|
||||
}
|
||||
|
||||
/* Tabs */
|
||||
|
||||
.claro .dijitTabContent {
|
||||
background : #eee;
|
||||
}
|
||||
|
||||
.claro .dijitTabContent.dijitTabChecked,
|
||||
.claro .dijitTabContent.dijitTabHover,
|
||||
.claro .dijitTabContent.dijitFocused {
|
||||
background : white;
|
||||
}
|
||||
|
||||
.claro .dijitTabPaneWrapper,
|
||||
.claro .dijitTabContainerTop-tabs,
|
||||
.claro .dijitTab,
|
||||
.claro .dijitAccordionInnerContainer {
|
||||
border-color : #ddd;
|
||||
}
|
||||
|
|
@ -1,3 +1,14 @@
|
|||
body#ttrssPrefs {
|
||||
background-color : #f5f5f5;
|
||||
}
|
||||
|
||||
body#ttrssPrefs #footer, body#ttrssPrefs #header {
|
||||
background-color : #f5f5f5;
|
||||
padding-left : 8px;
|
||||
padding-right : 8px;
|
||||
}
|
||||
|
||||
|
||||
#header a:hover {
|
||||
color : black;
|
||||
}
|
||||
|
@ -13,12 +24,12 @@ div#pref-tabs .dijitContentPane {
|
|||
}
|
||||
|
||||
div#pref-tabs {
|
||||
box-shadow : 0px 1px 1px -1px rgba(0,0,0,0.1);
|
||||
margin : 0px 5px 0px 5px;
|
||||
}
|
||||
|
||||
div#pref-tabs .dijitContentPane h3 {
|
||||
font-size : 14px;
|
||||
font-weight : bold;
|
||||
}
|
||||
|
||||
#pref-filter-wrap, #pref-filter-header, #pref-filter-content,
|
||||
|
@ -52,11 +63,10 @@ div.prefProfileHolder, div.prefFeedOPMLHolder, div.inactiveFeedHolder {
|
|||
height : 300px;
|
||||
overflow : auto;
|
||||
border-width : 0px 1px 1px 1px;
|
||||
border-color : #c0c0c0;
|
||||
border-color : #ddd;
|
||||
border-style : solid;
|
||||
margin : 0px 0px 5px 0px;
|
||||
background-color : #ecf4ff;
|
||||
box-shadow : inset 0px 0px 2px rgba(0,0,0,0.1);
|
||||
background-color : white;
|
||||
}
|
||||
div.filterTestHolder, div.prefFeedOPMLHolder {
|
||||
border-width : 1px;
|
||||
|
@ -66,12 +76,10 @@ ul.selfUpdateList, ul.userFeedList {
|
|||
height : 200px;
|
||||
overflow : auto;
|
||||
list-style-type : none;
|
||||
border : 1px solid #c0c0c0;
|
||||
background-color : #ecf4ff;
|
||||
border : 1px solid #ddd;
|
||||
background-color : #f5f5f5;
|
||||
margin : 0px 0px 5px 0px;
|
||||
padding : 5px;
|
||||
box-shadow : inset 0px 0px 2px rgba(0,0,0,0.1);
|
||||
border-radius : 4px;
|
||||
}
|
||||
|
||||
div#feedlistLoading, div#filterlistLoading, div#labellistLoading {
|
||||
|
@ -90,7 +98,8 @@ div#feedlistLoading img, div#filterlistLoading img, div#labellistLoading {
|
|||
|
||||
a.bookmarklet {
|
||||
color : #4684ff;
|
||||
border : 1px solid #ecf4ff;
|
||||
border : 1px solid #ddd;
|
||||
background : #f5f5f5;
|
||||
padding : 2px;
|
||||
}
|
||||
|
||||
|
@ -120,7 +129,9 @@ table.prefErrorLog td.filename, table.prefErrorLog td.login, table.prefErrorLog
|
|||
color : #555;
|
||||
}
|
||||
|
||||
.dijitAccordionContainer-child {
|
||||
box-shadow : inset 0px 0px 3px rgba(0,0,0,0.2);
|
||||
body#ttrssPrefs hr {
|
||||
border-color : #ecf4ff;
|
||||
max-width : 100%;
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -7,34 +7,28 @@ body#ttrssMain, body#ttrssPrefs, body#ttrssLogin, body {
|
|||
font-size: 14px;
|
||||
}
|
||||
|
||||
body#ttrssPrefs {
|
||||
background-color : #ecf4ff;
|
||||
}
|
||||
|
||||
body#ttrssPrefs #footer, body#ttrssPrefs #header {
|
||||
background-color : #ecf4ff;
|
||||
padding-left : 8px;
|
||||
padding-right : 8px;
|
||||
}
|
||||
|
||||
div.postReply {
|
||||
padding : 0px;
|
||||
}
|
||||
|
||||
div.postReply div.postHeader {
|
||||
border-width : 0px 0px 1px 0px;
|
||||
border-style : solid;
|
||||
border-color : #c0c0c0;
|
||||
background : #fafafa;
|
||||
box-shadow : 0px 0px 3px 0px rgba(0,0,0,0.1);
|
||||
padding : 5px;
|
||||
margin-right : 4px;
|
||||
color : #909090;
|
||||
border-width : 0px 0px 1px 0px;
|
||||
border-color : #ddd;
|
||||
border-style : solid;
|
||||
}
|
||||
|
||||
div.postReply div.postTitle {
|
||||
overflow : hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space : nowrap;
|
||||
font-weight : 600;
|
||||
text-rendering: optimizelegibility;
|
||||
font-family : "Segoe WP Semibold", "Segoe UI Semibold",
|
||||
"Segoe UI Web Semibold", "Segoe UI", Ubuntu, "DejaVu Sans", "Helvetica Neue",
|
||||
Helvetica, Arial, sans-serif;
|
||||
}
|
||||
|
||||
div.postReply div.postDate {
|
||||
|
@ -66,13 +60,10 @@ div.postReply img.tagsPic {
|
|||
div.articleNote {
|
||||
background-color : #fff7d5;
|
||||
padding : 5px;
|
||||
border-radius : 4px;
|
||||
margin : 5px;
|
||||
border-style : solid;
|
||||
border-color : #e7d796;
|
||||
border-width : 1px;
|
||||
box-shadow : inset 0px 0px 2px rgba(0,0,0,0.1);
|
||||
background-color : #fff7d5;
|
||||
color : #9a8c59;
|
||||
}
|
||||
|
||||
|
@ -87,29 +78,50 @@ div.postReply span.author {
|
|||
|
||||
h1 {
|
||||
font-size : 18px;
|
||||
font-weight : 600;
|
||||
text-rendering: optimizelegibility;
|
||||
font-family : "Segoe WP Semibold", "Segoe UI Semibold",
|
||||
"Segoe UI Web Semibold", "Segoe UI", Ubuntu, "DejaVu Sans", "Helvetica Neue",
|
||||
Helvetica, Arial, sans-serif;
|
||||
}
|
||||
|
||||
h2 {
|
||||
font-size : 16px;
|
||||
font-weight : bold;
|
||||
font-weight : 600;
|
||||
border-width : 0px 0px 1px 0px;
|
||||
border-style : solid;
|
||||
border-color : #ecf4ff;
|
||||
text-rendering: optimizelegibility;
|
||||
font-family : "Segoe WP Semibold", "Segoe UI Semibold",
|
||||
"Segoe UI Web Semibold", "Segoe UI", Ubuntu, "DejaVu Sans", "Helvetica Neue",
|
||||
Helvetica, Arial, sans-serif;
|
||||
}
|
||||
|
||||
h3 {
|
||||
font-size : 12px;
|
||||
font-weight : bold;
|
||||
font-size : 13px;
|
||||
border-width : 0px 0px 1px 0px;
|
||||
border-style : solid;
|
||||
border-color : #ecf4ff;
|
||||
font-weight : 600;
|
||||
text-rendering: optimizelegibility;
|
||||
font-family : "Segoe WP Semibold", "Segoe UI Semibold",
|
||||
"Segoe UI Web Semibold", "Segoe UI", Ubuntu, "DejaVu Sans", "Helvetica Neue",
|
||||
Helvetica, Arial, sans-serif;
|
||||
}
|
||||
|
||||
h4 {
|
||||
font-size : 14px;
|
||||
font-weight : 600;
|
||||
text-rendering: optimizelegibility;
|
||||
font-family : "Segoe WP Semibold", "Segoe UI Semibold",
|
||||
"Segoe UI Web Semibold", "Segoe UI", Ubuntu, "DejaVu Sans", "Helvetica Neue",
|
||||
Helvetica, Arial, sans-serif;
|
||||
}
|
||||
|
||||
hr {
|
||||
border-width : 0px 0px 1px 0px;
|
||||
border-style : solid;
|
||||
border-color : #c0c0c0;
|
||||
max-width : 90%;
|
||||
border-color : #ccc;
|
||||
}
|
||||
|
||||
a {
|
||||
|
@ -138,7 +150,6 @@ a:hover {
|
|||
min-width : 100px;
|
||||
padding : 5px;
|
||||
-width : 200px;
|
||||
box-shadow : 0px 0px 2px rgba(0,0,0,0.2);
|
||||
}
|
||||
|
||||
#notify img {
|
||||
|
@ -181,7 +192,11 @@ a:hover {
|
|||
}
|
||||
|
||||
.hl div.hlTitle a {
|
||||
font-weight : bold;
|
||||
font-weight : 600;
|
||||
text-rendering: optimizelegibility;
|
||||
font-family : "Segoe WP Semibold", "Segoe UI Semibold",
|
||||
"Segoe UI Web Semibold", "Segoe UI", Ubuntu, "DejaVu Sans", "Helvetica Neue",
|
||||
Helvetica, Arial, sans-serif;
|
||||
color : #777;
|
||||
}
|
||||
|
||||
|
@ -189,13 +204,9 @@ a:hover {
|
|||
color : black;
|
||||
}
|
||||
|
||||
.hl.active {
|
||||
box-shadow : inset 0px 0px 3px 0px rgba(0,0,0,0.1);
|
||||
}
|
||||
|
||||
.hl.active div.hlTitle a {
|
||||
color : #4684ff;
|
||||
text-shadow : 1px 1px 2px #fff;
|
||||
/* text-shadow : 1px 1px 2px #fff; */
|
||||
}
|
||||
|
||||
.hl.Selected {
|
||||
|
@ -206,18 +217,11 @@ a:hover {
|
|||
color : #909090;
|
||||
}
|
||||
|
||||
/* #headlines-frame div.hl:nth-child(even) {
|
||||
background : #fafafa;
|
||||
} */
|
||||
|
||||
#headlines-frame.normal {
|
||||
|
||||
}
|
||||
|
||||
.hl {
|
||||
border-width : 0px 0px 1px 0px;
|
||||
border-style : solid;
|
||||
border-color : #c0c0c0;
|
||||
border-color : #ddd;
|
||||
padding : 1px;
|
||||
}
|
||||
|
||||
.hl.active {
|
||||
|
@ -227,13 +231,11 @@ a:hover {
|
|||
div.filterTestHolder {
|
||||
height : 300px;
|
||||
overflow : auto;
|
||||
border-color : #c0c0c0;
|
||||
border-color : #ddd;
|
||||
border-style : solid;
|
||||
margin : 0px 0px 5px 0px;
|
||||
background-color : #ecf4ff;
|
||||
background-color : #f5f5f5;
|
||||
border-width : 1px;
|
||||
border-radius : 4px;
|
||||
box-shadow : inset 0px 0px 2px rgba(0,0,0,0.1);
|
||||
}
|
||||
|
||||
|
||||
|
@ -242,7 +244,7 @@ div.filterTestHolder {
|
|||
color : #555;
|
||||
padding-left : 10px;
|
||||
border-width : 0px 0px 0px 4px;
|
||||
border-color : #c0c0c0;
|
||||
border-color : #ccc;
|
||||
border-style : solid;
|
||||
}
|
||||
|
||||
|
@ -259,9 +261,9 @@ div.filterTestHolder {
|
|||
font-family : monospace;
|
||||
font-size : 12px;
|
||||
border-width : 0px;
|
||||
border-color : #c0c0c0;
|
||||
border-color : #ccc;
|
||||
border-style : solid;
|
||||
background : #fafafa;
|
||||
background : #f5f5f5;
|
||||
display : block;
|
||||
max-width : 98%;
|
||||
overflow : auto;
|
||||
|
@ -274,9 +276,7 @@ div.notice, div.warning, div.error {
|
|||
font-size : 12px;
|
||||
border-style : solid;
|
||||
border-color : #ccc;
|
||||
border-radius : 4px;
|
||||
border-width : 1px;
|
||||
box-shadow : inset 0px 0px 2px rgba(0,0,0,0.1);
|
||||
}
|
||||
|
||||
div.notice div.inner, div.warning div.inner, div.error div.inner {
|
||||
|
@ -324,47 +324,66 @@ div.prefHelp {
|
|||
color : #555;
|
||||
}
|
||||
|
||||
div#headlines-toolbar {
|
||||
border-width : 0px 0px 1px 0px;
|
||||
background-color : #fcfcfc;
|
||||
border-color : #c0c0c0;
|
||||
#main-toolbar > * {
|
||||
white-space : nowrap;
|
||||
display : table-cell;
|
||||
color : #999;
|
||||
}
|
||||
|
||||
#main-toolbar > *,
|
||||
#main-toolbar table *,
|
||||
#main-toolbar .actionChooser * {
|
||||
text-rendering: optimizelegibility;
|
||||
font-family : "Segoe WP", "Segoe UI Web", "Segoe UI", Ubuntu, "DejaVu Sans", "Helvetica Neue",
|
||||
Helvetica, Arial, sans-serif;
|
||||
font-size : 12px;
|
||||
font-family : "Segoe UI", Tahoma, sans-serif;
|
||||
color : #555;
|
||||
padding : 0px;
|
||||
margin : 0px;
|
||||
overflow : hidden;
|
||||
height : 25px;
|
||||
line-height : 25px;
|
||||
padding-left : 4px;
|
||||
|
||||
}
|
||||
|
||||
div#headlines-toolbar .dijitSelect {
|
||||
font-size : 11px;
|
||||
position : relative;
|
||||
top : -2px;
|
||||
#main-toolbar #headlines-toolbar {
|
||||
padding-right : 4px;
|
||||
width : 100%;
|
||||
}
|
||||
|
||||
div#headlines-toolbar span.r {
|
||||
float: right;
|
||||
position: relative;
|
||||
padding : 0 4px 0px 4px;
|
||||
#main-toolbar #headlines-toolbar span.holder {
|
||||
display : table;
|
||||
width : 100%;
|
||||
}
|
||||
|
||||
#main-toolbar #headlines-toolbar span.holder > * {
|
||||
display : table-cell;
|
||||
}
|
||||
|
||||
#main-toolbar #headlines-toolbar .main {
|
||||
text-align : right;
|
||||
}
|
||||
}
|
||||
|
||||
#main-toolbar #headlines-toolbar .main,
|
||||
#main-toolbar #headlines-toolbar .r {
|
||||
line-height : 24px;
|
||||
}
|
||||
|
||||
#headlines-toolbar span.r img {
|
||||
margin-right : 4px;
|
||||
position : relative;
|
||||
top : 3px;
|
||||
}
|
||||
|
||||
#headlines-toolbar span.r .error a {
|
||||
color : red;
|
||||
}
|
||||
|
||||
div#headlines-toolbar span.r a {
|
||||
color : #555;
|
||||
#main-toolbar #selected_prompt {
|
||||
font-style : italic;
|
||||
text-align : right;
|
||||
margin-right : 4px;
|
||||
}
|
||||
|
||||
span.contentPreview {
|
||||
color : #999;
|
||||
font-weight : normal;
|
||||
text-shadow : 1px 1px 2px #fff;
|
||||
font-size : 11px;
|
||||
font-size : 12px;
|
||||
padding-left : 4px;
|
||||
}
|
||||
|
||||
span.hlLabelRef {
|
||||
|
@ -377,7 +396,7 @@ span.hlLabelRef {
|
|||
display : inline-block;
|
||||
vertical-align : middle;
|
||||
white-space: nowrap;
|
||||
border-radius : 4px;
|
||||
border-radius : 4px;
|
||||
}
|
||||
|
||||
div.postHeader div.postDate {
|
||||
|
@ -397,63 +416,50 @@ div.postHeader div {
|
|||
#allEntryTags {
|
||||
border-width : 0px 0px 1px 0px;
|
||||
border-style : solid;
|
||||
border-color : #c0c0c0;
|
||||
border-color : #ddd;
|
||||
padding-bottom : 5px;
|
||||
display : none;
|
||||
}
|
||||
|
||||
a.hlFeed {
|
||||
display : block;
|
||||
white-space : nowrap;
|
||||
font-size : 9px;
|
||||
font-style : italic;
|
||||
font-weight : normal;
|
||||
border-radius : 4px;
|
||||
display : inline-block;
|
||||
padding : 1px 2px 1px 2px;
|
||||
margin-bottom : 2px;
|
||||
margin-top : 2px;
|
||||
color : #555;
|
||||
}
|
||||
|
||||
a.hlFeed:hover {
|
||||
color : #4684ff;
|
||||
}
|
||||
|
||||
img.markedPic, img.pubPic {
|
||||
cursor : pointer;
|
||||
vertical-align : middle;
|
||||
opacity : 0.5;
|
||||
-webkit-transition : opacity 0.25s;
|
||||
transition : opacity 0.25s;
|
||||
}
|
||||
|
||||
img.markedPic:hover, img.pubPic:hover {
|
||||
opacity : 1;
|
||||
}
|
||||
|
||||
img[src*='pub_set.png'], img[src*='mark_set.png'] {
|
||||
opacity : 1;
|
||||
}
|
||||
|
||||
div.tagCloudContainer {
|
||||
border : 1px solid #c0c0c0;
|
||||
background-color : #ecf4ff;
|
||||
border : 1px solid #ddd;
|
||||
background-color : #f5f5f5;
|
||||
margin : 5px 0px 5px 0px;
|
||||
padding : 5px;
|
||||
text-align : center;
|
||||
border-radius : 4px;
|
||||
box-shadow : inset 0px 0px 2px rgba(0,0,0,0.1);
|
||||
}
|
||||
|
||||
div.errorExplained {
|
||||
border : 1px solid #c0c0c0;
|
||||
background-color : #ecf4ff;
|
||||
border : 1px solid #ddd;
|
||||
background-color : #f5f5f5;
|
||||
margin : 5px 0px 5px 0px;
|
||||
padding : 5px;
|
||||
border-radius : 4px;
|
||||
box-shadow : inset 0px 0px 2px rgba(0,0,0,0.1);
|
||||
}
|
||||
|
||||
ul.feedErrorsList {
|
||||
max-height : 300px;
|
||||
overflow : auto;
|
||||
list-style-type : none;
|
||||
border : 1px solid #c0c0c0;
|
||||
background-color : #ecf4ff;
|
||||
border : 1px solid #ddd;
|
||||
background-color : #f5f5f5;
|
||||
margin : 0px 0px 5px 0px;
|
||||
padding : 5px;
|
||||
border-radius : 4px;
|
||||
box-shadow : inset 0px 0px 2px rgba(0,0,0,0.1);
|
||||
}
|
||||
|
||||
ul.feedErrorsList em {
|
||||
|
@ -464,7 +470,7 @@ ul.browseFeedList {
|
|||
height : 300px;
|
||||
overflow : auto;
|
||||
border-width : 0px 1px 1px 1px;
|
||||
border-color : #c0c0c0;
|
||||
border-color : #ddd;
|
||||
border-style : solid;
|
||||
margin : 0px 0px 5px 0px;
|
||||
background-color : white;
|
||||
|
@ -528,14 +534,6 @@ form {
|
|||
padding : 0px;
|
||||
}
|
||||
|
||||
#main_toolbar_form {
|
||||
margin : 0px;
|
||||
padding : 0px;
|
||||
display : table-cell;
|
||||
white-space : nowrap;
|
||||
width : 100%;
|
||||
}
|
||||
|
||||
div.loadingPrompt {
|
||||
padding : 1em;
|
||||
text-align : center;
|
||||
|
@ -545,20 +543,11 @@ div.loadingPrompt {
|
|||
div.whiteBox {
|
||||
margin-left : 1px;
|
||||
text-align : center;
|
||||
padding : 1em;
|
||||
}
|
||||
|
||||
/* html, body#ttrssMain, #main {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
} */
|
||||
|
||||
#toolbar div.actionChooser {
|
||||
display : table-cell;
|
||||
text-align : right;
|
||||
padding-right : 3px;
|
||||
padding : 1em 1em 0px 1em;
|
||||
font-size : 11px;
|
||||
border-width : 0px 0px 1px 0px;
|
||||
border-style : solid;
|
||||
border-color : #ddd;
|
||||
}
|
||||
|
||||
div.autocomplete {
|
||||
|
@ -589,11 +578,13 @@ div.autocomplete ul li {
|
|||
cursor : pointer;
|
||||
}
|
||||
|
||||
.hlTitle {
|
||||
.hl .hlTitle {
|
||||
overflow : hidden;
|
||||
white-space : nowrap;
|
||||
max-width : 500px;
|
||||
text-overflow : ellipsis;
|
||||
padding-left : 6px;
|
||||
padding-right : 6px;
|
||||
}
|
||||
|
||||
div#headlines-frame.wide .hlTitle {
|
||||
|
@ -602,6 +593,10 @@ div#headlines-frame.wide .hlTitle {
|
|||
white-space : normal;
|
||||
}
|
||||
|
||||
div#headlines-frame.wide .hl .hlFeed {
|
||||
display : none;
|
||||
}
|
||||
|
||||
.hl a.title.high, span.hlContent.high .contentPreview {
|
||||
color : #00aa00;
|
||||
}
|
||||
|
@ -667,7 +662,6 @@ span.labelColorIndicator {
|
|||
background-color : #fff7d5;
|
||||
color : #063064;
|
||||
text-align : center;
|
||||
box-shadow : 0px 0px 1px 0px rgba(0,0,0,0.1);
|
||||
}
|
||||
|
||||
div#cmdline {
|
||||
|
@ -716,14 +710,39 @@ div.hlRight img {
|
|||
max-height : 16px;
|
||||
}
|
||||
|
||||
span.hlUpdated {
|
||||
color : #555;
|
||||
min-width : 100px;
|
||||
.hl span.hlFeed {
|
||||
display : table-cell;
|
||||
width : 100%;
|
||||
vertical-align : middle;
|
||||
text-align : right;
|
||||
font-size : 10px;
|
||||
}
|
||||
|
||||
.hl span.hlFeed a {
|
||||
border-radius : 4px;
|
||||
display : inline-block;
|
||||
padding : 1px 4px 1px 4px;
|
||||
font-size : 11px;
|
||||
font-style : italic;
|
||||
font-weight : normal;
|
||||
color : #555;
|
||||
white-space : nowrap;
|
||||
}
|
||||
|
||||
.hl span.hlFeed a:hover {
|
||||
color : #4684ff;
|
||||
}
|
||||
|
||||
.hl span.hlUpdated {
|
||||
color : #555;
|
||||
display : table-cell;
|
||||
vertical-align : middle;
|
||||
text-align : right;
|
||||
font-size : 11px;
|
||||
white-space : nowrap;
|
||||
padding-left : 10px;
|
||||
}
|
||||
|
||||
span.hlUpdated div {
|
||||
display : inline-block;
|
||||
}
|
||||
|
||||
div.hlLeft {
|
||||
|
@ -771,21 +790,19 @@ div.fatalError textarea {
|
|||
|
||||
#content-wrap {
|
||||
padding : 0px;
|
||||
border-width : 0px 0px 0px 1px;
|
||||
border-style : solid;
|
||||
border-color : #c0c0c0;
|
||||
border-width : 0px;
|
||||
margin : 0px;
|
||||
}
|
||||
|
||||
#feeds-holder {
|
||||
padding : 0px;
|
||||
border-color : #c0c0c0;
|
||||
border-left-width : 0px;
|
||||
border-bottom-width : 0px;
|
||||
border-top-width : 0px;
|
||||
border-width : 0px 1px 0px 0px;
|
||||
border-style : solid;
|
||||
border-color : #ddd;
|
||||
overflow : hidden;
|
||||
box-shadow : inset 0px 0px 3px rgba(0,0,0,0.1);
|
||||
background : #f9fbff;
|
||||
background : #f5f5f5;
|
||||
box-shadow : inset -1px 0px 2px -1px rgba(0,0,0,0.1);
|
||||
-webkit-overflow-scrolling : touch;
|
||||
}
|
||||
|
||||
#headlines-wrap-inner {
|
||||
|
@ -796,11 +813,10 @@ div.fatalError textarea {
|
|||
|
||||
#headlines-frame {
|
||||
padding : 0px;
|
||||
border-color : #c0c0c0;
|
||||
border-style : solid;
|
||||
border-width : 0px;
|
||||
border-color : #ddd;
|
||||
margin-top : 0px;
|
||||
box-shadow : inset 0px 0px 3px rgba(0,0,0,0.1);
|
||||
-webkit-overflow-scrolling : touch;
|
||||
}
|
||||
|
||||
#headlines-toolbar_splitter, #toolbar_splitter {
|
||||
|
@ -813,7 +829,16 @@ div.fatalError textarea {
|
|||
border-width : 0px;
|
||||
white-space: nowrap;
|
||||
font-size : 12px;
|
||||
box-shadow : 0px 0px 2px rgba(0,0,0,0.1);
|
||||
}
|
||||
|
||||
#main-toolbar {
|
||||
background : white;
|
||||
border-width : 0px 0px 1px 0px;
|
||||
border-color : #ddd;
|
||||
border-style : solid;
|
||||
padding-left : 4px;
|
||||
height : 26px;
|
||||
|
||||
}
|
||||
|
||||
#header {
|
||||
|
@ -837,12 +862,12 @@ div.fatalError textarea {
|
|||
|
||||
#content-insert {
|
||||
padding : 0px;
|
||||
border-color : #c0c0c0;
|
||||
border-bottom-width : 0px;
|
||||
border-right-width : 0px;
|
||||
border-left-width : 0px;
|
||||
line-height: 20px;
|
||||
border-color : #ddd;
|
||||
border-width : 0px;
|
||||
line-height: 1.5;
|
||||
font-size : 15px;
|
||||
overflow : auto;
|
||||
-webkit-overflow-scrolling : touch;
|
||||
}
|
||||
|
||||
#feedTree .dijitTreeRow .dijitTreeLabel.Unread {
|
||||
|
@ -853,33 +878,6 @@ div.fatalError textarea {
|
|||
color : red;
|
||||
}
|
||||
|
||||
.dijitTreeLabel {
|
||||
outline : 0;
|
||||
}
|
||||
|
||||
.feedParam {
|
||||
color : #555;
|
||||
float : right;
|
||||
margin-right : 1em;
|
||||
}
|
||||
|
||||
.labelParam {
|
||||
float : right;
|
||||
margin-right : 1em;
|
||||
}
|
||||
|
||||
.dijitTreeLabel.Disabled, .labelParam.Disabled {
|
||||
color : #555;
|
||||
}
|
||||
|
||||
.dijitTreeRow.Error {
|
||||
color : red;
|
||||
}
|
||||
|
||||
.dijitTreeRow.Hidden {
|
||||
display : none;
|
||||
}
|
||||
|
||||
img.feedIcon, img.tinyFeedIcon {
|
||||
width : 16px;
|
||||
height : 16px;
|
||||
|
@ -888,24 +886,6 @@ img.feedIcon, img.tinyFeedIcon {
|
|||
display : inline-block;
|
||||
}
|
||||
|
||||
.dijitToolbar {
|
||||
text-shadow : 1px 1px 2px #fff;
|
||||
}
|
||||
|
||||
.dijitAccordionTitleFocus {
|
||||
text-shadow : 1px 1px 2px #fff;
|
||||
}
|
||||
|
||||
.dijitDialog .dijitToolbar {
|
||||
border : 1px solid #c0c0c0;
|
||||
}
|
||||
|
||||
.dijitDialog h2 {
|
||||
margin-top : 0px;
|
||||
margin-bottom : 4px;
|
||||
border-width : 0px;
|
||||
}
|
||||
|
||||
.player {
|
||||
display : inline-block;
|
||||
color : #555;
|
||||
|
@ -933,8 +913,19 @@ img.feedIcon, img.tinyFeedIcon {
|
|||
height : 100%;
|
||||
margin-left : 1px;
|
||||
text-align : center;
|
||||
padding : 1em;
|
||||
color : #555;
|
||||
font-size : 11px;
|
||||
font-style : italic;
|
||||
}
|
||||
|
||||
#headlines-spacer a, #headlines-spacer span {
|
||||
color : #555;
|
||||
padding : 10px;
|
||||
display : block;
|
||||
}
|
||||
|
||||
#headlines-spacer a:hover {
|
||||
color : #88b0f0;
|
||||
}
|
||||
|
||||
ul#filterDlg_Matches, ul#filterDlg_Actions {
|
||||
|
@ -942,12 +933,11 @@ ul#filterDlg_Matches, ul#filterDlg_Actions {
|
|||
overflow : auto;
|
||||
list-style-type : none;
|
||||
border-style : solid;
|
||||
border-color : #c0c0c0;
|
||||
border-color : #ddd;
|
||||
border-width : 0px 1px 1px 1px;
|
||||
background-color : #ecf4ff;
|
||||
background-color : white;
|
||||
margin : 0px 0px 5px 0px;
|
||||
padding : 0px;
|
||||
box-shadow : inset 0px 0px 2px rgba(0,0,0,0.1);
|
||||
}
|
||||
|
||||
ul#filterDlg_Matches li, ul#filterDlg_Actions li {
|
||||
|
@ -955,20 +945,14 @@ ul#filterDlg_Matches li, ul#filterDlg_Actions li {
|
|||
padding : 0px 0px 0px 5px;
|
||||
}
|
||||
|
||||
ul#filterDlg_Matches li div.dijitCheckBox, ul#filterDlg_Actions li div.dijitCheckBox {
|
||||
margin-right : 5px;
|
||||
}
|
||||
|
||||
ul.helpKbList {
|
||||
max-height : 300px;
|
||||
overflow : auto;
|
||||
list-style-type : none;
|
||||
border : 1px solid #c0c0c0;
|
||||
background-color : #ecf4ff;
|
||||
border : 1px solid #ddd;
|
||||
background-color : #f5f5f5;
|
||||
margin : 0px 0px 5px 0px;
|
||||
padding : 5px;
|
||||
border-radius : 4px;
|
||||
box-shadow : inset 0px 0px 2px rgba(0,0,0,0.1);
|
||||
}
|
||||
|
||||
ul.helpKbList span.hksequence {
|
||||
|
@ -983,18 +967,22 @@ ul.helpKbList h2 {
|
|||
margin-top : 0px;
|
||||
}
|
||||
|
||||
.dijitTreeNode .loadingNode {
|
||||
margin-left : 3px;
|
||||
height : 9px;
|
||||
}
|
||||
|
||||
span.collapseBtn {
|
||||
cursor : pointer;
|
||||
}
|
||||
|
||||
div.postContent h1 {
|
||||
font-size : 16px;
|
||||
}
|
||||
|
||||
div.postContent h2,
|
||||
div.postContent h3,
|
||||
div.postContent h4 {
|
||||
font-size : 15px;
|
||||
}
|
||||
|
||||
div.postContent p {
|
||||
max-width : 650px;
|
||||
text-align : justify;
|
||||
-webkit-hyphens: auto;
|
||||
-moz-hyphens: auto;
|
||||
hyphens: auto;
|
||||
|
@ -1010,90 +998,12 @@ div.postHeader span.author {
|
|||
font-weight : normal;
|
||||
}
|
||||
|
||||
body#ttrssZoom {
|
||||
margin-left : auto;
|
||||
margin-right : auto;
|
||||
padding : 20px;
|
||||
max-width : 670px;
|
||||
background : #f9fbff;
|
||||
}
|
||||
|
||||
body#ttrssZoom div.postHeader div.postFeedTitle {
|
||||
float : left;
|
||||
text-align : right;
|
||||
padding-left : 0px;
|
||||
font-size : 10px;
|
||||
}
|
||||
|
||||
body#ttrssZoom div.postHeader a.postComments {
|
||||
text-align : right;
|
||||
padding-left : 0px;
|
||||
font-size : 10px;
|
||||
}
|
||||
|
||||
body#ttrssZoom div.postHeader div.postDate {
|
||||
float : none;
|
||||
text-align : right;
|
||||
padding-left : 0px;
|
||||
color : #777;
|
||||
font-size : 10px;
|
||||
}
|
||||
|
||||
body#ttrssZoom div.postHeader div.postTags {
|
||||
color : #777;
|
||||
font-size : 10px;
|
||||
}
|
||||
|
||||
body#ttrssZoom div.postHeader div.postTitle {
|
||||
white-space : normal;
|
||||
}
|
||||
|
||||
body#ttrssZoom div.postContent p {
|
||||
max-width : 650px;
|
||||
text-align : justify;
|
||||
-webkit-hyphens: auto;
|
||||
-moz-hyphens: auto;
|
||||
hyphens: auto;
|
||||
}
|
||||
|
||||
body#ttrssZoom div.postHeader {
|
||||
margin : 10px;
|
||||
border : 1px solid #ccc;
|
||||
box-shadow : none;
|
||||
border-radius : 4px;
|
||||
}
|
||||
|
||||
body#ttrssZoom div.postReply {
|
||||
border : 1px solid #ccc;
|
||||
border-radius : 4px;
|
||||
box-shadow : inset 0px 0px 3px rgba(0,0,0,0.1);
|
||||
background : white;
|
||||
}
|
||||
|
||||
body#ttrssZoom div.postContent {
|
||||
|
||||
}
|
||||
|
||||
body#ttrssZoom div.footer {
|
||||
margin-top : 1em;
|
||||
text-align : center;
|
||||
}
|
||||
|
||||
body#ttrssZoom div.postContent img {
|
||||
max-width : 650px;
|
||||
height : auto;
|
||||
}
|
||||
|
||||
select.attachments {
|
||||
display : block;
|
||||
margin-top : 10px;
|
||||
max-width : 120px;
|
||||
}
|
||||
|
||||
div.hl.active {
|
||||
border-color : #88b0f0;
|
||||
}
|
||||
|
||||
#selected_prompt {
|
||||
margin-right : 25px;
|
||||
}
|
||||
|
@ -1107,46 +1017,28 @@ body#ttrssMain #feedTree .dijitTreeRow {
|
|||
padding : 2px 0px 2px;
|
||||
height : 22px;
|
||||
border-width : 1px;
|
||||
border-color : transparent;
|
||||
color : #333;
|
||||
}
|
||||
|
||||
body#ttrssMain #feedTree .dijitFolderClosed,
|
||||
body#ttrssMain #feedTree .dijitFolderOpened {
|
||||
display : none;
|
||||
}
|
||||
|
||||
.dijitTreeNode .dijitCheckBox {
|
||||
margin-left : 4px;
|
||||
}
|
||||
|
||||
body#ttrssMain #feedTree .dijitTreeIsRoot > .dijitTreeRow > .dijitTreeExpando {
|
||||
margin-left : 5px;
|
||||
}
|
||||
|
||||
body#ttrssMain #feedTree .dijitTreeExpando {
|
||||
margin-top : 0px;
|
||||
opacity : 0.6;
|
||||
}
|
||||
|
||||
body#ttrssMain #feedTree .dijitTreeNode {
|
||||
padding : 0px;
|
||||
border-width : 0px;
|
||||
ul#filterDlg_Matches li div.dijitCheckBox, ul#filterDlg_Actions li div.dijitCheckBox {
|
||||
margin-right : 5px;
|
||||
}
|
||||
|
||||
body#ttrssMain #feedTree {
|
||||
height : 100%;
|
||||
overflow-x : hidden;
|
||||
font-family : "Segoe UI", Tahoma, sans-serif;
|
||||
text-rendering: optimizelegibility;
|
||||
font-family : "Segoe UI Web", "Segoe UI", Ubuntu, "DejaVu Sans", "Helvetica Neue",
|
||||
Helvetica, Arial, sans-serif;
|
||||
}
|
||||
|
||||
#feedTree .counterNode.aux {
|
||||
body#ttrssMain #feedTree .counterNode.aux {
|
||||
background : #f0f0f0;
|
||||
color : #999;
|
||||
border-color : #f0f0f0;
|
||||
}
|
||||
|
||||
#feedTree .counterNode {
|
||||
body#ttrssMain #feedTree .counterNode {
|
||||
font-weight : bold;
|
||||
display : inline-block;
|
||||
font-size : 9px;
|
||||
|
@ -1159,31 +1051,12 @@ body#ttrssMain #feedTree {
|
|||
float : right;
|
||||
position : relative;
|
||||
line-height : 14px;
|
||||
margin-right : 4px;
|
||||
margin-right : 8px;
|
||||
margin-top : 3px;
|
||||
min-width : 23px;
|
||||
height : 14px;
|
||||
}
|
||||
|
||||
#feedTree .dijitTreeRow {
|
||||
max-width: 100%;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
|
||||
body#ttrssPrefs hr {
|
||||
border-color : #ecf4ff;
|
||||
max-width : 100%;
|
||||
}
|
||||
|
||||
.dijitMenuItemLabel {
|
||||
font-size : 13px;
|
||||
}
|
||||
|
||||
.dijitTreeRowSelected .dijitTreeLabel {
|
||||
text-shadow : 1px 1px 2px #fff;
|
||||
}
|
||||
|
||||
#feedTree img[src*='indicator_white.gif'] {
|
||||
position : relative;
|
||||
top : -2px;
|
||||
|
@ -1198,3 +1071,23 @@ div.enclosure_title {
|
|||
|
||||
}
|
||||
|
||||
body#ttrssMain #headlines-frame .dijitCheckBox {
|
||||
border-width : 0px;
|
||||
opacity : 0.5;
|
||||
}
|
||||
|
||||
body#ttrssMain #headlines-frame .dijitCheckBoxHover,
|
||||
body#ttrssMain #headlines-frame .dijitCheckBoxChecked {
|
||||
opacity : 1;
|
||||
}
|
||||
|
||||
body#ttrssMain #feedTree .dijitTreeRow img.dijitTreeExpandoLeaf {
|
||||
width : 16px;
|
||||
height : 16px;
|
||||
vertical-align : middle;
|
||||
position : relative;
|
||||
}
|
||||
|
||||
:focus {
|
||||
outline: none;
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
body {
|
||||
background : #f9fbff;
|
||||
background : #f5f5f5;
|
||||
color : black;
|
||||
padding : 0px;
|
||||
font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
|
||||
|
@ -15,11 +15,11 @@ form {
|
|||
}
|
||||
|
||||
div.content {
|
||||
overflow : hidden;
|
||||
background : white;
|
||||
border : 1px solid #ccc;
|
||||
border : 1px solid #ddd;
|
||||
padding : 10px;
|
||||
border-radius : 4px;
|
||||
box-shadow : inset 0 0 3px rgba(0,0,0,0.1);
|
||||
box-shadow : 0px 1px 1px -1px rgba(0,0,0,0.1);
|
||||
}
|
||||
|
||||
p.warning {
|
||||
|
@ -40,9 +40,7 @@ div.insensitive-small {
|
|||
}
|
||||
|
||||
.floatingLogo {
|
||||
float : right;
|
||||
position : relative;
|
||||
top : -10px;
|
||||
display : none;
|
||||
}
|
||||
|
||||
a {
|
||||
|
@ -61,7 +59,6 @@ div.notice, div.warning, div.error {
|
|||
font-size : 12px;
|
||||
border-style : solid;
|
||||
border-color : #ccc;
|
||||
border-radius : 4px;
|
||||
border-width : 1px;
|
||||
box-shadow : inset 0px 0px 2px rgba(0,0,0,0.1);
|
||||
}
|
||||
|
|
105
source/css/zoom.css
Normal file
|
@ -0,0 +1,105 @@
|
|||
body#ttrssZoom {
|
||||
margin-left : auto;
|
||||
margin-right : auto;
|
||||
padding : 20px;
|
||||
max-width : 670px;
|
||||
background : #f5f5f5;
|
||||
}
|
||||
|
||||
body#ttrssZoom div.postHeader div.postFeedTitle {
|
||||
float : left;
|
||||
text-align : right;
|
||||
padding-left : 0px;
|
||||
font-size : 11px;
|
||||
}
|
||||
|
||||
body#ttrssZoom div.postHeader a.postComments {
|
||||
text-align : right;
|
||||
padding-left : 0px;
|
||||
font-size : 11px;
|
||||
}
|
||||
|
||||
body#ttrssZoom div.postHeader div.postDate {
|
||||
float : none;
|
||||
text-align : right;
|
||||
padding-left : 0px;
|
||||
color : #777;
|
||||
font-size : 11px;
|
||||
}
|
||||
|
||||
body#ttrssZoom div.postHeader div.postTags {
|
||||
color : #777;
|
||||
font-size : 11px;
|
||||
}
|
||||
|
||||
body#ttrssZoom div.postHeader div.postTitle {
|
||||
white-space : normal;
|
||||
font-size : 16px;
|
||||
}
|
||||
|
||||
body#ttrssZoom div.postContent {
|
||||
font-size : 15px;
|
||||
line-height : 1.5;
|
||||
}
|
||||
|
||||
body#ttrssZoom div.postContent p {
|
||||
max-width : 650px;
|
||||
-webkit-hyphens: auto;
|
||||
-moz-hyphens: auto;
|
||||
hyphens: auto;
|
||||
}
|
||||
|
||||
body#ttrssZoom div.postHeader {
|
||||
margin : 10px;
|
||||
border-width : 0px 0px 1px 0px;
|
||||
border-style : solid;
|
||||
border-color : #eee;
|
||||
background : white;
|
||||
}
|
||||
|
||||
body#ttrssZoom div.postReply {
|
||||
border : 1px solid #ddd;
|
||||
background : white;
|
||||
box-shadow : 0px 1px 1px -1px rgba(0,0,0,0.1);
|
||||
}
|
||||
|
||||
body#ttrssZoom div.footer {
|
||||
margin-top : 1em;
|
||||
text-align : center;
|
||||
}
|
||||
|
||||
body#ttrssZoom div.postContent img {
|
||||
max-width : 630px;
|
||||
height : auto;
|
||||
}
|
||||
|
||||
body#ttrssZoom div.postContent blockquote {
|
||||
margin : 5px 0px 5px 0px;
|
||||
color : #555;
|
||||
padding-left : 10px;
|
||||
border-width : 0px 0px 0px 4px;
|
||||
border-color : #ccc;
|
||||
border-style : solid;
|
||||
}
|
||||
|
||||
body#ttrssZoom div.postContent code {
|
||||
color : #009900;
|
||||
font-family : monospace;
|
||||
font-size : 12px;
|
||||
}
|
||||
|
||||
body#ttrssZoom div.postContent pre {
|
||||
margin : 5px 0px 5px 0px;
|
||||
padding : 10px;
|
||||
color : #555;
|
||||
font-family : monospace;
|
||||
font-size : 12px;
|
||||
border-width : 0px;
|
||||
border-color : #ccc;
|
||||
border-style : solid;
|
||||
background : #f5f5f5;
|
||||
display : block;
|
||||
max-width : 98%;
|
||||
overflow : auto;
|
||||
}
|
||||
|
0
source/feed-icons/.empty
Executable file
0
source/feed-icons/index.html
Normal file
|
@ -41,8 +41,6 @@
|
|||
header("Content-type: image/png");
|
||||
$stamp = gmdate("D, d M Y H:i:s", filemtime($filename)). " GMT";
|
||||
header("Last-Modified: $stamp", true);
|
||||
ob_clean(); // discard any data in the output buffer (if possible)
|
||||
flush(); // flush headers (if possible)
|
||||
readfile($filename);
|
||||
}
|
||||
} else {
|
||||
|
|
Before Width: | Height: | Size: 610 B After Width: | Height: | Size: 623 B |
Before Width: | Height: | Size: 718 B After Width: | Height: | Size: 717 B |
BIN
source/images/tick.png
Normal file
After Width: | Height: | Size: 537 B |
BIN
source/images/treeExpandImages.png
Normal file
After Width: | Height: | Size: 288 B |
BIN
source/images/untick.png
Normal file
After Width: | Height: | Size: 518 B |
|
@ -92,7 +92,7 @@
|
|||
}
|
||||
|
||||
function ccache_update($feed_id, $owner_uid, $is_cat = false,
|
||||
$update_pcat = true) {
|
||||
$update_pcat = true, $pcat_fast = false) {
|
||||
|
||||
if (!is_numeric($feed_id)) return;
|
||||
|
||||
|
@ -127,11 +127,13 @@
|
|||
|
||||
/* Recalculate counters for child feeds */
|
||||
|
||||
$result = db_query("SELECT id FROM ttrss_feeds
|
||||
if (!$pcat_fast) {
|
||||
$result = db_query("SELECT id FROM ttrss_feeds
|
||||
WHERE owner_uid = '$owner_uid' AND $cat_qpart");
|
||||
|
||||
while ($line = db_fetch_assoc($result)) {
|
||||
ccache_update($line["id"], $owner_uid, false, false);
|
||||
while ($line = db_fetch_assoc($result)) {
|
||||
ccache_update($line["id"], $owner_uid, false, false);
|
||||
}
|
||||
}
|
||||
|
||||
$result = db_query("SELECT SUM(value) AS sv
|
||||
|
@ -177,7 +179,7 @@
|
|||
|
||||
$cat_id = (int) db_fetch_result($result, 0, "cat_id");
|
||||
|
||||
ccache_update($cat_id, $owner_uid, true);
|
||||
ccache_update($cat_id, $owner_uid, true, true, true);
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -127,8 +127,6 @@
|
|||
ORDER BY ttrss_feed_categories.title, ttrss_feeds.title, score DESC, date_updated DESC
|
||||
LIMIT $limit");
|
||||
|
||||
$cur_feed_title = "";
|
||||
|
||||
$headlines_count = db_num_rows($result);
|
||||
|
||||
$headlines = array();
|
||||
|
|
|
@ -63,7 +63,7 @@
|
|||
htmlspecialchars($line["title"])."</span></a>";
|
||||
|
||||
$feed_url = "<a target=\"_blank\" class=\"fb_feedUrl\"
|
||||
href=\"$feed_url\"><img src='images/pub_set.svg'
|
||||
href=\"$feed_url\"><img src='images/pub_set.png'
|
||||
style='vertical-align : middle'></a>";
|
||||
|
||||
$rv .= "<li>$check_box $feed_url $site_url".
|
||||
|
@ -72,7 +72,6 @@
|
|||
} else if ($mode == 2) {
|
||||
$feed_url = htmlspecialchars($line["feed_url"]);
|
||||
$site_url = htmlspecialchars($line["site_url"]);
|
||||
$title = htmlspecialchars($line["title"]);
|
||||
|
||||
$check_box = "<input onclick='toggleSelectListRow2(this)' dojoType=\"dijit.form.CheckBox\"
|
||||
type=\"checkbox\">";
|
||||
|
@ -92,7 +91,7 @@
|
|||
htmlspecialchars($line["title"])."</span></a>";
|
||||
|
||||
$feed_url = "<a target=\"_blank\" class=\"fb_feedUrl\"
|
||||
href=\"$feed_url\"><img src='images/pub_set.svg'
|
||||
href=\"$feed_url\"><img src='images/pub_set.png'
|
||||
style='vertical-align : middle'></a>";
|
||||
|
||||
|
||||
|
|
2403
source/include/functions2.php
Normal file
|
@ -109,7 +109,7 @@
|
|||
|
||||
if (!$label_id) return;
|
||||
|
||||
$result = db_query(
|
||||
db_query(
|
||||
"DELETE FROM ttrss_user_labels2
|
||||
WHERE
|
||||
label_id = '$label_id' AND
|
||||
|
|
|
@ -2,15 +2,22 @@
|
|||
<html>
|
||||
<head>
|
||||
<title>Tiny Tiny RSS : Login</title>
|
||||
<link rel="stylesheet" type="text/css" href="lib/dijit/themes/claro/claro.css"/>
|
||||
<link rel="stylesheet" type="text/css" href="css/tt-rss.css">
|
||||
<?php echo stylesheet_tag("lib/dijit/themes/claro/claro.css") ?>
|
||||
<?php echo stylesheet_tag("css/tt-rss.css") ?>
|
||||
<?php echo stylesheet_tag("css/dijit.css") ?>
|
||||
<link rel="shortcut icon" type="image/png" href="images/favicon.png">
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
|
||||
<script type="text/javascript" src="lib/dojo/dojo.js"></script>
|
||||
<script type="text/javascript" src="lib/dojo/tt-rss-layer.js"></script>
|
||||
<script type="text/javascript" src="lib/prototype.js"></script>
|
||||
<script type="text/javascript" src="js/functions.js"></script>
|
||||
<script type="text/javascript" charset="utf-8" src="errors.php?mode=js"></script>
|
||||
<?php
|
||||
foreach (array("lib/prototype.js",
|
||||
"lib/dojo/dojo.js",
|
||||
"lib/dojo/tt-rss-layer.js",
|
||||
"js/functions.js",
|
||||
"errors.php?mode=js") as $jsfile) {
|
||||
|
||||
echo javascript_tag($jsfile);
|
||||
|
||||
} ?>
|
||||
|
||||
<script type="text/javascript">
|
||||
require({cache:{}});
|
||||
Event.observe(window, 'load', function() {
|
||||
|
|
|
@ -2,6 +2,19 @@
|
|||
define_default('DAEMON_UPDATE_LOGIN_LIMIT', 30);
|
||||
define_default('DAEMON_FEED_LIMIT', 500);
|
||||
define_default('DAEMON_SLEEP_INTERVAL', 120);
|
||||
define_default('_MIN_CACHE_IMAGE_SIZE', 1024);
|
||||
|
||||
function calculate_article_hash($article, $pluginhost) {
|
||||
$tmp = "";
|
||||
|
||||
foreach ($article as $k => $v) {
|
||||
if ($k != "feed" && isset($v)) {
|
||||
$tmp .= sha1("$k:" . (is_array($v) ? implode(",", $v) : $v));
|
||||
}
|
||||
}
|
||||
|
||||
return sha1(implode(",", $pluginhost->get_plugin_names()) . $tmp);
|
||||
}
|
||||
|
||||
function update_feedbrowser_cache() {
|
||||
|
||||
|
@ -79,7 +92,7 @@
|
|||
$login_thresh_qpart = "";
|
||||
}
|
||||
|
||||
// Test if the feed need a update (update interval exceded).
|
||||
// Test if the feed need a update (update interval exceeded).
|
||||
if (DB_TYPE == "pgsql") {
|
||||
$update_limit_qpart = "AND ((
|
||||
ttrss_feeds.update_interval = 0
|
||||
|
@ -88,8 +101,10 @@
|
|||
) OR (
|
||||
ttrss_feeds.update_interval > 0
|
||||
AND ttrss_feeds.last_updated < NOW() - CAST((ttrss_feeds.update_interval || ' minutes') AS INTERVAL)
|
||||
) OR ttrss_feeds.last_updated IS NULL
|
||||
OR last_updated = '1970-01-01 00:00:00')";
|
||||
) OR (ttrss_feeds.last_updated IS NULL
|
||||
AND ttrss_user_prefs.value != '-1')
|
||||
OR (last_updated = '1970-01-01 00:00:00'
|
||||
AND ttrss_user_prefs.value != '-1'))";
|
||||
} else {
|
||||
$update_limit_qpart = "AND ((
|
||||
ttrss_feeds.update_interval = 0
|
||||
|
@ -98,8 +113,10 @@
|
|||
) OR (
|
||||
ttrss_feeds.update_interval > 0
|
||||
AND ttrss_feeds.last_updated < DATE_SUB(NOW(), INTERVAL ttrss_feeds.update_interval MINUTE)
|
||||
) OR ttrss_feeds.last_updated IS NULL
|
||||
OR last_updated = '1970-01-01 00:00:00')";
|
||||
) OR (ttrss_feeds.last_updated IS NULL
|
||||
AND ttrss_user_prefs.value != '-1')
|
||||
OR (last_updated = '1970-01-01 00:00:00'
|
||||
AND ttrss_user_prefs.value != '-1'))";
|
||||
}
|
||||
|
||||
// Test if feed is currently being updated by another process.
|
||||
|
@ -118,6 +135,7 @@
|
|||
ttrss_feeds, ttrss_users, ttrss_user_prefs
|
||||
WHERE
|
||||
ttrss_feeds.owner_uid = ttrss_users.id
|
||||
AND ttrss_user_prefs.profile IS NULL
|
||||
AND ttrss_users.id = ttrss_user_prefs.owner_uid
|
||||
AND ttrss_user_prefs.pref_name = 'DEFAULT_UPDATE_INTERVAL'
|
||||
$login_thresh_qpart $update_limit_qpart
|
||||
|
@ -151,6 +169,7 @@
|
|||
}
|
||||
|
||||
$nf = 0;
|
||||
$bstarted = microtime(true);
|
||||
|
||||
// For each feed, we call the feed update function.
|
||||
foreach ($feeds_to_update as $feed) {
|
||||
|
@ -165,6 +184,7 @@
|
|||
ttrss_user_prefs.owner_uid = ttrss_feeds.owner_uid AND
|
||||
ttrss_users.id = ttrss_user_prefs.owner_uid AND
|
||||
ttrss_user_prefs.pref_name = 'DEFAULT_UPDATE_INTERVAL' AND
|
||||
ttrss_user_prefs.profile IS NULL AND
|
||||
feed_url = '".db_escape_string($feed)."' AND
|
||||
(ttrss_feeds.update_interval > 0 OR
|
||||
ttrss_user_prefs.value != '-1')
|
||||
|
@ -172,15 +192,27 @@
|
|||
ORDER BY ttrss_feeds.id $query_limit");
|
||||
|
||||
if (db_num_rows($tmp_result) > 0) {
|
||||
$rss = false;
|
||||
|
||||
while ($tline = db_fetch_assoc($tmp_result)) {
|
||||
if($debug) _debug(" => " . $tline["last_updated"] . ", " . $tline["id"] . " " . $tline["owner_uid"]);
|
||||
update_rss_feed($tline["id"], true);
|
||||
|
||||
$fstarted = microtime(true);
|
||||
$rss = update_rss_feed($tline["id"], true, false);
|
||||
_debug_suppress(false);
|
||||
|
||||
_debug(sprintf(" %.4f (sec)", microtime(true) - $fstarted));
|
||||
|
||||
++$nf;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ($nf > 0) {
|
||||
_debug(sprintf("Processed %d feeds in %.4f (sec), %.4f (sec/feed avg)", $nf,
|
||||
microtime(true) - $bstarted, (microtime(true) - $bstarted) / $nf));
|
||||
}
|
||||
|
||||
require_once "digest.php";
|
||||
|
||||
// Send feed digests by email if needed.
|
||||
|
@ -191,7 +223,7 @@
|
|||
} // function update_daemon_common
|
||||
|
||||
// ignore_daemon is not used
|
||||
function update_rss_feed($feed, $ignore_daemon = false, $no_cache = false) {
|
||||
function update_rss_feed($feed, $ignore_daemon = false, $no_cache = false, $rss = false) {
|
||||
|
||||
$debug_enabled = defined('DAEMON_EXTENDED_DEBUG') || $_REQUEST['xdebug'];
|
||||
|
||||
|
@ -199,7 +231,7 @@
|
|||
_debug("start", $debug_enabled);
|
||||
|
||||
$result = db_query("SELECT id,update_interval,auth_login,
|
||||
feed_url,auth_pass,cache_images,last_updated,
|
||||
feed_url,auth_pass,cache_images,
|
||||
mark_unread_on_update, owner_uid,
|
||||
pubsub_state, auth_pass_encrypted,
|
||||
(SELECT max(date_entered) FROM
|
||||
|
@ -211,7 +243,6 @@
|
|||
return false;
|
||||
}
|
||||
|
||||
$last_updated = db_fetch_result($result, 0, "last_updated");
|
||||
$last_article_timestamp = @strtotime(db_fetch_result($result, 0, "last_article_timestamp"));
|
||||
|
||||
if (defined('_DISABLE_HTTP_304'))
|
||||
|
@ -252,34 +283,37 @@
|
|||
$pluginhost->load($user_plugins, PluginHost::KIND_USER, $owner_uid);
|
||||
$pluginhost->load_data();
|
||||
|
||||
$rss = false;
|
||||
$rss_hash = false;
|
||||
|
||||
$force_refetch = isset($_REQUEST["force_refetch"]);
|
||||
|
||||
if (file_exists($cache_filename) &&
|
||||
is_readable($cache_filename) &&
|
||||
!$auth_login && !$auth_pass &&
|
||||
filemtime($cache_filename) > time() - 30) {
|
||||
|
||||
_debug("using local cache.", $debug_enabled);
|
||||
|
||||
@$feed_data = file_get_contents($cache_filename);
|
||||
|
||||
if ($feed_data) {
|
||||
$rss_hash = sha1($feed_data);
|
||||
}
|
||||
|
||||
if ($rss && is_object($rss) && get_class($rss) == "FeedParser") {
|
||||
_debug("using previously initialized parser object");
|
||||
} else {
|
||||
_debug("local cache will not be used for this feed", $debug_enabled);
|
||||
}
|
||||
$rss_hash = false;
|
||||
|
||||
if (!$rss) {
|
||||
$force_refetch = isset($_REQUEST["force_refetch"]);
|
||||
|
||||
foreach ($pluginhost->get_hooks(PluginHost::HOOK_FETCH_FEED) as $plugin) {
|
||||
$feed_data = $plugin->hook_fetch_feed($feed_data, $fetch_url, $owner_uid, $feed);
|
||||
$feed_data = $plugin->hook_fetch_feed($feed_data, $fetch_url, $owner_uid, $feed, $last_article_timestamp, $auth_login, $auth_pass);
|
||||
}
|
||||
|
||||
// try cache
|
||||
if (!$feed_data &&
|
||||
file_exists($cache_filename) &&
|
||||
is_readable($cache_filename) &&
|
||||
!$auth_login && !$auth_pass &&
|
||||
filemtime($cache_filename) > time() - 30) {
|
||||
|
||||
_debug("using local cache [$cache_filename].", $debug_enabled);
|
||||
|
||||
@$feed_data = file_get_contents($cache_filename);
|
||||
|
||||
if ($feed_data) {
|
||||
$rss_hash = sha1($feed_data);
|
||||
}
|
||||
|
||||
} else {
|
||||
_debug("local cache will not be used for this feed", $debug_enabled);
|
||||
}
|
||||
|
||||
// fetch feed from source
|
||||
if (!$feed_data) {
|
||||
_debug("fetching [$fetch_url]...", $debug_enabled);
|
||||
_debug("If-Modified-Since: ".gmdate('D, d M Y H:i:s \G\M\T', $last_article_timestamp), $debug_enabled);
|
||||
|
@ -318,6 +352,16 @@
|
|||
}
|
||||
}
|
||||
} */
|
||||
|
||||
// cache vanilla feed data for re-use
|
||||
if ($feed_data && !$auth_pass && !$auth_login && is_writable(CACHE_DIR . "/simplepie")) {
|
||||
$new_rss_hash = sha1($feed_data);
|
||||
|
||||
if ($new_rss_hash != $rss_hash) {
|
||||
_debug("saving $cache_filename", $debug_enabled);
|
||||
@file_put_contents($cache_filename, $feed_data);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!$feed_data) {
|
||||
|
@ -356,10 +400,12 @@
|
|||
$rss->init();
|
||||
}
|
||||
|
||||
require_once "lib/languagedetect/LanguageDetect.php";
|
||||
if (DETECT_ARTICLE_LANGUAGE) {
|
||||
require_once "lib/languagedetect/LanguageDetect.php";
|
||||
|
||||
$lang = new Text_LanguageDetect();
|
||||
$lang->setNameMode(2);
|
||||
$lang = new Text_LanguageDetect();
|
||||
$lang->setNameMode(2);
|
||||
}
|
||||
|
||||
// print_r($rss);
|
||||
|
||||
|
@ -367,16 +413,6 @@
|
|||
|
||||
if (!$rss->error()) {
|
||||
|
||||
// cache data for later
|
||||
if (!$auth_pass && !$auth_login && is_writable(CACHE_DIR . "/simplepie")) {
|
||||
$new_rss_hash = sha1($rss_data);
|
||||
|
||||
if ($new_rss_hash != $rss_hash && count($rss->get_items()) > 0 ) {
|
||||
_debug("saving $cache_filename", $debug_enabled);
|
||||
@file_put_contents($cache_filename, $feed_data);
|
||||
}
|
||||
}
|
||||
|
||||
// We use local pluginhost here because we need to load different per-user feed plugins
|
||||
$pluginhost->run_hooks(PluginHost::HOOK_FEED_PARSED, "hook_feed_parsed", $rss);
|
||||
|
||||
|
@ -495,7 +531,20 @@
|
|||
|
||||
_debug("feed hub url: $feed_hub_url", $debug_enabled);
|
||||
|
||||
if ($feed_hub_url && function_exists('curl_init') &&
|
||||
$feed_self_url = $fetch_url;
|
||||
|
||||
$links = $rss->get_links('self');
|
||||
|
||||
if ($links && is_array($links)) {
|
||||
foreach ($links as $l) {
|
||||
$feed_self_url = $l;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
_debug("feed self url = $feed_self_url");
|
||||
|
||||
if ($feed_hub_url && $feed_self_url && function_exists('curl_init') &&
|
||||
!ini_get("open_basedir")) {
|
||||
|
||||
require_once 'lib/pubsubhubbub/subscriber.php';
|
||||
|
@ -505,9 +554,9 @@
|
|||
|
||||
$s = new Subscriber($feed_hub_url, $callback_url);
|
||||
|
||||
$rc = $s->subscribe($fetch_url);
|
||||
$rc = $s->subscribe($feed_self_url);
|
||||
|
||||
_debug("feed hub url found, subscribe request sent.", $debug_enabled);
|
||||
_debug("feed hub url found, subscribe request sent. [rc=$rc]", $debug_enabled);
|
||||
|
||||
db_query("UPDATE ttrss_feeds SET pubsub_state = 1
|
||||
WHERE id = '$feed'");
|
||||
|
@ -524,9 +573,6 @@
|
|||
$entry_guid = $item->get_id();
|
||||
if (!$entry_guid) $entry_guid = $item->get_link();
|
||||
if (!$entry_guid) $entry_guid = make_guid_from_title($item->get_title());
|
||||
|
||||
_debug("f_guid $entry_guid", $debug_enabled);
|
||||
|
||||
if (!$entry_guid) continue;
|
||||
|
||||
$entry_guid = "$owner_uid,$entry_guid";
|
||||
|
@ -543,9 +589,6 @@
|
|||
|
||||
if ($entry_timestamp == -1 || !$entry_timestamp || $entry_timestamp > time()) {
|
||||
$entry_timestamp = time();
|
||||
$no_orig_date = 'true';
|
||||
} else {
|
||||
$no_orig_date = 'false';
|
||||
}
|
||||
|
||||
$entry_timestamp_fmt = strftime("%Y/%m/%d %H:%M:%S", $entry_timestamp);
|
||||
|
@ -572,15 +615,19 @@
|
|||
print "\n";
|
||||
}
|
||||
|
||||
$entry_language = $lang->detect($entry_title . " " . $entry_content, 1);
|
||||
$entry_language = "";
|
||||
|
||||
if (count($entry_language) > 0) {
|
||||
$entry_language = array_keys($entry_language);
|
||||
$entry_language = db_escape_string(substr($entry_language[0], 0, 2));
|
||||
if (DETECT_ARTICLE_LANGUAGE) {
|
||||
$entry_language = $lang->detect($entry_title . " " . $entry_content, 1);
|
||||
|
||||
_debug("detected language: $entry_language", $debug_enabled);
|
||||
} else{
|
||||
$entry_language = "";
|
||||
if (count($entry_language) > 0) {
|
||||
$possible = array_keys($entry_language);
|
||||
$entry_language = $possible[0];
|
||||
|
||||
_debug("detected language: $entry_language", $debug_enabled);
|
||||
} else {
|
||||
$entry_language = "";
|
||||
}
|
||||
}
|
||||
|
||||
$entry_comments = $item->get_comments_url();
|
||||
|
@ -618,24 +665,15 @@
|
|||
|
||||
_debug("done collecting data.", $debug_enabled);
|
||||
|
||||
// TODO: less memory-hungry implementation
|
||||
|
||||
_debug("applying plugin filters..", $debug_enabled);
|
||||
|
||||
// FIXME not sure if owner_uid is a good idea here, we may have a base entry without user entry (?)
|
||||
$result = db_query("SELECT plugin_data,title,content,link,tag_cache,author FROM ttrss_entries, ttrss_user_entries
|
||||
WHERE ref_id = id AND (guid = '".db_escape_string($entry_guid)."' OR guid = '$entry_guid_hashed') AND owner_uid = $owner_uid");
|
||||
$result = db_query("SELECT id, content_hash FROM ttrss_entries
|
||||
WHERE guid = '".db_escape_string($entry_guid)."' OR guid = '$entry_guid_hashed'");
|
||||
|
||||
if (db_num_rows($result) != 0) {
|
||||
$entry_plugin_data = db_fetch_result($result, 0, "plugin_data");
|
||||
$stored_article = array("title" => db_fetch_result($result, 0, "title"),
|
||||
"content" => db_fetch_result($result, 0, "content"),
|
||||
"link" => db_fetch_result($result, 0, "link"),
|
||||
"tags" => explode(",", db_fetch_result($result, 0, "tag_cache")),
|
||||
"author" => db_fetch_result($result, 0, "author"));
|
||||
$base_entry_id = db_fetch_result($result, 0, "id");
|
||||
$entry_stored_hash = db_fetch_result($result, 0, "content_hash");
|
||||
} else {
|
||||
$entry_plugin_data = "";
|
||||
$stored_article = array();
|
||||
$base_entry_id = false;
|
||||
$entry_stored_hash = "";
|
||||
}
|
||||
|
||||
$article = array("owner_uid" => $owner_uid, // read only
|
||||
|
@ -644,36 +682,63 @@
|
|||
"content" => $entry_content,
|
||||
"link" => $entry_link,
|
||||
"tags" => $entry_tags,
|
||||
"plugin_data" => $entry_plugin_data,
|
||||
"author" => $entry_author,
|
||||
"stored" => $stored_article,
|
||||
"language" => $entry_language, // read only
|
||||
"feed" => array("id" => $feed,
|
||||
"fetch_url" => $fetch_url,
|
||||
"site_url" => $site_url)
|
||||
);
|
||||
|
||||
foreach ($pluginhost->get_hooks(PluginHost::HOOK_ARTICLE_FILTER) as $plugin) {
|
||||
$article = $plugin->hook_article_filter($article);
|
||||
$entry_plugin_data = "";
|
||||
$entry_current_hash = calculate_article_hash($article, $pluginhost);
|
||||
|
||||
_debug("article hash: $entry_current_hash [stored=$entry_stored_hash]", $debug_enabled);
|
||||
|
||||
if ($entry_current_hash == $entry_stored_hash && !isset($_REQUEST["force_rehash"])) {
|
||||
_debug("stored article seems up to date [IID: $base_entry_id], updating timestamp only", $debug_enabled);
|
||||
|
||||
// we keep encountering the entry in feeds, so we need to
|
||||
// update date_updated column so that we don't get horrible
|
||||
// dupes when the entry gets purged and reinserted again e.g.
|
||||
// in the case of SLOW SLOW OMG SLOW updating feeds
|
||||
|
||||
$base_entry_id = db_fetch_result($result, 0, "id");
|
||||
|
||||
db_query("UPDATE ttrss_entries SET date_updated = NOW()
|
||||
WHERE id = '$base_entry_id'");
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
_debug("hash differs, applying plugin filters:", $debug_enabled);
|
||||
|
||||
foreach ($pluginhost->get_hooks(PluginHost::HOOK_ARTICLE_FILTER) as $plugin) {
|
||||
_debug("... " . get_class($plugin), $debug_enabled);
|
||||
|
||||
$start = microtime(true);
|
||||
$article = $plugin->hook_article_filter($article);
|
||||
|
||||
_debug("=== " . sprintf("%.4f (sec)", microtime(true) - $start), $debug_enabled);
|
||||
|
||||
$entry_plugin_data .= mb_strtolower(get_class($plugin)) . ",";
|
||||
}
|
||||
|
||||
$entry_plugin_data = db_escape_string($entry_plugin_data);
|
||||
|
||||
_debug("plugin data: $entry_plugin_data", $debug_enabled);
|
||||
|
||||
$entry_tags = $article["tags"];
|
||||
$entry_guid = db_escape_string($entry_guid);
|
||||
$entry_title = db_escape_string($article["title"]);
|
||||
$entry_author = db_escape_string($article["author"]);
|
||||
$entry_link = db_escape_string($article["link"]);
|
||||
$entry_plugin_data = db_escape_string($article["plugin_data"]);
|
||||
$entry_content = $article["content"]; // escaped below
|
||||
|
||||
|
||||
_debug("plugin data: $entry_plugin_data", $debug_enabled);
|
||||
|
||||
if ($cache_images && is_writable(CACHE_DIR . '/images'))
|
||||
cache_images($entry_content, $site_url, $debug_enabled);
|
||||
|
||||
$entry_content = db_escape_string($entry_content, false);
|
||||
|
||||
$content_hash = "SHA1:" . sha1($entry_content);
|
||||
|
||||
db_query("BEGIN");
|
||||
|
||||
$result = db_query("SELECT id FROM ttrss_entries
|
||||
|
@ -707,8 +772,8 @@
|
|||
'$entry_link',
|
||||
'$entry_timestamp_fmt',
|
||||
'$entry_content',
|
||||
'$content_hash',
|
||||
$no_orig_date,
|
||||
'$entry_current_hash',
|
||||
false,
|
||||
NOW(),
|
||||
'$date_feed_processed',
|
||||
'$entry_comments',
|
||||
|
@ -720,28 +785,14 @@
|
|||
$article_labels = array();
|
||||
|
||||
} else {
|
||||
// we keep encountering the entry in feeds, so we need to
|
||||
// update date_updated column so that we don't get horrible
|
||||
// dupes when the entry gets purged and reinserted again e.g.
|
||||
// in the case of SLOW SLOW OMG SLOW updating feeds
|
||||
|
||||
$base_entry_id = db_fetch_result($result, 0, "id");
|
||||
|
||||
db_query("UPDATE ttrss_entries SET date_updated = NOW()
|
||||
WHERE id = '$base_entry_id'");
|
||||
|
||||
$article_labels = get_article_labels($base_entry_id, $owner_uid);
|
||||
}
|
||||
|
||||
// now it should exist, if not - bad luck then
|
||||
|
||||
$result = db_query("SELECT
|
||||
id,content_hash,no_orig_date,title,plugin_data,guid,
|
||||
".SUBSTRING_FOR_DATE."(date_updated,1,19) as date_updated,
|
||||
".SUBSTRING_FOR_DATE."(updated,1,19) as updated,
|
||||
num_comments
|
||||
FROM
|
||||
ttrss_entries
|
||||
$result = db_query("SELECT id FROM ttrss_entries
|
||||
WHERE guid = '$entry_guid' OR guid = '$entry_guid_hashed'");
|
||||
|
||||
$entry_ref_id = 0;
|
||||
|
@ -751,14 +802,6 @@
|
|||
|
||||
_debug("base guid found, checking for user record", $debug_enabled);
|
||||
|
||||
// this will be used below in update handler
|
||||
$orig_content_hash = db_fetch_result($result, 0, "content_hash");
|
||||
$orig_title = db_fetch_result($result, 0, "title");
|
||||
$orig_num_comments = db_fetch_result($result, 0, "num_comments");
|
||||
$orig_date_updated = strtotime(db_fetch_result($result,
|
||||
0, "date_updated"));
|
||||
$orig_plugin_data = db_fetch_result($result, 0, "plugin_data");
|
||||
|
||||
$ref_id = db_fetch_result($result, 0, "id");
|
||||
$entry_ref_id = $ref_id;
|
||||
|
||||
|
@ -872,7 +915,7 @@
|
|||
|
||||
$p = new Publisher(PUBSUBHUBBUB_HUB);
|
||||
|
||||
$pubsub_result = $p->publish_update($rss_link);
|
||||
/* $pubsub_result = */ $p->publish_update($rss_link);
|
||||
}
|
||||
|
||||
$result = db_query(
|
||||
|
@ -892,53 +935,20 @@
|
|||
|
||||
_debug("RID: $entry_ref_id, IID: $entry_int_id", $debug_enabled);
|
||||
|
||||
$post_needs_update = false;
|
||||
$update_insignificant = false;
|
||||
db_query("UPDATE ttrss_entries
|
||||
SET title = '$entry_title',
|
||||
content = '$entry_content',
|
||||
content_hash = '$entry_current_hash',
|
||||
updated = '$entry_timestamp_fmt',
|
||||
num_comments = '$num_comments',
|
||||
plugin_data = '$entry_plugin_data',
|
||||
author = '$entry_author',
|
||||
lang = '$entry_language'
|
||||
WHERE id = '$ref_id'");
|
||||
|
||||
if ($orig_num_comments != $num_comments) {
|
||||
$post_needs_update = true;
|
||||
$update_insignificant = true;
|
||||
}
|
||||
|
||||
if ($entry_plugin_data != $orig_plugin_data) {
|
||||
$post_needs_update = true;
|
||||
$update_insignificant = true;
|
||||
}
|
||||
|
||||
if ($content_hash != $orig_content_hash) {
|
||||
$post_needs_update = true;
|
||||
$update_insignificant = false;
|
||||
}
|
||||
|
||||
if (db_escape_string($orig_title) != $entry_title) {
|
||||
$post_needs_update = true;
|
||||
$update_insignificant = false;
|
||||
}
|
||||
|
||||
// if post needs update, update it and mark all user entries
|
||||
// linking to this post as updated
|
||||
if ($post_needs_update) {
|
||||
|
||||
if (defined('DAEMON_EXTENDED_DEBUG')) {
|
||||
_debug("post $entry_guid_hashed needs update...", $debug_enabled);
|
||||
}
|
||||
|
||||
// print "<!-- post $orig_title needs update : $post_needs_update -->";
|
||||
|
||||
db_query("UPDATE ttrss_entries
|
||||
SET title = '$entry_title', content = '$entry_content',
|
||||
content_hash = '$content_hash',
|
||||
updated = '$entry_timestamp_fmt',
|
||||
num_comments = '$num_comments',
|
||||
plugin_data = '$entry_plugin_data'
|
||||
WHERE id = '$ref_id'");
|
||||
|
||||
if (!$update_insignificant) {
|
||||
if ($mark_unread_on_update) {
|
||||
db_query("UPDATE ttrss_user_entries
|
||||
SET last_read = null, unread = true WHERE ref_id = '$ref_id'");
|
||||
}
|
||||
}
|
||||
if ($mark_unread_on_update) {
|
||||
db_query("UPDATE ttrss_user_entries
|
||||
SET last_read = null, unread = true WHERE ref_id = '$ref_id'");
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -960,7 +970,7 @@
|
|||
if (is_array($encs)) {
|
||||
foreach ($encs as $e) {
|
||||
$e_item = array(
|
||||
$e->link, $e->type, $e->length, $e->title);
|
||||
$e->link, $e->type, $e->length, $e->title, $e->width, $e->height);
|
||||
array_push($enclosures, $e_item);
|
||||
}
|
||||
}
|
||||
|
@ -980,14 +990,16 @@
|
|||
$enc_type = db_escape_string($enc[1]);
|
||||
$enc_dur = db_escape_string($enc[2]);
|
||||
$enc_title = db_escape_string($enc[3]);
|
||||
$enc_width = intval($enc[4]);
|
||||
$enc_height = intval($enc[5]);
|
||||
|
||||
$result = db_query("SELECT id FROM ttrss_enclosures
|
||||
WHERE content_url = '$enc_url' AND post_id = '$entry_ref_id'");
|
||||
|
||||
if (db_num_rows($result) == 0) {
|
||||
db_query("INSERT INTO ttrss_enclosures
|
||||
(content_url, content_type, title, duration, post_id) VALUES
|
||||
('$enc_url', '$enc_type', '$enc_title', '$enc_dur', '$entry_ref_id')");
|
||||
(content_url, content_type, title, duration, post_id, width, height) VALUES
|
||||
('$enc_url', '$enc_type', '$enc_title', '$enc_dur', '$entry_ref_id', $enc_width, $enc_height)");
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1101,21 +1113,27 @@
|
|||
|
||||
$error_msg = db_escape_string(mb_substr($rss->error(), 0, 245));
|
||||
|
||||
_debug("error fetching feed: $error_msg", $debug_enabled);
|
||||
_debug("fetch error: $error_msg", $debug_enabled);
|
||||
|
||||
if (count($rss->errors()) > 1) {
|
||||
foreach ($rss->errors() as $error) {
|
||||
_debug("+ $error");
|
||||
}
|
||||
}
|
||||
|
||||
db_query(
|
||||
"UPDATE ttrss_feeds SET last_error = '$error_msg',
|
||||
last_updated = NOW() WHERE id = '$feed'");
|
||||
last_updated = NOW() WHERE id = '$feed'");
|
||||
|
||||
unset($rss);
|
||||
}
|
||||
|
||||
unset($rss);
|
||||
|
||||
_debug("done", $debug_enabled);
|
||||
|
||||
return $rss;
|
||||
}
|
||||
|
||||
function cache_images($html, $site_url, $debug) {
|
||||
$cache_dir = CACHE_DIR . "/images";
|
||||
|
||||
libxml_use_internal_errors(true);
|
||||
|
||||
$charset_hack = '<head>
|
||||
|
@ -1139,7 +1157,7 @@
|
|||
if (!file_exists($local_filename)) {
|
||||
$file_content = fetch_file_contents($src);
|
||||
|
||||
if ($file_content && strlen($file_content) > 1024) {
|
||||
if ($file_content && strlen($file_content) > _MIN_CACHE_IMAGE_SIZE) {
|
||||
file_put_contents($local_filename, $file_content);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -146,11 +146,6 @@
|
|||
array_push($errors, "PHP support for CURL is required for PubSubHubbub.");
|
||||
}
|
||||
|
||||
if (SPHINX_ENABLED && class_exists("SphinxClient")) {
|
||||
array_push($errors, "Your PHP has a separate systemwide Sphinx client installed which conflicts with the client library used by tt-rss. Either remove the system library or disable Sphinx support.");
|
||||
|
||||
}
|
||||
|
||||
if (!class_exists("DOMDocument")) {
|
||||
array_push($errors, "PHP support for DOMDocument is required, but was not found.");
|
||||
}
|
||||
|
|
|
@ -1,3 +1,3 @@
|
|||
<?php # This file has been generated at: Thu May 30 08:39:20 MSK 2013
|
||||
<?php # This file has been generated at: Fri Sep 27 13:42:37 MSK 2013
|
||||
define('GENERATED_CONFIG_CHECK', 26);
|
||||
$requred_defines = array( 'DB_TYPE', 'DB_HOST', 'DB_USER', 'DB_NAME', 'DB_PASS', 'MYSQL_CHARSET', 'SELF_URL_PATH', 'FEED_CRYPT_KEY', 'SINGLE_USER_MODE', 'SIMPLE_UPDATE_MODE', 'PHP_EXECUTABLE', 'LOCK_DIRECTORY', 'CACHE_DIR', 'ICONS_DIR', 'ICONS_URL', 'AUTH_AUTO_CREATE', 'AUTH_AUTO_LOGIN', 'FORCE_ARTICLE_PURGE', 'PUBSUBHUBBUB_HUB', 'PUBSUBHUBBUB_ENABLED', 'SPHINX_ENABLED', 'SPHINX_SERVER', 'SPHINX_INDEX', 'ENABLE_REGISTRATION', 'REG_NOTIFY_ADDRESS', 'REG_MAX_USERS', 'SESSION_COOKIE_LIFETIME', 'SESSION_CHECK_ADDRESS', 'SMTP_FROM_NAME', 'SMTP_FROM_ADDRESS', 'DIGEST_SUBJECT', 'SMTP_SERVER', 'SMTP_LOGIN', 'SMTP_PASSWORD', 'SMTP_SECURE', 'CHECK_FOR_NEW_VERSION', 'ENABLE_GZIP_OUTPUT', 'PLUGINS', 'LOG_DESTINATION', 'CONFIG_VERSION'); ?>
|
||||
$requred_defines = array( 'DB_TYPE', 'DB_HOST', 'DB_USER', 'DB_NAME', 'DB_PASS', 'MYSQL_CHARSET', 'SELF_URL_PATH', 'FEED_CRYPT_KEY', 'SINGLE_USER_MODE', 'SIMPLE_UPDATE_MODE', 'PHP_EXECUTABLE', 'LOCK_DIRECTORY', 'CACHE_DIR', 'ICONS_DIR', 'ICONS_URL', 'AUTH_AUTO_CREATE', 'AUTH_AUTO_LOGIN', 'FORCE_ARTICLE_PURGE', 'PUBSUBHUBBUB_HUB', 'PUBSUBHUBBUB_ENABLED', 'ENABLE_REGISTRATION', 'REG_NOTIFY_ADDRESS', 'REG_MAX_USERS', 'SESSION_COOKIE_LIFETIME', 'SESSION_CHECK_ADDRESS', 'SMTP_FROM_NAME', 'SMTP_FROM_ADDRESS', 'DIGEST_SUBJECT', 'SMTP_SERVER', 'SMTP_LOGIN', 'SMTP_PASSWORD', 'SMTP_SECURE', 'CHECK_FOR_NEW_VERSION', 'DETECT_ARTICLE_LANGUAGE', 'ENABLE_GZIP_OUTPUT', 'PLUGINS', 'LOG_DESTINATION', 'CONFIG_VERSION'); ?>
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
<?php
|
||||
define('VERSION_STATIC', '1.10');
|
||||
define('VERSION_STATIC', '1.14');
|
||||
|
||||
function get_version() {
|
||||
date_default_timezone_set('UTC');
|
||||
|
|
|
@ -56,15 +56,19 @@
|
|||
<head>
|
||||
<title>Tiny Tiny RSS</title>
|
||||
|
||||
<?php stylesheet_tag("lib/dijit/themes/claro/claro.css"); ?>
|
||||
<?php stylesheet_tag("css/layout.css"); ?>
|
||||
<script type="text/javascript">
|
||||
var __ttrss_version = "<?php echo VERSION ?>"
|
||||
</script>
|
||||
|
||||
<?php echo stylesheet_tag("lib/dijit/themes/claro/claro.css"); ?>
|
||||
<?php echo stylesheet_tag("css/layout.css"); ?>
|
||||
|
||||
<?php if ($_SESSION["uid"]) {
|
||||
$theme = get_pref( "USER_CSS_THEME", $_SESSION["uid"], false);
|
||||
if ($theme && file_exists("themes/$theme")) {
|
||||
stylesheet_tag("themes/$theme");
|
||||
echo stylesheet_tag("themes/$theme");
|
||||
} else {
|
||||
stylesheet_tag("themes/default.css");
|
||||
echo stylesheet_tag("themes/default.css");
|
||||
}
|
||||
}
|
||||
?>
|
||||
|
@ -86,12 +90,12 @@
|
|||
|
||||
<?php
|
||||
foreach (array("lib/prototype.js",
|
||||
"lib/scriptaculous/scriptaculous.js?load=effects,dragdrop,controls",
|
||||
"lib/scriptaculous/scriptaculous.js?load=effects,controls",
|
||||
"lib/dojo/dojo.js",
|
||||
"lib/dojo/tt-rss-layer.js",
|
||||
"errors.php?mode=js") as $jsfile) {
|
||||
|
||||
javascript_tag($jsfile);
|
||||
echo javascript_tag($jsfile);
|
||||
|
||||
} ?>
|
||||
|
||||
|
@ -153,6 +157,10 @@
|
|||
<div id="toolbar" dojoType="dijit.layout.ContentPane" region="top">
|
||||
<div id="main-toolbar" dojoType="dijit.Toolbar">
|
||||
|
||||
<form id="headlines-toolbar" action="" onsubmit='return false'>
|
||||
|
||||
</form>
|
||||
|
||||
<form id="main_toolbar_form" action="" onsubmit='return false'>
|
||||
|
||||
<button dojoType="dijit.form.Button" id="collapse_feeds_btn"
|
||||
|
@ -257,9 +265,6 @@
|
|||
|
||||
<div id="headlines-wrap-inner" dojoType="dijit.layout.BorderContainer" region="center">
|
||||
|
||||
<div id="headlines-toolbar" dojoType="dijit.layout.ContentPane" region="top">
|
||||
</div>
|
||||
|
||||
<div id="floatingTitle" style="display : none"></div>
|
||||
|
||||
<div id="headlines-frame" dojoType="dijit.layout.ContentPane"
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
<title>Tiny Tiny RSS - Installer</title>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
|
||||
<link rel="stylesheet" type="text/css" href="../css/utility.css">
|
||||
<link rel="stylesheet" type="text/css" href="../css/dijit.css">
|
||||
<style type="text/css">
|
||||
textarea { font-size : 12px; }
|
||||
</style>
|
||||
|
@ -10,6 +11,12 @@
|
|||
<body>
|
||||
|
||||
<?php
|
||||
|
||||
// could be needed because of existing config.php
|
||||
function define_default($param, $value) {
|
||||
//
|
||||
}
|
||||
|
||||
function make_password($length = 8) {
|
||||
|
||||
$password = "";
|
||||
|
@ -263,7 +270,7 @@
|
|||
|
||||
<fieldset>
|
||||
<label>Password</label>
|
||||
<input required name="DB_PASS" size="20" type="password" value="<?php echo $DB_PASS ?>"/>
|
||||
<input name="DB_PASS" size="20" type="password" value="<?php echo $DB_PASS ?>"/>
|
||||
</fieldset>
|
||||
|
||||
<fieldset>
|
||||
|
|
|
@ -58,12 +58,12 @@ dojo.declare("fox.FeedStoreModel", dijit.tree.ForestStoreModel, {
|
|||
|
||||
if (is_cat) {
|
||||
treeItem = this.store._itemsByIdentity['CAT:' + feed];
|
||||
items = this.store._arrayOfTopLevelItems;
|
||||
} else {
|
||||
treeItem = this.store._itemsByIdentity['FEED:' + feed];
|
||||
items = this.store._arrayOfAllItems;
|
||||
}
|
||||
|
||||
items = this.store._arrayOfAllItems;
|
||||
|
||||
for (var i = 0; i < items.length; i++) {
|
||||
if (items[i] == treeItem) {
|
||||
|
||||
|
@ -71,14 +71,18 @@ dojo.declare("fox.FeedStoreModel", dijit.tree.ForestStoreModel, {
|
|||
var unread = this.store.getValue(items[j], 'unread');
|
||||
var id = this.store.getValue(items[j], 'id');
|
||||
|
||||
if (unread > 0 && (is_cat || id.match("FEED:"))) return items[j];
|
||||
if (unread > 0 && ((is_cat && id.match("CAT:")) || (!is_cat && id.match("FEED:")))) {
|
||||
if( !is_cat || ! (this.store.hasAttribute(items[j], 'parent_id') && this.store.getValue(items[j], 'parent_id') == feed) ) return items[j];
|
||||
}
|
||||
}
|
||||
|
||||
for (var j = 0; j < i; j++) {
|
||||
var unread = this.store.getValue(items[j], 'unread');
|
||||
var id = this.store.getValue(items[j], 'id');
|
||||
|
||||
if (unread > 0 && (is_cat || id.match("FEED:"))) return items[j];
|
||||
if (unread > 0 && ((is_cat && id.match("CAT:")) || (!is_cat && id.match("FEED:")))) {
|
||||
if( !is_cat || ! (this.store.hasAttribute(items[j], 'parent_id') && this.store.getValue(items[j], 'parent_id') == feed) ) return items[j];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -539,7 +543,7 @@ dojo.declare("fox.FeedTree", dijit.Tree, {
|
|||
}
|
||||
|
||||
items = this.model.store._arrayOfAllItems;
|
||||
var item = items[0];
|
||||
var item = items[0] == treeItem ? items[items.length-1] : items[0];
|
||||
|
||||
for (var i = 0; i < items.length; i++) {
|
||||
if (items[i] == treeItem) {
|
||||
|
|
|
@ -24,6 +24,7 @@ dojo.declare("fox.PrefFilterTree", lib.CheckBoxTree, {
|
|||
|
||||
var enabled = this.model.store.getValue(args.item, 'enabled');
|
||||
var param = this.model.store.getValue(args.item, 'param');
|
||||
var rules = this.model.store.getValue(args.item, 'rules');
|
||||
|
||||
if (param) {
|
||||
param = dojo.doc.createElement('span');
|
||||
|
@ -32,6 +33,13 @@ dojo.declare("fox.PrefFilterTree", lib.CheckBoxTree, {
|
|||
dojo.place(param, tnode.rowNode, 'first');
|
||||
}
|
||||
|
||||
if (rules) {
|
||||
param = dojo.doc.createElement('span');
|
||||
param.className = 'filterRules';
|
||||
param.innerHTML = rules;
|
||||
dojo.place(param, tnode.rowNode, 'next');
|
||||
}
|
||||
|
||||
if (this.model.store.getValue(args.item, 'id') != 'root') {
|
||||
var img = dojo.doc.createElement('img');
|
||||
img.src ='images/filter.png';
|
||||
|
|
|
@ -44,11 +44,8 @@ function exception_error(location, e, ext_info) {
|
|||
|
||||
try {
|
||||
|
||||
if (ext_info) {
|
||||
if (ext_info.responseText) {
|
||||
ext_info = ext_info.responseText;
|
||||
}
|
||||
}
|
||||
if (ext_info)
|
||||
ext_info = JSON.stringify(ext_info);
|
||||
|
||||
try {
|
||||
new Ajax.Request("backend.php", {
|
||||
|
@ -104,13 +101,15 @@ function exception_error(location, e, ext_info) {
|
|||
title: "Unhandled exception",
|
||||
style: "width: 600px",
|
||||
report: function() {
|
||||
if (confirm(__("Are you sure to report this exception to tt-rss.org? The report will include your browser information. Your IP would be saved in the database."))) {
|
||||
if (confirm(__("Are you sure to report this exception to tt-rss.org? The report will include information about your web browser and tt-rss configuration. Your IP will be saved in the database."))) {
|
||||
|
||||
document.forms['exceptionForm'].params.value = $H({
|
||||
browserName: navigator.appName,
|
||||
browserVersion: navigator.appVersion,
|
||||
browserPlatform: navigator.platform,
|
||||
browserCookies: navigator.cookieEnabled,
|
||||
ttrssVersion: __ttrss_version,
|
||||
initParams: JSON.stringify(init_params),
|
||||
}).toQueryString();
|
||||
|
||||
document.forms['exceptionForm'].submit();
|
||||
|
@ -205,6 +204,7 @@ function notify_real(msg, no_hide, n_type) {
|
|||
return;
|
||||
} else {
|
||||
Element.show(n);
|
||||
new Effect.Highlight(n);
|
||||
}
|
||||
|
||||
/* types:
|
||||
|
@ -829,7 +829,14 @@ function quickAddFeed() {
|
|||
onComplete: function(transport) {
|
||||
try {
|
||||
|
||||
var reply = JSON.parse(transport.responseText);
|
||||
try {
|
||||
var reply = JSON.parse(transport.responseText);
|
||||
} catch (e) {
|
||||
Element.hide("feed_add_spinner");
|
||||
alert(__("Failed to parse output. This can indicate server timeout and/or network issues. Backend output was logged to browser console."));
|
||||
console.log('quickAddFeed, backend returned:' + transport.responseText);
|
||||
return;
|
||||
}
|
||||
|
||||
var rc = reply['result'];
|
||||
|
||||
|
@ -854,6 +861,8 @@ function quickAddFeed() {
|
|||
case 4:
|
||||
feeds = rc['feeds'];
|
||||
|
||||
Element.show("fadd_multiple_notify");
|
||||
|
||||
var select = dijit.byId("feedDlg_feedContainerSelect");
|
||||
|
||||
while (select.getOptions().length > 0)
|
||||
|
@ -1148,33 +1157,48 @@ function quickAddFilter() {
|
|||
href: query});
|
||||
|
||||
if (!inPreferences()) {
|
||||
var selectedText = getSelectionText();
|
||||
|
||||
var lh = dojo.connect(dialog, "onLoad", function(){
|
||||
dojo.disconnect(lh);
|
||||
|
||||
var query = "op=rpc&method=getlinktitlebyid&id=" + getActiveArticleId();
|
||||
if (selectedText != "") {
|
||||
|
||||
new Ajax.Request("backend.php", {
|
||||
parameters: query,
|
||||
onComplete: function(transport) {
|
||||
var reply = JSON.parse(transport.responseText);
|
||||
var feed_id = activeFeedIsCat() ? 'CAT:' + parseInt(getActiveFeedId()) :
|
||||
getActiveFeedId();
|
||||
|
||||
var title = false;
|
||||
var rule = { reg_exp: selectedText, feed_id: feed_id, filter_type: 1 };
|
||||
|
||||
if (reply && reply) title = reply.title;
|
||||
addFilterRule(null, dojo.toJson(rule));
|
||||
|
||||
if (title || getActiveFeedId() || activeFeedIsCat()) {
|
||||
} else {
|
||||
|
||||
console.log(title + " " + getActiveFeedId());
|
||||
var query = "op=rpc&method=getlinktitlebyid&id=" + getActiveArticleId();
|
||||
|
||||
var feed_id = activeFeedIsCat() ? 'CAT:' + parseInt(getActiveFeedId()) :
|
||||
getActiveFeedId();
|
||||
new Ajax.Request("backend.php", {
|
||||
parameters: query,
|
||||
onComplete: function(transport) {
|
||||
var reply = JSON.parse(transport.responseText);
|
||||
|
||||
var rule = { reg_exp: title, feed_id: feed_id, filter_type: 1 };
|
||||
var title = false;
|
||||
|
||||
addFilterRule(null, dojo.toJson(rule));
|
||||
}
|
||||
if (reply && reply) title = reply.title;
|
||||
|
||||
} });
|
||||
if (title || getActiveFeedId() || activeFeedIsCat()) {
|
||||
|
||||
console.log(title + " " + getActiveFeedId());
|
||||
|
||||
var feed_id = activeFeedIsCat() ? 'CAT:' + parseInt(getActiveFeedId()) :
|
||||
getActiveFeedId();
|
||||
|
||||
var rule = { reg_exp: title, feed_id: feed_id, filter_type: 1 };
|
||||
|
||||
addFilterRule(null, dojo.toJson(rule));
|
||||
}
|
||||
|
||||
} });
|
||||
|
||||
}
|
||||
|
||||
});
|
||||
}
|
||||
|
@ -1270,10 +1294,8 @@ function backend_sanity_check_callback(transport) {
|
|||
console.log('reading init-params...');
|
||||
|
||||
for (k in params) {
|
||||
var v = params[k];
|
||||
console.log("IP: " + k + " => " + v);
|
||||
|
||||
if (k == "label_base_index") _label_base_index = parseInt(v);
|
||||
console.log("IP: " + k + " => " + JSON.stringify(params[k]));
|
||||
if (k == "label_base_index") _label_base_index = parseInt(params[k]);
|
||||
}
|
||||
|
||||
init_params = params;
|
||||
|
@ -1934,3 +1956,25 @@ function feed_to_label_id(feed) {
|
|||
return _label_base_index - 1 + Math.abs(feed);
|
||||
}
|
||||
|
||||
// http://stackoverflow.com/questions/6251937/how-to-get-selecteduser-highlighted-text-in-contenteditable-element-and-replac
|
||||
|
||||
function getSelectionText() {
|
||||
var text = "";
|
||||
|
||||
if (typeof window.getSelection != "undefined") {
|
||||
var sel = window.getSelection();
|
||||
if (sel.rangeCount) {
|
||||
var container = document.createElement("div");
|
||||
for (var i = 0, len = sel.rangeCount; i < len; ++i) {
|
||||
container.appendChild(sel.getRangeAt(i).cloneContents());
|
||||
}
|
||||
text = container.innerHTML;
|
||||
}
|
||||
} else if (typeof document.selection != "undefined") {
|
||||
if (document.selection.type == "Text") {
|
||||
text = document.selection.createRange().textText;
|
||||
}
|
||||
}
|
||||
|
||||
return text.stripTags();
|
||||
}
|
||||
|
|
|
@ -231,6 +231,7 @@ function init() {
|
|||
dojo.require("dijit.form.Select");
|
||||
dojo.require("dijit.form.SimpleTextarea");
|
||||
dojo.require("dijit.form.TextBox");
|
||||
dojo.require("dijit.form.ComboBox");
|
||||
dojo.require("dijit.form.ValidationTextBox");
|
||||
dojo.require("dijit.InlineEditBox");
|
||||
dojo.require("dijit.layout.AccordionContainer");
|
||||
|
@ -500,6 +501,10 @@ function init() {
|
|||
if (!isCdmMode()) {
|
||||
_widescreen_mode = !_widescreen_mode;
|
||||
|
||||
// reset stored sizes because geometry changed
|
||||
setCookie("ttrss_ci_width", 0);
|
||||
setCookie("ttrss_ci_height", 0);
|
||||
|
||||
switchPanelMode(_widescreen_mode);
|
||||
}
|
||||
};
|
||||
|
@ -550,25 +555,11 @@ function init_second_stage() {
|
|||
updateFeedList();
|
||||
closeArticlePanel();
|
||||
|
||||
_widescreen_mode = getInitParam("widescreen");
|
||||
switchPanelMode(_widescreen_mode);
|
||||
|
||||
if (parseInt(getCookie("ttrss_fh_width")) > 0) {
|
||||
dijit.byId("feeds-holder").domNode.setStyle(
|
||||
{width: getCookie("ttrss_fh_width") + "px" });
|
||||
}
|
||||
|
||||
if (parseInt(getCookie("ttrss_ci_width")) > 0) {
|
||||
if (_widescreen_mode) {
|
||||
dijit.byId("content-insert").domNode.setStyle(
|
||||
{width: getCookie("ttrss_ci_width") + "px" });
|
||||
|
||||
} else {
|
||||
dijit.byId("content-insert").domNode.setStyle(
|
||||
{height: getCookie("ttrss_ci_height") + "px" });
|
||||
}
|
||||
}
|
||||
|
||||
dijit.byId("main").resize();
|
||||
|
||||
var tmph = dojo.connect(dijit.byId('feeds-holder'), 'resize',
|
||||
|
@ -624,6 +615,9 @@ function init_second_stage() {
|
|||
hotkeys[1] = tmp;
|
||||
setInitParam("hotkeys", hotkeys);
|
||||
|
||||
_widescreen_mode = getInitParam("widescreen");
|
||||
switchPanelMode(_widescreen_mode);
|
||||
|
||||
console.log("second stage ok");
|
||||
|
||||
if (getInitParam("simple_update")) {
|
||||
|
@ -706,6 +700,10 @@ function quickMenuGo(opid) {
|
|||
if (!isCdmMode()) {
|
||||
_widescreen_mode = !_widescreen_mode;
|
||||
|
||||
// reset stored sizes because geometry changed
|
||||
setCookie("ttrss_ci_width", 0);
|
||||
setCookie("ttrss_ci_height", 0);
|
||||
|
||||
switchPanelMode(_widescreen_mode);
|
||||
}
|
||||
break;
|
||||
|
@ -989,6 +987,12 @@ function handle_rpc_json(transport, scheduled_call) {
|
|||
try {
|
||||
var reply = JSON.parse(transport.responseText);
|
||||
|
||||
var netalert_dijit = dijit.byId("net-alert");
|
||||
var netalert = false;
|
||||
|
||||
if (netalert_dijit)
|
||||
netalert = netalert_dijit.domNode;
|
||||
|
||||
if (reply) {
|
||||
|
||||
var error = reply['error'];
|
||||
|
@ -1035,16 +1039,21 @@ function handle_rpc_json(transport, scheduled_call) {
|
|||
if (runtime_info)
|
||||
parse_runtime_info(runtime_info);
|
||||
|
||||
Element.hide(dijit.byId("net-alert").domNode);
|
||||
if (netalert) Element.hide(netalert);
|
||||
|
||||
} else {
|
||||
//notify_error("Error communicating with server.");
|
||||
Element.show(dijit.byId("net-alert").domNode);
|
||||
if (netalert)
|
||||
Element.show(netalert);
|
||||
else
|
||||
notify_error("Communication problem with server.");
|
||||
}
|
||||
|
||||
} catch (e) {
|
||||
Element.show(dijit.byId("net-alert").domNode);
|
||||
//notify_error("Error communicating with server.");
|
||||
if (netalert)
|
||||
Element.show(netalert);
|
||||
else
|
||||
notify_error("Communication problem with server.");
|
||||
|
||||
console.log(e);
|
||||
//exception_error("handle_rpc_json", e, transport);
|
||||
}
|
||||
|
@ -1064,11 +1073,13 @@ function switchPanelMode(wide) {
|
|||
|
||||
dijit.byId("content-insert").domNode.setStyle({width: '50%',
|
||||
height: 'auto',
|
||||
borderLeftWidth: '1px',
|
||||
borderLeftColor: '#c0c0c0',
|
||||
borderTopWidth: '0px' });
|
||||
|
||||
$("headlines-toolbar").setStyle({ borderBottomWidth: '0px' });
|
||||
if (parseInt(getCookie("ttrss_ci_width")) > 0) {
|
||||
dijit.byId("content-insert").domNode.setStyle(
|
||||
{width: getCookie("ttrss_ci_width") + "px" });
|
||||
}
|
||||
|
||||
$("headlines-frame").setStyle({ borderBottomWidth: '0px' });
|
||||
$("headlines-frame").addClassName("wide");
|
||||
|
||||
|
@ -1078,10 +1089,12 @@ function switchPanelMode(wide) {
|
|||
|
||||
dijit.byId("content-insert").domNode.setStyle({width: 'auto',
|
||||
height: '50%',
|
||||
borderLeftWidth: '0px',
|
||||
borderTopWidth: '1px'});
|
||||
borderTopWidth: '0px'});
|
||||
|
||||
$("headlines-toolbar").setStyle({ borderBottomWidth: '1px' });
|
||||
if (parseInt(getCookie("ttrss_ci_height")) > 0) {
|
||||
dijit.byId("content-insert").domNode.setStyle(
|
||||
{height: getCookie("ttrss_ci_height") + "px" });
|
||||
}
|
||||
|
||||
$("headlines-frame").setStyle({ borderBottomWidth: '1px' });
|
||||
$("headlines-frame").removeClassName("wide");
|
||||
|
|
|
@ -87,8 +87,12 @@ function headlines_callback2(transport, offset, background, infscroll_req) {
|
|||
dijit.byId("headlines-frame").attr('content',
|
||||
reply['headlines']['content']);
|
||||
|
||||
dijit.byId("headlines-toolbar").attr('content',
|
||||
reply['headlines']['toolbar']);
|
||||
//dijit.byId("headlines-toolbar").attr('content',
|
||||
// reply['headlines']['toolbar']);
|
||||
|
||||
dojo.html.set($("headlines-toolbar"),
|
||||
reply['headlines']['toolbar'],
|
||||
{parseContent: true});
|
||||
|
||||
$$("#headlines-frame > div[id*=RROW]").each(function(row) {
|
||||
if (loaded_article_ids.indexOf(row.id) != -1) {
|
||||
|
@ -104,6 +108,10 @@ function headlines_callback2(transport, offset, background, infscroll_req) {
|
|||
|
||||
initHeadlinesMenu();
|
||||
|
||||
if (_infscroll_disable)
|
||||
hsp.innerHTML = "<a href='#' onclick='openNextUnreadFeed()'>" +
|
||||
__("Click to open next unread feed.") + "</a>";
|
||||
|
||||
if (_search_query) {
|
||||
$("feed_title").innerHTML += "<span id='cancel_search'>" +
|
||||
" (<a href='#' onclick='cancelSearch()'>" + __("Cancel search") + "</a>)" +
|
||||
|
@ -143,9 +151,9 @@ function headlines_callback2(transport, offset, background, infscroll_req) {
|
|||
|
||||
if (!hsp) hsp = new Element("DIV", {"id": "headlines-spacer"});
|
||||
|
||||
if (getInitParam("cdm_auto_catchup") == 1) {
|
||||
// if (getInitParam("cdm_auto_catchup") == 1) {
|
||||
c.domNode.appendChild(hsp);
|
||||
}
|
||||
// }
|
||||
|
||||
console.log("added " + new_elems.size() + " headlines");
|
||||
|
||||
|
@ -172,7 +180,8 @@ function headlines_callback2(transport, offset, background, infscroll_req) {
|
|||
|
||||
var hsp = $("headlines-spacer");
|
||||
|
||||
if (hsp) hsp.innerHTML = "";
|
||||
if (hsp) hsp.innerHTML = "<a href='#' onclick='openNextUnreadFeed()'>" +
|
||||
__("Click to open next unread feed.") + "</a>";
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -190,14 +199,11 @@ function headlines_callback2(transport, offset, background, infscroll_req) {
|
|||
else
|
||||
request_counters(true);
|
||||
|
||||
} else if (transport.responseText) {
|
||||
} else {
|
||||
console.error("Invalid object received: " + transport.responseText);
|
||||
dijit.byId("headlines-frame").attr('content', "<div class='whiteBox'>" +
|
||||
__('Could not update headlines (invalid object received - see error console for details)') +
|
||||
"</div>");
|
||||
} else {
|
||||
//notify_error("Error communicating with server.");
|
||||
Element.show(dijit.byId("net-alert").domNode);
|
||||
}
|
||||
|
||||
_infscroll_request_sent = 0;
|
||||
|
@ -314,13 +320,11 @@ function article_callback2(transport, id) {
|
|||
// return;
|
||||
// }
|
||||
|
||||
} else if (transport.responseText) {
|
||||
} else {
|
||||
console.error("Invalid object received: " + transport.responseText);
|
||||
|
||||
render_article("<div class='whiteBox'>" +
|
||||
__('Could not display article (invalid object received - see error console for details)') + "</div>");
|
||||
} else {
|
||||
Element.show(dijit.byId("net-alert").domNode);
|
||||
}
|
||||
|
||||
var unread_in_buffer = $$("#headlines-frame > div[id*=RROW][class*=Unread]").length
|
||||
|
@ -961,10 +965,12 @@ function getLoadedArticleIds() {
|
|||
}
|
||||
|
||||
// mode = all,none,unread,invert,marked,published
|
||||
function selectArticles(mode) {
|
||||
function selectArticles(mode, query) {
|
||||
try {
|
||||
|
||||
var children = $$("#headlines-frame > div[id*=RROW]");
|
||||
if (!query) query = "#headlines-frame > div[id*=RROW]";
|
||||
|
||||
var children = $$(query);
|
||||
|
||||
children.each(function(child) {
|
||||
var id = child.id.replace("RROW-", "");
|
||||
|
@ -1243,7 +1249,7 @@ function postMouseOut(id) {
|
|||
|
||||
function unpackVisibleHeadlines() {
|
||||
try {
|
||||
if (!isCdmMode()) return;
|
||||
if (!isCdmMode() || !getInitParam("cdm_expanded")) return;
|
||||
|
||||
$$("#headlines-frame > div[id*=RROW]").each(
|
||||
function(child) {
|
||||
|
@ -1306,15 +1312,20 @@ function headlines_scroll_handler(e) {
|
|||
((e.scrollTop + e.offsetHeight) / e.scrollHeight >= 0.7))) {
|
||||
|
||||
if (hsp)
|
||||
hsp.innerHTML = "<img src='images/indicator_tiny.gif'> " +
|
||||
__("Loading, please wait...");
|
||||
hsp.innerHTML = "<span class='loading'><img src='images/indicator_tiny.gif'> " +
|
||||
__("Loading, please wait...") + "</span>";
|
||||
|
||||
loadMoreHeadlines();
|
||||
return;
|
||||
|
||||
}
|
||||
} else {
|
||||
if (hsp) hsp.innerHTML = "";
|
||||
if (hsp)
|
||||
if (_infscroll_disable)
|
||||
hsp.innerHTML = "<a href='#' onclick='openNextUnreadFeed()'>" +
|
||||
__("Click to open next unread feed.") + "</a>";
|
||||
else
|
||||
hsp.innerHTML = "";
|
||||
}
|
||||
|
||||
if (isCdmMode()) {
|
||||
|
@ -1350,6 +1361,20 @@ function headlines_scroll_handler(e) {
|
|||
500);
|
||||
}
|
||||
}
|
||||
|
||||
if (_infscroll_disable) {
|
||||
var child = $$("#headlines-frame div[id*=RROW]").last();
|
||||
|
||||
if (child && $("headlines-frame").scrollTop >
|
||||
(child.offsetTop + child.offsetHeight - 50)) {
|
||||
|
||||
console.log("we seem to be at an end");
|
||||
|
||||
if (getInitParam("on_catchup_show_next_feed") == "1") {
|
||||
openNextUnreadFeed();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} catch (e) {
|
||||
|
@ -1357,6 +1382,16 @@ function headlines_scroll_handler(e) {
|
|||
}
|
||||
}
|
||||
|
||||
function openNextUnreadFeed() {
|
||||
try {
|
||||
var is_cat = activeFeedIsCat();
|
||||
var nuf = getNextUnreadFeed(getActiveFeedId(), is_cat);
|
||||
if (nuf) viewfeed(nuf, '', is_cat);
|
||||
} catch (e) {
|
||||
exception_error("openNextUnreadFeed", e);
|
||||
}
|
||||
}
|
||||
|
||||
function catchupBatchedArticles() {
|
||||
try {
|
||||
if (catchup_id_batch.length > 0 && !_infscroll_request_sent) {
|
||||
|
@ -1761,7 +1796,8 @@ function cdmClicked(event, id) {
|
|||
return !event.shiftKey;
|
||||
}
|
||||
|
||||
} else {
|
||||
} else if (event.target.parents(".cdmHeader").length > 0) {
|
||||
|
||||
toggleSelected(id, true);
|
||||
|
||||
var elem = $("RROW-" + id);
|
||||
|
@ -2107,6 +2143,72 @@ function initHeadlinesMenu() {
|
|||
|
||||
menu.startup();
|
||||
|
||||
/* vgroup feed title menu */
|
||||
|
||||
var nodes = $$("#headlines-frame > div[class='cdmFeedTitle']");
|
||||
var ids = [];
|
||||
|
||||
nodes.each(function(node) {
|
||||
ids.push(node.id);
|
||||
});
|
||||
|
||||
if (ids.length > 0) {
|
||||
if (dijit.byId("headlinesFeedTitleMenu"))
|
||||
dijit.byId("headlinesFeedTitleMenu").destroyRecursive();
|
||||
|
||||
var menu = new dijit.Menu({
|
||||
id: "headlinesFeedTitleMenu",
|
||||
targetNodeIds: ids,
|
||||
});
|
||||
|
||||
var tmph = dojo.connect(menu, '_openMyself', function (event) {
|
||||
var callerNode = event.target, match = null, tries = 0;
|
||||
|
||||
while (match == null && callerNode && tries <= 3) {
|
||||
console.log(callerNode.id);
|
||||
|
||||
match = callerNode.id.match("^[A-Z]+[-]([0-9]+)$");
|
||||
callerNode = callerNode.parentNode;
|
||||
++tries;
|
||||
|
||||
console.log(match[1]);
|
||||
}
|
||||
|
||||
if (match) this.callerRowId = parseInt(match[1]);
|
||||
|
||||
});
|
||||
|
||||
menu.addChild(new dijit.MenuItem({
|
||||
label: __("Select articles in group"),
|
||||
onClick: function(event) {
|
||||
selectArticles("all",
|
||||
"#headlines-frame > div[id*=RROW]"+
|
||||
"[orig-feed-id='"+menu.callerRowId+"']");
|
||||
|
||||
}}));
|
||||
|
||||
menu.addChild(new dijit.MenuItem({
|
||||
label: __("Mark group as read"),
|
||||
onClick: function(event) {
|
||||
selectArticles("none");
|
||||
selectArticles("all",
|
||||
"#headlines-frame > div[id*=RROW]"+
|
||||
"[orig-feed-id='"+menu.callerRowId+"']");
|
||||
|
||||
catchupSelection();
|
||||
}}));
|
||||
|
||||
|
||||
menu.addChild(new dijit.MenuItem({
|
||||
label: __("Mark feed as read"),
|
||||
onClick: function(event) {
|
||||
catchupFeedInGroup(menu.callerRowId);
|
||||
}}));
|
||||
|
||||
menu.startup();
|
||||
|
||||
}
|
||||
|
||||
} catch (e) {
|
||||
exception_error("initHeadlinesMenu", e);
|
||||
}
|
||||
|
|
|
@ -1,220 +1,220 @@
|
|||
<?php
|
||||
/**
|
||||
* Mobile Detect
|
||||
* $Id: Mobile_Detect.php 44 2012-05-03 21:45:00Z serbanghita@gmail.com $
|
||||
*
|
||||
* @usage require_once 'Mobile_Detect.php';
|
||||
* $detect = new Mobile_Detect();
|
||||
* $detect->isMobile() or $detect->isTablet()
|
||||
*
|
||||
* For more specific usage see the documentation navigate to:
|
||||
* http://code.google.com/p/php-mobile-detect/wiki/Mobile_Detect
|
||||
*
|
||||
* @license http://www.opensource.org/licenses/mit-license.php The MIT License
|
||||
*/
|
||||
|
||||
class Mobile_Detect {
|
||||
|
||||
protected $detectionRules;
|
||||
protected $userAgent = null;
|
||||
protected $accept = null;
|
||||
// Assume the visitor has a desktop environment.
|
||||
protected $isMobile = false;
|
||||
protected $isTablet = false;
|
||||
protected $phoneDeviceName = null;
|
||||
protected $tabletDevicename = null;
|
||||
protected $operatingSystemName = null;
|
||||
protected $userAgentName = null;
|
||||
// List of mobile devices (phones)
|
||||
protected $phoneDevices = array(
|
||||
'iPhone' => '(iPhone.*Mobile|iPod|iTunes)',
|
||||
'BlackBerry' => 'BlackBerry|rim[0-9]+',
|
||||
'HTC' => 'HTC|HTC.*(6800|8100|8900|A7272|S510e|C110e|Legend|Desire|T8282)|APX515CKT|Qtek9090',
|
||||
'Nexus' => 'Nexus One|Nexus S',
|
||||
'DellStreak' => 'Dell Streak',
|
||||
'Motorola' => '\bDroid\b.*Build|HRI39|MOT\-|A1260|A1680|A555|A853|A855|A953|A955|A956|Motorola.*ELECTRIFY|Motorola.*i1|i867|i940|MB200|MB300|MB501|MB502|MB508|MB511|MB520|MB525|MB526|MB611|MB612|MB632|MB810|MB855|MB860|MB861|MB865|MB870|ME501|ME502|ME511|ME525|ME600|ME632|ME722|ME811|ME860|ME863|ME865|MT620|MT710|MT716|MT720|MT810|MT870|MT917|Motorola.*TITANIUM|WX435|WX445|XT300|XT301|XT311|XT316|XT317|XT319|XT320|XT390|XT502|XT530|XT531|XT532|XT535|XT603|XT610|XT611|XT615|XT681|XT701|XT702|XT711|XT720|XT800|XT806|XT860|XT862|XT875|XT882|XT883|XT894|XT909|XT910|XT912|XT928',
|
||||
'Samsung' => 'Samsung|GT-I9100|GT-I9000|GT-I9020|SCH-A310|SCH-A530|SCH-A570|SCH-A610|SCH-A630|SCH-A650|SCH-A790|SCH-A795|SCH-A850|SCH-A870|SCH-A890|SCH-A930|SCH-A950|SCH-A970|SCH-A990|SCH-I100|SCH-I110|SCH-I400|SCH-I405|SCH-I500|SCH-I510|SCH-I515|SCH-I600|SCH-I730|SCH-I760|SCH-I770|SCH-I830|SCH-I910|SCH-I920|SCH-LC11|SCH-N150|SCH-N300|SCH-R300|SCH-R400|SCH-R410|SCH-T300|SCH-U310|SCH-U320|SCH-U350|SCH-U360|SCH-U365|SCH-U370|SCH-U380|SCH-U410|SCH-U430|SCH-U450|SCH-U460|SCH-U470|SCH-U490|SCH-U540|SCH-U550|SCH-U620|SCH-U640|SCH-U650|SCH-U660|SCH-U700|SCH-U740|SCH-U750|SCH-U810|SCH-U820|SCH-U900|SCH-U940|SCH-U960|SCS-26UC|SGH-A107|SGH-A117|SGH-A127|SGH-A137|SGH-A157|SGH-A167|SGH-A177|SGH-A187|SGH-A197|SGH-A227|SGH-A237|SGH-A257|SGH-A437|SGH-A517|SGH-A597|SGH-A637|SGH-A657|SGH-A667|SGH-A687|SGH-A697|SGH-A697|SGH-A707|SGH-A717|SGH-A727|SGH-A737|SGH-A747|SGH-A767|SGH-A777|SGH-A797|SGH-A817|SGH-A827|SGH-A837|SGH-A847|SGH-A867|SGH-A877|SGH-A887|SGH-A897|SGH-A927|SGH-C207|SGH-C225|SGH-C417|SGH-D307|SGH-D347|SGH-D357|SGH-D407|SGH-D415|SGH-D807|SGH-E105|SGH-E315|SGH-E316|SGH-E317|SGH-E335|SGH-E635|SGH-E715|SGH-I577|SGH-I607|SGH-I617|SGH-I627|SGH-I637|SGH-I677|SGH-I717|SGH-I727|SGH-I777|SGH-I827|SGH-I847|SGH-I857|SGH-I896|SGH-I897|SGH-I907|SGH-I917|SGH-I927|SGH-I937|SGH-I997|SGH-N105|SGH-N625|SGH-P107|SGH-P207|SGH-P735|SGH-P777|SGH-Q105|SGH-R225|SGH-S105|SGH-S307|SGH-T109|SGH-T119|SGH-T139|SGH-T209|SGH-T219|SGH-T229|SGH-T239|SGH-T249|SGH-T259|SGH-T309|SGH-T319|SGH-T329|SGH-T339|SGH-T349|SGH-T359|SGH-T369|SGH-T379|SGH-T409|SGH-T429|SGH-T439|SGH-T459|SGH-T469|SGH-T479|SGH-T499|SGH-T509|SGH-T519|SGH-T539|SGH-T559|SGH-T589|SGH-T609|SGH-T619|SGH-T629|SGH-T639|SGH-T659|SGH-T669|SGH-T679|SGH-T709|SGH-T719|SGH-T729|SGH-T739|SGH-T749|SGH-T759|SGH-T769|SGH-T809|SGH-T819|SGH-T839|SGH-T919|SGH-T919|SGH-T929|SGH-T939|SGH-T939|SGH-T959|SGH-T989|SGH-V205|SGH-V206|SGH-X105|SGH-X426|SGH-X427|SGH-X475|SGH-X495|SGH-X497|SGH-X507|SGH-ZX10|SGH-ZX20|SPH-A120|SPH-A400|SPH-A420|SPH-A460|SPH-A500I|SPH-A560|SPH-A600|SPH-A620|SPH-A660|SPH-A700|SPH-A740|SPH-A760|SPH-A790|SPH-A800|SPH-A820|SPH-A840|SPH-A880|SPH-A900|SPH-A940|SPH-A960|SPH-D600|SPH-D700|SPH-D710|SPH-D720|SPH-I300|SPH-I325|SPH-I330|SPH-I350|SPH-I500|SPH-I600|SPH-I700|SPH-L700|SPH-M100|SPH-M220|SPH-M240|SPH-M300|SPH-M305|SPH-M320|SPH-M330|SPH-M350|SPH-M360|SPH-M370|SPH-M380|SPH-M510|SPH-M540|SPH-M550|SPH-M560|SPH-M570|SPH-M580|SPH-M610|SPH-M620|SPH-M630|SPH-M800|SPH-M810|SPH-M850|SPH-M900|SPH-M910|SPH-M920|SPH-M930|SPH-N200|SPH-N240|SPH-N300|SPH-N400|SPH-Z400|SWC-E100',
|
||||
'Sony' => 'E10i|SonyEricsson|SonyEricssonLT15iv',
|
||||
'Asus' => 'Asus.*Galaxy',
|
||||
'Palm' => 'PalmSource|Palm', // avantgo|blazer|elaine|hiptop|plucker|xiino
|
||||
'GenericPhone' => '(mmp|pocket|psp|symbian|Smartphone|smartfon|treo|up.browser|up.link|vodafone|wap|nokia|Series40|Series60|S60|SonyEricsson|N900|PPC;|MAUI.*WAP.*Browser|LG-P500)'
|
||||
);
|
||||
// List of tablet devices.
|
||||
protected $tabletDevices = array(
|
||||
'BlackBerryTablet' => 'PlayBook|RIM Tablet',
|
||||
'iPad' => 'iPad|iPad.*Mobile', // @todo: check for mobile friendly emails topic.
|
||||
'Kindle' => 'Kindle|Silk.*Accelerated',
|
||||
'SamsungTablet' => 'SAMSUNG.*Tablet|Galaxy.*Tab|GT-P1000|GT-P1010|GT-P6210|GT-P6800|GT-P6810|GT-P7100|GT-P7300|GT-P7310|GT-P7500|GT-P7510|SCH-I800|SCH-I815|SCH-I905|SGH-I777|SGH-I957|SGH-I987|SGH-T849|SGH-T859|SGH-T869|SGH-T989|SPH-D710|SPH-P100',
|
||||
'HTCtablet' => 'HTC Flyer|HTC Jetstream|HTC-P715a|HTC EVO View 4G|PG41200',
|
||||
'MotorolaTablet' => 'xoom|sholest|MZ615|MZ605|MZ505|MZ601|MZ602|MZ603|MZ604|MZ606|MZ607|MZ608|MZ609|MZ615|MZ616|MZ617',
|
||||
'AsusTablet' => 'Transformer|TF101',
|
||||
'NookTablet' => 'NookColor|nook browser|BNTV250A|LogicPD Zoom2',
|
||||
'AcerTablet' => 'Android.*(A100|A101|A200|A500|A501|A510|W500|W500P|W501|W501P)',
|
||||
'YarvikTablet' => 'Android.*(TAB210|TAB211|TAB224|TAB250|TAB260|TAB264|TAB310|TAB360|TAB364|TAB410|TAB411|TAB420|TAB424|TAB450|TAB460|TAB461|TAB464|TAB465|TAB467|TAB468)',
|
||||
'GenericTablet' => 'Tablet(?!.*PC)|ViewPad7|LG-V909|MID7015|BNTV250A|LogicPD Zoom2|\bA7EB\b|CatNova8|A1_07|CT704|CT1002|\bM721\b',
|
||||
);
|
||||
// List of mobile Operating Systems.
|
||||
protected $operatingSystems = array(
|
||||
'AndroidOS' => '(android.*mobile|android(?!.*mobile))',
|
||||
'BlackBerryOS' => '(blackberry|rim tablet os)',
|
||||
'PalmOS' => '(avantgo|blazer|elaine|hiptop|palm|plucker|xiino)',
|
||||
'SymbianOS' => 'Symbian|SymbOS|Series60|Series40|\bS60\b',
|
||||
'WindowsMobileOS' => 'IEMobile|Windows Phone|Windows CE.*(PPC|Smartphone)|MSIEMobile|Window Mobile|XBLWP7',
|
||||
'iOS' => '(iphone|ipod|ipad)',
|
||||
'FlashLiteOS' => '',
|
||||
'JavaOS' => '',
|
||||
'NokiaOS' => '',
|
||||
'webOS' => '',
|
||||
'badaOS' => '\bBada\b',
|
||||
'BREWOS' => '',
|
||||
);
|
||||
// List of mobile User Agents.
|
||||
protected $userAgents = array(
|
||||
'Chrome' => '\bCrMo\b|Chrome\/[.0-9]* Mobile',
|
||||
'Dolfin' => '\bDolfin\b',
|
||||
'Opera' => 'Opera.*Mini|Opera.*Mobi',
|
||||
'Skyfire' => 'skyfire',
|
||||
'IE' => 'IEMobile',
|
||||
'Firefox' => 'fennec|firefox.*maemo|(Mobile|Tablet).*Firefox|Firefox.*Mobile',
|
||||
'Bolt' => 'bolt',
|
||||
'TeaShark' => 'teashark',
|
||||
'Blazer' => 'Blazer',
|
||||
'Safari' => 'Mobile.*Safari|Safari.*Mobile',
|
||||
'Midori' => 'midori',
|
||||
'GenericBrowser' => 'NokiaBrowser|OviBrowser|SEMC.*Browser'
|
||||
);
|
||||
|
||||
function __construct(){
|
||||
|
||||
// Merge all rules together.
|
||||
$this->detectionRules = array_merge(
|
||||
$this->phoneDevices,
|
||||
$this->tabletDevices,
|
||||
$this->operatingSystems,
|
||||
$this->userAgents
|
||||
);
|
||||
$this->userAgent = $_SERVER['HTTP_USER_AGENT'];
|
||||
$this->accept = $_SERVER['HTTP_ACCEPT'];
|
||||
|
||||
if (
|
||||
isset($_SERVER['HTTP_X_WAP_PROFILE']) ||
|
||||
isset($_SERVER['HTTP_X_WAP_CLIENTID']) ||
|
||||
isset($_SERVER['HTTP_WAP_CONNECTION']) ||
|
||||
isset($_SERVER['HTTP_PROFILE']) ||
|
||||
isset($_SERVER['HTTP_X_OPERAMINI_PHONE_UA']) || // Reported by Nokia devices (eg. C3)
|
||||
isset($_SERVER['HTTP_X_NOKIA_IPADDRESS']) ||
|
||||
isset($_SERVER['HTTP_X_NOKIA_GATEWAY_ID']) ||
|
||||
isset($_SERVER['HTTP_X_ORANGE_ID']) ||
|
||||
isset($_SERVER['HTTP_X_VODAFONE_3GPDPCONTEXT']) ||
|
||||
isset($_SERVER['HTTP_X_HUAWEI_USERID']) ||
|
||||
isset($_SERVER['HTTP_UA_OS']) || // Reported by Windows Smartphones
|
||||
(isset($_SERVER['HTTP_UA_CPU']) && $_SERVER['HTTP_UA_CPU'] == 'ARM') // Seen this on a HTC
|
||||
) {
|
||||
$this->isMobile = true;
|
||||
} elseif (!empty($this->accept) && (strpos($this->accept, 'text/vnd.wap.wml') !== false || strpos($this->accept, 'application/vnd.wap.xhtml+xml') !== false)) {
|
||||
$this->isMobile = true;
|
||||
} else {
|
||||
$this->_detect();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public function getRules()
|
||||
{
|
||||
return $this->detectionRules;
|
||||
}
|
||||
|
||||
/**
|
||||
* Magic overloading method.
|
||||
*
|
||||
* @method boolean is[...]()
|
||||
* @param string $name
|
||||
* @param array $arguments
|
||||
* @return mixed
|
||||
*/
|
||||
public function __call($name, $arguments)
|
||||
{
|
||||
|
||||
$key = substr($name, 2);
|
||||
return $this->_detect($key);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Private method that does the detection of the
|
||||
* mobile devices.
|
||||
*
|
||||
* @param type $key
|
||||
* @return boolean|null
|
||||
*/
|
||||
private function _detect($key='')
|
||||
{
|
||||
|
||||
if(empty($key)){
|
||||
|
||||
// Begin general search.
|
||||
foreach($this->detectionRules as $_regex){
|
||||
if(empty($_regex)){ continue; }
|
||||
if(preg_match('/'.$_regex.'/is', $this->userAgent)){
|
||||
$this->isMobile = true;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
|
||||
} else {
|
||||
|
||||
// Search for a certain key.
|
||||
// Make the keys lowecase so we can match: isIphone(), isiPhone(), isiphone(), etc.
|
||||
$key = strtolower($key);
|
||||
$_rules = array_change_key_case($this->detectionRules);
|
||||
|
||||
if(array_key_exists($key, $_rules)){
|
||||
if(empty($_rules[$key])){ return null; }
|
||||
if(preg_match('/'.$_rules[$key].'/is', $this->userAgent)){
|
||||
$this->isMobile = true;
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
trigger_error("Method $key is not defined", E_USER_WARNING);
|
||||
}
|
||||
|
||||
return false;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the device is mobile.
|
||||
* Returns true if any type of mobile device detected, including special ones
|
||||
* @return bool
|
||||
*/
|
||||
public function isMobile()
|
||||
{
|
||||
return $this->isMobile;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the device is a tablet.
|
||||
* Return true if any type of tablet device is detected.
|
||||
* @return boolean
|
||||
*/
|
||||
public function isTablet()
|
||||
{
|
||||
|
||||
foreach($this->tabletDevices as $_regex){
|
||||
if(preg_match('/'.$_regex.'/is', $this->userAgent)){
|
||||
$this->isTablet = true;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
|
||||
}
|
||||
|
||||
|
||||
<?php
|
||||
/**
|
||||
* Mobile Detect
|
||||
* $Id: Mobile_Detect.php 44 2012-05-03 21:45:00Z serbanghita@gmail.com $
|
||||
*
|
||||
* @usage require_once 'Mobile_Detect.php';
|
||||
* $detect = new Mobile_Detect();
|
||||
* $detect->isMobile() or $detect->isTablet()
|
||||
*
|
||||
* For more specific usage see the documentation navigate to:
|
||||
* http://code.google.com/p/php-mobile-detect/wiki/Mobile_Detect
|
||||
*
|
||||
* @license http://www.opensource.org/licenses/mit-license.php The MIT License
|
||||
*/
|
||||
|
||||
class Mobile_Detect {
|
||||
|
||||
protected $detectionRules;
|
||||
protected $userAgent = null;
|
||||
protected $accept = null;
|
||||
// Assume the visitor has a desktop environment.
|
||||
protected $isMobile = false;
|
||||
protected $isTablet = false;
|
||||
protected $phoneDeviceName = null;
|
||||
protected $tabletDevicename = null;
|
||||
protected $operatingSystemName = null;
|
||||
protected $userAgentName = null;
|
||||
// List of mobile devices (phones)
|
||||
protected $phoneDevices = array(
|
||||
'iPhone' => '(iPhone.*Mobile|iPod|iTunes)',
|
||||
'BlackBerry' => 'BlackBerry|rim[0-9]+',
|
||||
'HTC' => 'HTC|HTC.*(6800|8100|8900|A7272|S510e|C110e|Legend|Desire|T8282)|APX515CKT|Qtek9090',
|
||||
'Nexus' => 'Nexus One|Nexus S',
|
||||
'DellStreak' => 'Dell Streak',
|
||||
'Motorola' => '\bDroid\b.*Build|HRI39|MOT\-|A1260|A1680|A555|A853|A855|A953|A955|A956|Motorola.*ELECTRIFY|Motorola.*i1|i867|i940|MB200|MB300|MB501|MB502|MB508|MB511|MB520|MB525|MB526|MB611|MB612|MB632|MB810|MB855|MB860|MB861|MB865|MB870|ME501|ME502|ME511|ME525|ME600|ME632|ME722|ME811|ME860|ME863|ME865|MT620|MT710|MT716|MT720|MT810|MT870|MT917|Motorola.*TITANIUM|WX435|WX445|XT300|XT301|XT311|XT316|XT317|XT319|XT320|XT390|XT502|XT530|XT531|XT532|XT535|XT603|XT610|XT611|XT615|XT681|XT701|XT702|XT711|XT720|XT800|XT806|XT860|XT862|XT875|XT882|XT883|XT894|XT909|XT910|XT912|XT928',
|
||||
'Samsung' => 'Samsung|GT-I9100|GT-I9000|GT-I9020|SCH-A310|SCH-A530|SCH-A570|SCH-A610|SCH-A630|SCH-A650|SCH-A790|SCH-A795|SCH-A850|SCH-A870|SCH-A890|SCH-A930|SCH-A950|SCH-A970|SCH-A990|SCH-I100|SCH-I110|SCH-I400|SCH-I405|SCH-I500|SCH-I510|SCH-I515|SCH-I600|SCH-I730|SCH-I760|SCH-I770|SCH-I830|SCH-I910|SCH-I920|SCH-LC11|SCH-N150|SCH-N300|SCH-R300|SCH-R400|SCH-R410|SCH-T300|SCH-U310|SCH-U320|SCH-U350|SCH-U360|SCH-U365|SCH-U370|SCH-U380|SCH-U410|SCH-U430|SCH-U450|SCH-U460|SCH-U470|SCH-U490|SCH-U540|SCH-U550|SCH-U620|SCH-U640|SCH-U650|SCH-U660|SCH-U700|SCH-U740|SCH-U750|SCH-U810|SCH-U820|SCH-U900|SCH-U940|SCH-U960|SCS-26UC|SGH-A107|SGH-A117|SGH-A127|SGH-A137|SGH-A157|SGH-A167|SGH-A177|SGH-A187|SGH-A197|SGH-A227|SGH-A237|SGH-A257|SGH-A437|SGH-A517|SGH-A597|SGH-A637|SGH-A657|SGH-A667|SGH-A687|SGH-A697|SGH-A697|SGH-A707|SGH-A717|SGH-A727|SGH-A737|SGH-A747|SGH-A767|SGH-A777|SGH-A797|SGH-A817|SGH-A827|SGH-A837|SGH-A847|SGH-A867|SGH-A877|SGH-A887|SGH-A897|SGH-A927|SGH-C207|SGH-C225|SGH-C417|SGH-D307|SGH-D347|SGH-D357|SGH-D407|SGH-D415|SGH-D807|SGH-E105|SGH-E315|SGH-E316|SGH-E317|SGH-E335|SGH-E635|SGH-E715|SGH-I577|SGH-I607|SGH-I617|SGH-I627|SGH-I637|SGH-I677|SGH-I717|SGH-I727|SGH-I777|SGH-I827|SGH-I847|SGH-I857|SGH-I896|SGH-I897|SGH-I907|SGH-I917|SGH-I927|SGH-I937|SGH-I997|SGH-N105|SGH-N625|SGH-P107|SGH-P207|SGH-P735|SGH-P777|SGH-Q105|SGH-R225|SGH-S105|SGH-S307|SGH-T109|SGH-T119|SGH-T139|SGH-T209|SGH-T219|SGH-T229|SGH-T239|SGH-T249|SGH-T259|SGH-T309|SGH-T319|SGH-T329|SGH-T339|SGH-T349|SGH-T359|SGH-T369|SGH-T379|SGH-T409|SGH-T429|SGH-T439|SGH-T459|SGH-T469|SGH-T479|SGH-T499|SGH-T509|SGH-T519|SGH-T539|SGH-T559|SGH-T589|SGH-T609|SGH-T619|SGH-T629|SGH-T639|SGH-T659|SGH-T669|SGH-T679|SGH-T709|SGH-T719|SGH-T729|SGH-T739|SGH-T749|SGH-T759|SGH-T769|SGH-T809|SGH-T819|SGH-T839|SGH-T919|SGH-T919|SGH-T929|SGH-T939|SGH-T939|SGH-T959|SGH-T989|SGH-V205|SGH-V206|SGH-X105|SGH-X426|SGH-X427|SGH-X475|SGH-X495|SGH-X497|SGH-X507|SGH-ZX10|SGH-ZX20|SPH-A120|SPH-A400|SPH-A420|SPH-A460|SPH-A500I|SPH-A560|SPH-A600|SPH-A620|SPH-A660|SPH-A700|SPH-A740|SPH-A760|SPH-A790|SPH-A800|SPH-A820|SPH-A840|SPH-A880|SPH-A900|SPH-A940|SPH-A960|SPH-D600|SPH-D700|SPH-D710|SPH-D720|SPH-I300|SPH-I325|SPH-I330|SPH-I350|SPH-I500|SPH-I600|SPH-I700|SPH-L700|SPH-M100|SPH-M220|SPH-M240|SPH-M300|SPH-M305|SPH-M320|SPH-M330|SPH-M350|SPH-M360|SPH-M370|SPH-M380|SPH-M510|SPH-M540|SPH-M550|SPH-M560|SPH-M570|SPH-M580|SPH-M610|SPH-M620|SPH-M630|SPH-M800|SPH-M810|SPH-M850|SPH-M900|SPH-M910|SPH-M920|SPH-M930|SPH-N200|SPH-N240|SPH-N300|SPH-N400|SPH-Z400|SWC-E100',
|
||||
'Sony' => 'E10i|SonyEricsson|SonyEricssonLT15iv',
|
||||
'Asus' => 'Asus.*Galaxy',
|
||||
'Palm' => 'PalmSource|Palm', // avantgo|blazer|elaine|hiptop|plucker|xiino
|
||||
'GenericPhone' => '(mmp|pocket|psp|symbian|Smartphone|smartfon|treo|up.browser|up.link|vodafone|wap|nokia|Series40|Series60|S60|SonyEricsson|N900|PPC;|MAUI.*WAP.*Browser|LG-P500)'
|
||||
);
|
||||
// List of tablet devices.
|
||||
protected $tabletDevices = array(
|
||||
'BlackBerryTablet' => 'PlayBook|RIM Tablet',
|
||||
'iPad' => 'iPad|iPad.*Mobile', // @todo: check for mobile friendly emails topic.
|
||||
'Kindle' => 'Kindle|Silk.*Accelerated',
|
||||
'SamsungTablet' => 'SAMSUNG.*Tablet|Galaxy.*Tab|GT-P1000|GT-P1010|GT-P6210|GT-P6800|GT-P6810|GT-P7100|GT-P7300|GT-P7310|GT-P7500|GT-P7510|SCH-I800|SCH-I815|SCH-I905|SGH-I777|SGH-I957|SGH-I987|SGH-T849|SGH-T859|SGH-T869|SGH-T989|SPH-D710|SPH-P100',
|
||||
'HTCtablet' => 'HTC Flyer|HTC Jetstream|HTC-P715a|HTC EVO View 4G|PG41200',
|
||||
'MotorolaTablet' => 'xoom|sholest|MZ615|MZ605|MZ505|MZ601|MZ602|MZ603|MZ604|MZ606|MZ607|MZ608|MZ609|MZ615|MZ616|MZ617',
|
||||
'AsusTablet' => 'Transformer|TF101',
|
||||
'NookTablet' => 'NookColor|nook browser|BNTV250A|LogicPD Zoom2',
|
||||
'AcerTablet' => 'Android.*(A100|A101|A200|A500|A501|A510|W500|W500P|W501|W501P)',
|
||||
'YarvikTablet' => 'Android.*(TAB210|TAB211|TAB224|TAB250|TAB260|TAB264|TAB310|TAB360|TAB364|TAB410|TAB411|TAB420|TAB424|TAB450|TAB460|TAB461|TAB464|TAB465|TAB467|TAB468)',
|
||||
'GenericTablet' => 'Tablet(?!.*PC)|ViewPad7|LG-V909|MID7015|BNTV250A|LogicPD Zoom2|\bA7EB\b|CatNova8|A1_07|CT704|CT1002|\bM721\b',
|
||||
);
|
||||
// List of mobile Operating Systems.
|
||||
protected $operatingSystems = array(
|
||||
'AndroidOS' => '(android.*mobile|android(?!.*mobile))',
|
||||
'BlackBerryOS' => '(blackberry|rim tablet os)',
|
||||
'PalmOS' => '(avantgo|blazer|elaine|hiptop|palm|plucker|xiino)',
|
||||
'SymbianOS' => 'Symbian|SymbOS|Series60|Series40|\bS60\b',
|
||||
'WindowsMobileOS' => 'IEMobile|Windows Phone|Windows CE.*(PPC|Smartphone)|MSIEMobile|Window Mobile|XBLWP7',
|
||||
'iOS' => '(iphone|ipod|ipad)',
|
||||
'FlashLiteOS' => '',
|
||||
'JavaOS' => '',
|
||||
'NokiaOS' => '',
|
||||
'webOS' => '',
|
||||
'badaOS' => '\bBada\b',
|
||||
'BREWOS' => '',
|
||||
);
|
||||
// List of mobile User Agents.
|
||||
protected $userAgents = array(
|
||||
'Chrome' => '\bCrMo\b|Chrome\/[.0-9]* Mobile',
|
||||
'Dolfin' => '\bDolfin\b',
|
||||
'Opera' => 'Opera.*Mini|Opera.*Mobi',
|
||||
'Skyfire' => 'skyfire',
|
||||
'IE' => 'IEMobile',
|
||||
'Firefox' => 'fennec|firefox.*maemo|(Mobile|Tablet).*Firefox|Firefox.*Mobile',
|
||||
'Bolt' => 'bolt',
|
||||
'TeaShark' => 'teashark',
|
||||
'Blazer' => 'Blazer',
|
||||
'Safari' => 'Mobile.*Safari|Safari.*Mobile',
|
||||
'Midori' => 'midori',
|
||||
'GenericBrowser' => 'NokiaBrowser|OviBrowser|SEMC.*Browser'
|
||||
);
|
||||
|
||||
function __construct(){
|
||||
|
||||
// Merge all rules together.
|
||||
$this->detectionRules = array_merge(
|
||||
$this->phoneDevices,
|
||||
$this->tabletDevices,
|
||||
$this->operatingSystems,
|
||||
$this->userAgents
|
||||
);
|
||||
$this->userAgent = $_SERVER['HTTP_USER_AGENT'];
|
||||
$this->accept = $_SERVER['HTTP_ACCEPT'];
|
||||
|
||||
if (
|
||||
isset($_SERVER['HTTP_X_WAP_PROFILE']) ||
|
||||
isset($_SERVER['HTTP_X_WAP_CLIENTID']) ||
|
||||
isset($_SERVER['HTTP_WAP_CONNECTION']) ||
|
||||
isset($_SERVER['HTTP_PROFILE']) ||
|
||||
isset($_SERVER['HTTP_X_OPERAMINI_PHONE_UA']) || // Reported by Nokia devices (eg. C3)
|
||||
isset($_SERVER['HTTP_X_NOKIA_IPADDRESS']) ||
|
||||
isset($_SERVER['HTTP_X_NOKIA_GATEWAY_ID']) ||
|
||||
isset($_SERVER['HTTP_X_ORANGE_ID']) ||
|
||||
isset($_SERVER['HTTP_X_VODAFONE_3GPDPCONTEXT']) ||
|
||||
isset($_SERVER['HTTP_X_HUAWEI_USERID']) ||
|
||||
isset($_SERVER['HTTP_UA_OS']) || // Reported by Windows Smartphones
|
||||
(isset($_SERVER['HTTP_UA_CPU']) && $_SERVER['HTTP_UA_CPU'] == 'ARM') // Seen this on a HTC
|
||||
) {
|
||||
$this->isMobile = true;
|
||||
} elseif (!empty($this->accept) && (strpos($this->accept, 'text/vnd.wap.wml') !== false || strpos($this->accept, 'application/vnd.wap.xhtml+xml') !== false)) {
|
||||
$this->isMobile = true;
|
||||
} else {
|
||||
$this->_detect();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public function getRules()
|
||||
{
|
||||
return $this->detectionRules;
|
||||
}
|
||||
|
||||
/**
|
||||
* Magic overloading method.
|
||||
*
|
||||
* @method boolean is[...]()
|
||||
* @param string $name
|
||||
* @param array $arguments
|
||||
* @return mixed
|
||||
*/
|
||||
public function __call($name, $arguments)
|
||||
{
|
||||
|
||||
$key = substr($name, 2);
|
||||
return $this->_detect($key);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Private method that does the detection of the
|
||||
* mobile devices.
|
||||
*
|
||||
* @param type $key
|
||||
* @return boolean|null
|
||||
*/
|
||||
private function _detect($key='')
|
||||
{
|
||||
|
||||
if(empty($key)){
|
||||
|
||||
// Begin general search.
|
||||
foreach($this->detectionRules as $_regex){
|
||||
if(empty($_regex)){ continue; }
|
||||
if(preg_match('/'.$_regex.'/is', $this->userAgent)){
|
||||
$this->isMobile = true;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
|
||||
} else {
|
||||
|
||||
// Search for a certain key.
|
||||
// Make the keys lowecase so we can match: isIphone(), isiPhone(), isiphone(), etc.
|
||||
$key = strtolower($key);
|
||||
$_rules = array_change_key_case($this->detectionRules);
|
||||
|
||||
if(array_key_exists($key, $_rules)){
|
||||
if(empty($_rules[$key])){ return null; }
|
||||
if(preg_match('/'.$_rules[$key].'/is', $this->userAgent)){
|
||||
$this->isMobile = true;
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
trigger_error("Method $key is not defined", E_USER_WARNING);
|
||||
}
|
||||
|
||||
return false;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the device is mobile.
|
||||
* Returns true if any type of mobile device detected, including special ones
|
||||
* @return bool
|
||||
*/
|
||||
public function isMobile()
|
||||
{
|
||||
return $this->isMobile;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the device is a tablet.
|
||||
* Return true if any type of tablet device is detected.
|
||||
* @return boolean
|
||||
*/
|
||||
public function isTablet()
|
||||
{
|
||||
|
||||
foreach($this->tabletDevices as $_regex){
|
||||
if(preg_match('/'.$_regex.'/is', $this->userAgent)){
|
||||
$this->isTablet = true;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -1,10 +1,10 @@
|
|||
Copyright (c) 2005, Fabricio Zuardi
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
|
||||
* Neither the name of the author nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
Copyright (c) 2005, Fabricio Zuardi
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
|
||||
* Neither the name of the author nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
|
|
@ -1,38 +1,38 @@
|
|||
* 1.0.0 build 2010031920
|
||||
|
||||
- first public release
|
||||
- help in readme, install
|
||||
- cleanup ans separation of QRtools and QRspec
|
||||
- now TCPDF binding requires minimal changes in TCPDF, having most of job
|
||||
done in QRtools tcpdfBarcodeArray
|
||||
- nicer QRtools::timeBenchmark output
|
||||
- license and copyright notices in files
|
||||
- indent cleanup - from tab to 4spc, keep it that way please :)
|
||||
- sf project, repository, wiki
|
||||
- simple code generator in index.php
|
||||
|
||||
* 1.1.0 build 2010032113
|
||||
|
||||
- added merge tool wich generate merged version of code
|
||||
located in phpqrcode.php
|
||||
- splited qrconst.php from qrlib.php
|
||||
|
||||
* 1.1.1 build 2010032405
|
||||
|
||||
- patch by Rick Seymour allowing saving PNG and displaying it at the same time
|
||||
- added version info in VERSION file
|
||||
- modified merge tool to include version info into generated file
|
||||
- fixed e-mail in almost all head comments
|
||||
|
||||
* 1.1.2 build 2010032722
|
||||
|
||||
- full integration with TCPDF thanks to Nicola Asuni, it's author
|
||||
- fixed bug with alphanumeric encoding detection
|
||||
|
||||
* 1.1.3 build 2010081807
|
||||
|
||||
- short opening tags replaced with standard ones
|
||||
|
||||
* 1.1.4 build 2010100721
|
||||
|
||||
- added missing static keyword QRinput::check (found by Luke Brookhart, Onjax LLC)
|
||||
* 1.0.0 build 2010031920
|
||||
|
||||
- first public release
|
||||
- help in readme, install
|
||||
- cleanup ans separation of QRtools and QRspec
|
||||
- now TCPDF binding requires minimal changes in TCPDF, having most of job
|
||||
done in QRtools tcpdfBarcodeArray
|
||||
- nicer QRtools::timeBenchmark output
|
||||
- license and copyright notices in files
|
||||
- indent cleanup - from tab to 4spc, keep it that way please :)
|
||||
- sf project, repository, wiki
|
||||
- simple code generator in index.php
|
||||
|
||||
* 1.1.0 build 2010032113
|
||||
|
||||
- added merge tool wich generate merged version of code
|
||||
located in phpqrcode.php
|
||||
- splited qrconst.php from qrlib.php
|
||||
|
||||
* 1.1.1 build 2010032405
|
||||
|
||||
- patch by Rick Seymour allowing saving PNG and displaying it at the same time
|
||||
- added version info in VERSION file
|
||||
- modified merge tool to include version info into generated file
|
||||
- fixed e-mail in almost all head comments
|
||||
|
||||
* 1.1.2 build 2010032722
|
||||
|
||||
- full integration with TCPDF thanks to Nicola Asuni, it's author
|
||||
- fixed bug with alphanumeric encoding detection
|
||||
|
||||
* 1.1.3 build 2010081807
|
||||
|
||||
- short opening tags replaced with standard ones
|
||||
|
||||
* 1.1.4 build 2010100721
|
||||
|
||||
- added missing static keyword QRinput::check (found by Luke Brookhart, Onjax LLC)
|
||||
|
|
|
@ -1,67 +1,67 @@
|
|||
== REQUIREMENTS ==
|
||||
|
||||
* PHP5
|
||||
* PHP GD2 extension with JPEG and PNG support
|
||||
|
||||
== INSTALLATION ==
|
||||
|
||||
If you want to recreate cache by yourself make sure cache directory is
|
||||
writable and you have permisions to write into it. Also make sure you are
|
||||
able to read files in it if you have cache option enabled
|
||||
|
||||
== CONFIGURATION ==
|
||||
|
||||
Feel free to modify config constants in qrconfig.php file. Read about it in
|
||||
provided comments and project wiki page (links in README file)
|
||||
|
||||
== QUICK START ==
|
||||
|
||||
Notice: probably you should'nt use all of this in same script :)
|
||||
|
||||
<?phpb
|
||||
|
||||
//include only that one, rest required files will be included from it
|
||||
include "qrlib.php"
|
||||
|
||||
//write code into file, Error corection lecer is lowest, L (one form: L,M,Q,H)
|
||||
//each code square will be 4x4 pixels (4x zoom)
|
||||
//code will have 2 code squares white boundary around
|
||||
|
||||
QRcode::png('PHP QR Code :)', 'test.png', 'L', 4, 2);
|
||||
|
||||
//same as above but outputs file directly into browser (with appr. header etc.)
|
||||
//all other settings are default
|
||||
//WARNING! it should be FIRST and ONLY output generated by script, otherwise
|
||||
//rest of output will land inside PNG binary, breaking it for sure
|
||||
QRcode::png('PHP QR Code :)');
|
||||
|
||||
//show benchmark
|
||||
QRtools::timeBenchmark();
|
||||
|
||||
//rebuild cache
|
||||
QRtools::buildCache();
|
||||
|
||||
//code generated in text mode - as a binary table
|
||||
//then displayed out as HTML using Unicode block building chars :)
|
||||
$tab = $qr->encode('PHP QR Code :)');
|
||||
QRspec::debug($tab, true);
|
||||
|
||||
== TCPDF INTEGRATION ==
|
||||
|
||||
Inside bindings/tcpdf you will find slightly modified 2dbarcodes.php.
|
||||
Instal phpqrcode liblaty inside tcpdf folder, then overwrite (or merge)
|
||||
2dbarcodes.php
|
||||
|
||||
Then use similar as example #50 from TCPDF examples:
|
||||
|
||||
<?php
|
||||
|
||||
$style = array(
|
||||
'border' => true,
|
||||
'padding' => 4,
|
||||
'fgcolor' => array(0,0,0),
|
||||
'bgcolor' => false, //array(255,255,255)
|
||||
);
|
||||
|
||||
//code name: QR, specify error correction level after semicolon (L,M,Q,H)
|
||||
$pdf->write2DBarcode('PHP QR Code :)', 'QR,L', '', '', 30, 30, $style, 'N');
|
||||
== REQUIREMENTS ==
|
||||
|
||||
* PHP5
|
||||
* PHP GD2 extension with JPEG and PNG support
|
||||
|
||||
== INSTALLATION ==
|
||||
|
||||
If you want to recreate cache by yourself make sure cache directory is
|
||||
writable and you have permisions to write into it. Also make sure you are
|
||||
able to read files in it if you have cache option enabled
|
||||
|
||||
== CONFIGURATION ==
|
||||
|
||||
Feel free to modify config constants in qrconfig.php file. Read about it in
|
||||
provided comments and project wiki page (links in README file)
|
||||
|
||||
== QUICK START ==
|
||||
|
||||
Notice: probably you should'nt use all of this in same script :)
|
||||
|
||||
<?phpb
|
||||
|
||||
//include only that one, rest required files will be included from it
|
||||
include "qrlib.php"
|
||||
|
||||
//write code into file, Error corection lecer is lowest, L (one form: L,M,Q,H)
|
||||
//each code square will be 4x4 pixels (4x zoom)
|
||||
//code will have 2 code squares white boundary around
|
||||
|
||||
QRcode::png('PHP QR Code :)', 'test.png', 'L', 4, 2);
|
||||
|
||||
//same as above but outputs file directly into browser (with appr. header etc.)
|
||||
//all other settings are default
|
||||
//WARNING! it should be FIRST and ONLY output generated by script, otherwise
|
||||
//rest of output will land inside PNG binary, breaking it for sure
|
||||
QRcode::png('PHP QR Code :)');
|
||||
|
||||
//show benchmark
|
||||
QRtools::timeBenchmark();
|
||||
|
||||
//rebuild cache
|
||||
QRtools::buildCache();
|
||||
|
||||
//code generated in text mode - as a binary table
|
||||
//then displayed out as HTML using Unicode block building chars :)
|
||||
$tab = $qr->encode('PHP QR Code :)');
|
||||
QRspec::debug($tab, true);
|
||||
|
||||
== TCPDF INTEGRATION ==
|
||||
|
||||
Inside bindings/tcpdf you will find slightly modified 2dbarcodes.php.
|
||||
Instal phpqrcode liblaty inside tcpdf folder, then overwrite (or merge)
|
||||
2dbarcodes.php
|
||||
|
||||
Then use similar as example #50 from TCPDF examples:
|
||||
|
||||
<?php
|
||||
|
||||
$style = array(
|
||||
'border' => true,
|
||||
'padding' => 4,
|
||||
'fgcolor' => array(0,0,0),
|
||||
'bgcolor' => false, //array(255,255,255)
|
||||
);
|
||||
|
||||
//code name: QR, specify error correction level after semicolon (L,M,Q,H)
|
||||
$pdf->write2DBarcode('PHP QR Code :)', 'QR,L', '', '', 30, 30, $style, 'N');
|
||||
|
|
|
@ -1,165 +1,165 @@
|
|||
GNU LESSER GENERAL PUBLIC LICENSE
|
||||
Version 3, 29 June 2007
|
||||
|
||||
Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
|
||||
Everyone is permitted to copy and distribute verbatim copies
|
||||
of this license document, but changing it is not allowed.
|
||||
|
||||
|
||||
This version of the GNU Lesser General Public License incorporates
|
||||
the terms and conditions of version 3 of the GNU General Public
|
||||
License, supplemented by the additional permissions listed below.
|
||||
|
||||
0. Additional Definitions.
|
||||
|
||||
As used herein, "this License" refers to version 3 of the GNU Lesser
|
||||
General Public License, and the "GNU GPL" refers to version 3 of the GNU
|
||||
General Public License.
|
||||
|
||||
"The Library" refers to a covered work governed by this License,
|
||||
other than an Application or a Combined Work as defined below.
|
||||
|
||||
An "Application" is any work that makes use of an interface provided
|
||||
by the Library, but which is not otherwise based on the Library.
|
||||
Defining a subclass of a class defined by the Library is deemed a mode
|
||||
of using an interface provided by the Library.
|
||||
|
||||
A "Combined Work" is a work produced by combining or linking an
|
||||
Application with the Library. The particular version of the Library
|
||||
with which the Combined Work was made is also called the "Linked
|
||||
Version".
|
||||
|
||||
The "Minimal Corresponding Source" for a Combined Work means the
|
||||
Corresponding Source for the Combined Work, excluding any source code
|
||||
for portions of the Combined Work that, considered in isolation, are
|
||||
based on the Application, and not on the Linked Version.
|
||||
|
||||
The "Corresponding Application Code" for a Combined Work means the
|
||||
object code and/or source code for the Application, including any data
|
||||
and utility programs needed for reproducing the Combined Work from the
|
||||
Application, but excluding the System Libraries of the Combined Work.
|
||||
|
||||
1. Exception to Section 3 of the GNU GPL.
|
||||
|
||||
You may convey a covered work under sections 3 and 4 of this License
|
||||
without being bound by section 3 of the GNU GPL.
|
||||
|
||||
2. Conveying Modified Versions.
|
||||
|
||||
If you modify a copy of the Library, and, in your modifications, a
|
||||
facility refers to a function or data to be supplied by an Application
|
||||
that uses the facility (other than as an argument passed when the
|
||||
facility is invoked), then you may convey a copy of the modified
|
||||
version:
|
||||
|
||||
a) under this License, provided that you make a good faith effort to
|
||||
ensure that, in the event an Application does not supply the
|
||||
function or data, the facility still operates, and performs
|
||||
whatever part of its purpose remains meaningful, or
|
||||
|
||||
b) under the GNU GPL, with none of the additional permissions of
|
||||
this License applicable to that copy.
|
||||
|
||||
3. Object Code Incorporating Material from Library Header Files.
|
||||
|
||||
The object code form of an Application may incorporate material from
|
||||
a header file that is part of the Library. You may convey such object
|
||||
code under terms of your choice, provided that, if the incorporated
|
||||
material is not limited to numerical parameters, data structure
|
||||
layouts and accessors, or small macros, inline functions and templates
|
||||
(ten or fewer lines in length), you do both of the following:
|
||||
|
||||
a) Give prominent notice with each copy of the object code that the
|
||||
Library is used in it and that the Library and its use are
|
||||
covered by this License.
|
||||
|
||||
b) Accompany the object code with a copy of the GNU GPL and this license
|
||||
document.
|
||||
|
||||
4. Combined Works.
|
||||
|
||||
You may convey a Combined Work under terms of your choice that,
|
||||
taken together, effectively do not restrict modification of the
|
||||
portions of the Library contained in the Combined Work and reverse
|
||||
engineering for debugging such modifications, if you also do each of
|
||||
the following:
|
||||
|
||||
a) Give prominent notice with each copy of the Combined Work that
|
||||
the Library is used in it and that the Library and its use are
|
||||
covered by this License.
|
||||
|
||||
b) Accompany the Combined Work with a copy of the GNU GPL and this license
|
||||
document.
|
||||
|
||||
c) For a Combined Work that displays copyright notices during
|
||||
execution, include the copyright notice for the Library among
|
||||
these notices, as well as a reference directing the user to the
|
||||
copies of the GNU GPL and this license document.
|
||||
|
||||
d) Do one of the following:
|
||||
|
||||
0) Convey the Minimal Corresponding Source under the terms of this
|
||||
License, and the Corresponding Application Code in a form
|
||||
suitable for, and under terms that permit, the user to
|
||||
recombine or relink the Application with a modified version of
|
||||
the Linked Version to produce a modified Combined Work, in the
|
||||
manner specified by section 6 of the GNU GPL for conveying
|
||||
Corresponding Source.
|
||||
|
||||
1) Use a suitable shared library mechanism for linking with the
|
||||
Library. A suitable mechanism is one that (a) uses at run time
|
||||
a copy of the Library already present on the user's computer
|
||||
system, and (b) will operate properly with a modified version
|
||||
of the Library that is interface-compatible with the Linked
|
||||
Version.
|
||||
|
||||
e) Provide Installation Information, but only if you would otherwise
|
||||
be required to provide such information under section 6 of the
|
||||
GNU GPL, and only to the extent that such information is
|
||||
necessary to install and execute a modified version of the
|
||||
Combined Work produced by recombining or relinking the
|
||||
Application with a modified version of the Linked Version. (If
|
||||
you use option 4d0, the Installation Information must accompany
|
||||
the Minimal Corresponding Source and Corresponding Application
|
||||
Code. If you use option 4d1, you must provide the Installation
|
||||
Information in the manner specified by section 6 of the GNU GPL
|
||||
for conveying Corresponding Source.)
|
||||
|
||||
5. Combined Libraries.
|
||||
|
||||
You may place library facilities that are a work based on the
|
||||
Library side by side in a single library together with other library
|
||||
facilities that are not Applications and are not covered by this
|
||||
License, and convey such a combined library under terms of your
|
||||
choice, if you do both of the following:
|
||||
|
||||
a) Accompany the combined library with a copy of the same work based
|
||||
on the Library, uncombined with any other library facilities,
|
||||
conveyed under the terms of this License.
|
||||
|
||||
b) Give prominent notice with the combined library that part of it
|
||||
is a work based on the Library, and explaining where to find the
|
||||
accompanying uncombined form of the same work.
|
||||
|
||||
6. Revised Versions of the GNU Lesser General Public License.
|
||||
|
||||
The Free Software Foundation may publish revised and/or new versions
|
||||
of the GNU Lesser General Public License from time to time. Such new
|
||||
versions will be similar in spirit to the present version, but may
|
||||
differ in detail to address new problems or concerns.
|
||||
|
||||
Each version is given a distinguishing version number. If the
|
||||
Library as you received it specifies that a certain numbered version
|
||||
of the GNU Lesser General Public License "or any later version"
|
||||
applies to it, you have the option of following the terms and
|
||||
conditions either of that published version or of any later version
|
||||
published by the Free Software Foundation. If the Library as you
|
||||
received it does not specify a version number of the GNU Lesser
|
||||
General Public License, you may choose any version of the GNU Lesser
|
||||
General Public License ever published by the Free Software Foundation.
|
||||
|
||||
If the Library as you received it specifies that a proxy can decide
|
||||
whether future versions of the GNU Lesser General Public License shall
|
||||
apply, that proxy's public statement of acceptance of any version is
|
||||
permanent authorization for you to choose that version for the
|
||||
Library.
|
||||
GNU LESSER GENERAL PUBLIC LICENSE
|
||||
Version 3, 29 June 2007
|
||||
|
||||
Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
|
||||
Everyone is permitted to copy and distribute verbatim copies
|
||||
of this license document, but changing it is not allowed.
|
||||
|
||||
|
||||
This version of the GNU Lesser General Public License incorporates
|
||||
the terms and conditions of version 3 of the GNU General Public
|
||||
License, supplemented by the additional permissions listed below.
|
||||
|
||||
0. Additional Definitions.
|
||||
|
||||
As used herein, "this License" refers to version 3 of the GNU Lesser
|
||||
General Public License, and the "GNU GPL" refers to version 3 of the GNU
|
||||
General Public License.
|
||||
|
||||
"The Library" refers to a covered work governed by this License,
|
||||
other than an Application or a Combined Work as defined below.
|
||||
|
||||
An "Application" is any work that makes use of an interface provided
|
||||
by the Library, but which is not otherwise based on the Library.
|
||||
Defining a subclass of a class defined by the Library is deemed a mode
|
||||
of using an interface provided by the Library.
|
||||
|
||||
A "Combined Work" is a work produced by combining or linking an
|
||||
Application with the Library. The particular version of the Library
|
||||
with which the Combined Work was made is also called the "Linked
|
||||
Version".
|
||||
|
||||
The "Minimal Corresponding Source" for a Combined Work means the
|
||||
Corresponding Source for the Combined Work, excluding any source code
|
||||
for portions of the Combined Work that, considered in isolation, are
|
||||
based on the Application, and not on the Linked Version.
|
||||
|
||||
The "Corresponding Application Code" for a Combined Work means the
|
||||
object code and/or source code for the Application, including any data
|
||||
and utility programs needed for reproducing the Combined Work from the
|
||||
Application, but excluding the System Libraries of the Combined Work.
|
||||
|
||||
1. Exception to Section 3 of the GNU GPL.
|
||||
|
||||
You may convey a covered work under sections 3 and 4 of this License
|
||||
without being bound by section 3 of the GNU GPL.
|
||||
|
||||
2. Conveying Modified Versions.
|
||||
|
||||
If you modify a copy of the Library, and, in your modifications, a
|
||||
facility refers to a function or data to be supplied by an Application
|
||||
that uses the facility (other than as an argument passed when the
|
||||
facility is invoked), then you may convey a copy of the modified
|
||||
version:
|
||||
|
||||
a) under this License, provided that you make a good faith effort to
|
||||
ensure that, in the event an Application does not supply the
|
||||
function or data, the facility still operates, and performs
|
||||
whatever part of its purpose remains meaningful, or
|
||||
|
||||
b) under the GNU GPL, with none of the additional permissions of
|
||||
this License applicable to that copy.
|
||||
|
||||
3. Object Code Incorporating Material from Library Header Files.
|
||||
|
||||
The object code form of an Application may incorporate material from
|
||||
a header file that is part of the Library. You may convey such object
|
||||
code under terms of your choice, provided that, if the incorporated
|
||||
material is not limited to numerical parameters, data structure
|
||||
layouts and accessors, or small macros, inline functions and templates
|
||||
(ten or fewer lines in length), you do both of the following:
|
||||
|
||||
a) Give prominent notice with each copy of the object code that the
|
||||
Library is used in it and that the Library and its use are
|
||||
covered by this License.
|
||||
|
||||
b) Accompany the object code with a copy of the GNU GPL and this license
|
||||
document.
|
||||
|
||||
4. Combined Works.
|
||||
|
||||
You may convey a Combined Work under terms of your choice that,
|
||||
taken together, effectively do not restrict modification of the
|
||||
portions of the Library contained in the Combined Work and reverse
|
||||
engineering for debugging such modifications, if you also do each of
|
||||
the following:
|
||||
|
||||
a) Give prominent notice with each copy of the Combined Work that
|
||||
the Library is used in it and that the Library and its use are
|
||||
covered by this License.
|
||||
|
||||
b) Accompany the Combined Work with a copy of the GNU GPL and this license
|
||||
document.
|
||||
|
||||
c) For a Combined Work that displays copyright notices during
|
||||
execution, include the copyright notice for the Library among
|
||||
these notices, as well as a reference directing the user to the
|
||||
copies of the GNU GPL and this license document.
|
||||
|
||||
d) Do one of the following:
|
||||
|
||||
0) Convey the Minimal Corresponding Source under the terms of this
|
||||
License, and the Corresponding Application Code in a form
|
||||
suitable for, and under terms that permit, the user to
|
||||
recombine or relink the Application with a modified version of
|
||||
the Linked Version to produce a modified Combined Work, in the
|
||||
manner specified by section 6 of the GNU GPL for conveying
|
||||
Corresponding Source.
|
||||
|
||||
1) Use a suitable shared library mechanism for linking with the
|
||||
Library. A suitable mechanism is one that (a) uses at run time
|
||||
a copy of the Library already present on the user's computer
|
||||
system, and (b) will operate properly with a modified version
|
||||
of the Library that is interface-compatible with the Linked
|
||||
Version.
|
||||
|
||||
e) Provide Installation Information, but only if you would otherwise
|
||||
be required to provide such information under section 6 of the
|
||||
GNU GPL, and only to the extent that such information is
|
||||
necessary to install and execute a modified version of the
|
||||
Combined Work produced by recombining or relinking the
|
||||
Application with a modified version of the Linked Version. (If
|
||||
you use option 4d0, the Installation Information must accompany
|
||||
the Minimal Corresponding Source and Corresponding Application
|
||||
Code. If you use option 4d1, you must provide the Installation
|
||||
Information in the manner specified by section 6 of the GNU GPL
|
||||
for conveying Corresponding Source.)
|
||||
|
||||
5. Combined Libraries.
|
||||
|
||||
You may place library facilities that are a work based on the
|
||||
Library side by side in a single library together with other library
|
||||
facilities that are not Applications and are not covered by this
|
||||
License, and convey such a combined library under terms of your
|
||||
choice, if you do both of the following:
|
||||
|
||||
a) Accompany the combined library with a copy of the same work based
|
||||
on the Library, uncombined with any other library facilities,
|
||||
conveyed under the terms of this License.
|
||||
|
||||
b) Give prominent notice with the combined library that part of it
|
||||
is a work based on the Library, and explaining where to find the
|
||||
accompanying uncombined form of the same work.
|
||||
|
||||
6. Revised Versions of the GNU Lesser General Public License.
|
||||
|
||||
The Free Software Foundation may publish revised and/or new versions
|
||||
of the GNU Lesser General Public License from time to time. Such new
|
||||
versions will be similar in spirit to the present version, but may
|
||||
differ in detail to address new problems or concerns.
|
||||
|
||||
Each version is given a distinguishing version number. If the
|
||||
Library as you received it specifies that a certain numbered version
|
||||
of the GNU Lesser General Public License "or any later version"
|
||||
applies to it, you have the option of following the terms and
|
||||
conditions either of that published version or of any later version
|
||||
published by the Free Software Foundation. If the Library as you
|
||||
received it does not specify a version number of the GNU Lesser
|
||||
General Public License, you may choose any version of the GNU Lesser
|
||||
General Public License ever published by the Free Software Foundation.
|
||||
|
||||
If the Library as you received it specifies that a proxy can decide
|
||||
whether future versions of the GNU Lesser General Public License shall
|
||||
apply, that proxy's public statement of acceptance of any version is
|
||||
permanent authorization for you to choose that version for the
|
||||
Library.
|
||||
|
|
|
@ -1,45 +1,45 @@
|
|||
This is PHP implementation of QR Code 2-D barcode generator. It is pure-php
|
||||
LGPL-licensed implementation based on C libqrencode by Kentaro Fukuchi.
|
||||
|
||||
== LICENSING ==
|
||||
|
||||
Copyright (C) 2010 by Dominik Dzienia
|
||||
|
||||
This library is free software; you can redistribute it and/or modify it under
|
||||
the terms of the GNU Lesser General Public License as published by the Free
|
||||
Software Foundation; either version 3 of the License, or any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. See the GNU Lesser General Public License (LICENSE file)
|
||||
for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License along
|
||||
with this library; if not, write to the Free Software Foundation, Inc., 51
|
||||
Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
|
||||
== INSTALATION AND USAGE ==
|
||||
|
||||
* INSTALL file
|
||||
* http://sourceforge.net/apps/mediawiki/phpqrcode/index.php?title=Main_Page
|
||||
|
||||
== CONTACT ==
|
||||
|
||||
Fell free to contact me via e-mail (deltalab at poczta dot fm) or using
|
||||
folowing project pages:
|
||||
|
||||
* http://sourceforge.net/projects/phpqrcode/
|
||||
* http://phpqrcode.sourceforge.net/
|
||||
|
||||
== ACKNOWLEDGMENTS ==
|
||||
|
||||
Based on C libqrencode library (ver. 3.1.1)
|
||||
Copyright (C) 2006-2010 by Kentaro Fukuchi
|
||||
http://megaui.net/fukuchi/works/qrencode/index.en.html
|
||||
|
||||
QR Code is registered trademarks of DENSO WAVE INCORPORATED in JAPAN and other
|
||||
countries.
|
||||
|
||||
Reed-Solomon code encoder is written by Phil Karn, KA9Q.
|
||||
Copyright (C) 2002, 2003, 2004, 2006 Phil Karn, KA9Q
|
||||
This is PHP implementation of QR Code 2-D barcode generator. It is pure-php
|
||||
LGPL-licensed implementation based on C libqrencode by Kentaro Fukuchi.
|
||||
|
||||
== LICENSING ==
|
||||
|
||||
Copyright (C) 2010 by Dominik Dzienia
|
||||
|
||||
This library is free software; you can redistribute it and/or modify it under
|
||||
the terms of the GNU Lesser General Public License as published by the Free
|
||||
Software Foundation; either version 3 of the License, or any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. See the GNU Lesser General Public License (LICENSE file)
|
||||
for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License along
|
||||
with this library; if not, write to the Free Software Foundation, Inc., 51
|
||||
Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
|
||||
== INSTALATION AND USAGE ==
|
||||
|
||||
* INSTALL file
|
||||
* http://sourceforge.net/apps/mediawiki/phpqrcode/index.php?title=Main_Page
|
||||
|
||||
== CONTACT ==
|
||||
|
||||
Fell free to contact me via e-mail (deltalab at poczta dot fm) or using
|
||||
folowing project pages:
|
||||
|
||||
* http://sourceforge.net/projects/phpqrcode/
|
||||
* http://phpqrcode.sourceforge.net/
|
||||
|
||||
== ACKNOWLEDGMENTS ==
|
||||
|
||||
Based on C libqrencode library (ver. 3.1.1)
|
||||
Copyright (C) 2006-2010 by Kentaro Fukuchi
|
||||
http://megaui.net/fukuchi/works/qrencode/index.en.html
|
||||
|
||||
QR Code is registered trademarks of DENSO WAVE INCORPORATED in JAPAN and other
|
||||
countries.
|
||||
|
||||
Reed-Solomon code encoder is written by Phil Karn, KA9Q.
|
||||
Copyright (C) 2002, 2003, 2004, 2006 Phil Karn, KA9Q
|
||||
|
|
@ -1,2 +1,2 @@
|
|||
1.1.4
|
||||
1.1.4
|
||||
2010100721
|
|
@ -1,93 +1,93 @@
|
|||
<?php
|
||||
/*
|
||||
* PHP QR Code encoder
|
||||
*
|
||||
* Exemplatory usage
|
||||
*
|
||||
* PHP QR Code is distributed under LGPL 3
|
||||
* Copyright (C) 2010 Dominik Dzienia <deltalab at poczta dot fm>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 3 of the License, or any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
/*
|
||||
* PHP QR Code encoder
|
||||
*
|
||||
* Exemplatory usage
|
||||
*
|
||||
* PHP QR Code is distributed under LGPL 3
|
||||
* Copyright (C) 2010 Dominik Dzienia <deltalab at poczta dot fm>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 3 of the License, or any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
echo "<h1>PHP QR Code</h1><hr/>";
|
||||
|
||||
//set it to writable location, a place for temp generated PNG files
|
||||
$PNG_TEMP_DIR = dirname(__FILE__).DIRECTORY_SEPARATOR.'temp'.DIRECTORY_SEPARATOR;
|
||||
|
||||
//html PNG location prefix
|
||||
$PNG_WEB_DIR = 'temp/';
|
||||
|
||||
include "qrlib.php";
|
||||
|
||||
//ofcourse we need rights to create temp dir
|
||||
if (!file_exists($PNG_TEMP_DIR))
|
||||
|
||||
//set it to writable location, a place for temp generated PNG files
|
||||
$PNG_TEMP_DIR = dirname(__FILE__).DIRECTORY_SEPARATOR.'temp'.DIRECTORY_SEPARATOR;
|
||||
|
||||
//html PNG location prefix
|
||||
$PNG_WEB_DIR = 'temp/';
|
||||
|
||||
include "qrlib.php";
|
||||
|
||||
//ofcourse we need rights to create temp dir
|
||||
if (!file_exists($PNG_TEMP_DIR))
|
||||
mkdir($PNG_TEMP_DIR);
|
||||
|
||||
|
||||
$filename = $PNG_TEMP_DIR.'test.png';
|
||||
|
||||
//processing form input
|
||||
//remember to sanitize user input in real-life solution !!!
|
||||
$errorCorrectionLevel = 'L';
|
||||
if (isset($_REQUEST['level']) && in_array($_REQUEST['level'], array('L','M','Q','H')))
|
||||
$errorCorrectionLevel = $_REQUEST['level'];
|
||||
|
||||
|
||||
$filename = $PNG_TEMP_DIR.'test.png';
|
||||
|
||||
//processing form input
|
||||
//remember to sanitize user input in real-life solution !!!
|
||||
$errorCorrectionLevel = 'L';
|
||||
if (isset($_REQUEST['level']) && in_array($_REQUEST['level'], array('L','M','Q','H')))
|
||||
$errorCorrectionLevel = $_REQUEST['level'];
|
||||
|
||||
$matrixPointSize = 4;
|
||||
if (isset($_REQUEST['size']))
|
||||
$matrixPointSize = min(max((int)$_REQUEST['size'], 1), 10);
|
||||
|
||||
|
||||
$matrixPointSize = 4;
|
||||
if (isset($_REQUEST['size']))
|
||||
$matrixPointSize = min(max((int)$_REQUEST['size'], 1), 10);
|
||||
|
||||
|
||||
if (isset($_REQUEST['data'])) {
|
||||
|
||||
//it's very important!
|
||||
if (trim($_REQUEST['data']) == '')
|
||||
die('data cannot be empty! <a href="?">back</a>');
|
||||
if (isset($_REQUEST['data'])) {
|
||||
|
||||
//it's very important!
|
||||
if (trim($_REQUEST['data']) == '')
|
||||
die('data cannot be empty! <a href="?">back</a>');
|
||||
|
||||
// user data
|
||||
// user data
|
||||
$filename = $PNG_TEMP_DIR.'test'.md5($_REQUEST['data'].'|'.$errorCorrectionLevel.'|'.$matrixPointSize).'.png';
|
||||
QRcode::png($_REQUEST['data'], $filename, $errorCorrectionLevel, $matrixPointSize, 2);
|
||||
QRcode::png($_REQUEST['data'], $filename, $errorCorrectionLevel, $matrixPointSize, 2);
|
||||
|
||||
} else {
|
||||
|
||||
} else {
|
||||
|
||||
//default data
|
||||
echo 'You can provide data in GET parameter: <a href="?data=like_that">like that</a><hr/>';
|
||||
QRcode::png('PHP QR Code :)', $filename, $errorCorrectionLevel, $matrixPointSize, 2);
|
||||
QRcode::png('PHP QR Code :)', $filename, $errorCorrectionLevel, $matrixPointSize, 2);
|
||||
|
||||
}
|
||||
|
||||
|
||||
//display generated file
|
||||
echo '<img src="'.$PNG_WEB_DIR.basename($filename).'" /><hr/>';
|
||||
|
||||
//config form
|
||||
echo '<form action="index.php" method="post">
|
||||
Data: <input name="data" value="'.(isset($_REQUEST['data'])?htmlspecialchars($_REQUEST['data']):'PHP QR Code :)').'" />
|
||||
ECC: <select name="level">
|
||||
<option value="L"'.(($errorCorrectionLevel=='L')?' selected':'').'>L - smallest</option>
|
||||
<option value="M"'.(($errorCorrectionLevel=='M')?' selected':'').'>M</option>
|
||||
<option value="Q"'.(($errorCorrectionLevel=='Q')?' selected':'').'>Q</option>
|
||||
<option value="H"'.(($errorCorrectionLevel=='H')?' selected':'').'>H - best</option>
|
||||
</select>
|
||||
Size: <select name="size">';
|
||||
|
||||
for($i=1;$i<=10;$i++)
|
||||
echo '<option value="'.$i.'"'.(($matrixPointSize==$i)?' selected':'').'>'.$i.'</option>';
|
||||
|
||||
echo '</select>
|
||||
<input type="submit" value="GENERATE"></form><hr/>';
|
||||
|
||||
echo '<img src="'.$PNG_WEB_DIR.basename($filename).'" /><hr/>';
|
||||
|
||||
//config form
|
||||
echo '<form action="index.php" method="post">
|
||||
Data: <input name="data" value="'.(isset($_REQUEST['data'])?htmlspecialchars($_REQUEST['data']):'PHP QR Code :)').'" />
|
||||
ECC: <select name="level">
|
||||
<option value="L"'.(($errorCorrectionLevel=='L')?' selected':'').'>L - smallest</option>
|
||||
<option value="M"'.(($errorCorrectionLevel=='M')?' selected':'').'>M</option>
|
||||
<option value="Q"'.(($errorCorrectionLevel=='Q')?' selected':'').'>Q</option>
|
||||
<option value="H"'.(($errorCorrectionLevel=='H')?' selected':'').'>H - best</option>
|
||||
</select>
|
||||
Size: <select name="size">';
|
||||
|
||||
for($i=1;$i<=10;$i++)
|
||||
echo '<option value="'.$i.'"'.(($matrixPointSize==$i)?' selected':'').'>'.$i.'</option>';
|
||||
|
||||
echo '</select>
|
||||
<input type="submit" value="GENERATE"></form><hr/>';
|
||||
|
||||
// benchmark
|
||||
QRtools::timeBenchmark();
|
||||
|
||||
|
|
|
@ -1,180 +1,180 @@
|
|||
<?php
|
||||
/*
|
||||
* PHP QR Code encoder
|
||||
*
|
||||
* Bitstream class
|
||||
*
|
||||
* Based on libqrencode C library distributed under LGPL 2.1
|
||||
* Copyright (C) 2006, 2007, 2008, 2009 Kentaro Fukuchi <fukuchi@megaui.net>
|
||||
*
|
||||
* PHP QR Code is distributed under LGPL 3
|
||||
* Copyright (C) 2010 Dominik Dzienia <deltalab at poczta dot fm>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 3 of the License, or any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
class QRbitstream {
|
||||
|
||||
public $data = array();
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
public function size()
|
||||
{
|
||||
return count($this->data);
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
public function allocate($setLength)
|
||||
{
|
||||
$this->data = array_fill(0, $setLength, 0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
public static function newFromNum($bits, $num)
|
||||
{
|
||||
$bstream = new QRbitstream();
|
||||
$bstream->allocate($bits);
|
||||
|
||||
$mask = 1 << ($bits - 1);
|
||||
for($i=0; $i<$bits; $i++) {
|
||||
if($num & $mask) {
|
||||
$bstream->data[$i] = 1;
|
||||
} else {
|
||||
$bstream->data[$i] = 0;
|
||||
}
|
||||
$mask = $mask >> 1;
|
||||
}
|
||||
|
||||
return $bstream;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
public static function newFromBytes($size, $data)
|
||||
{
|
||||
$bstream = new QRbitstream();
|
||||
$bstream->allocate($size * 8);
|
||||
$p=0;
|
||||
|
||||
for($i=0; $i<$size; $i++) {
|
||||
$mask = 0x80;
|
||||
for($j=0; $j<8; $j++) {
|
||||
if($data[$i] & $mask) {
|
||||
$bstream->data[$p] = 1;
|
||||
} else {
|
||||
$bstream->data[$p] = 0;
|
||||
}
|
||||
$p++;
|
||||
$mask = $mask >> 1;
|
||||
}
|
||||
}
|
||||
|
||||
return $bstream;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
public function append(QRbitstream $arg)
|
||||
{
|
||||
if (is_null($arg)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if($arg->size() == 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if($this->size() == 0) {
|
||||
$this->data = $arg->data;
|
||||
return 0;
|
||||
}
|
||||
|
||||
$this->data = array_values(array_merge($this->data, $arg->data));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
public function appendNum($bits, $num)
|
||||
{
|
||||
if ($bits == 0)
|
||||
return 0;
|
||||
|
||||
$b = QRbitstream::newFromNum($bits, $num);
|
||||
|
||||
if(is_null($b))
|
||||
return -1;
|
||||
|
||||
$ret = $this->append($b);
|
||||
unset($b);
|
||||
|
||||
return $ret;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
public function appendBytes($size, $data)
|
||||
{
|
||||
if ($size == 0)
|
||||
return 0;
|
||||
|
||||
$b = QRbitstream::newFromBytes($size, $data);
|
||||
|
||||
if(is_null($b))
|
||||
return -1;
|
||||
|
||||
$ret = $this->append($b);
|
||||
unset($b);
|
||||
|
||||
return $ret;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
public function toByte()
|
||||
{
|
||||
|
||||
$size = $this->size();
|
||||
|
||||
if($size == 0) {
|
||||
return array();
|
||||
}
|
||||
|
||||
$data = array_fill(0, (int)(($size + 7) / 8), 0);
|
||||
$bytes = (int)($size / 8);
|
||||
|
||||
$p = 0;
|
||||
|
||||
for($i=0; $i<$bytes; $i++) {
|
||||
$v = 0;
|
||||
for($j=0; $j<8; $j++) {
|
||||
$v = $v << 1;
|
||||
$v |= $this->data[$p];
|
||||
$p++;
|
||||
}
|
||||
$data[$i] = $v;
|
||||
}
|
||||
|
||||
if($size & 7) {
|
||||
$v = 0;
|
||||
for($j=0; $j<($size & 7); $j++) {
|
||||
$v = $v << 1;
|
||||
$v |= $this->data[$p];
|
||||
$p++;
|
||||
}
|
||||
$data[$bytes] = $v;
|
||||
}
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
}
|
||||
<?php
|
||||
/*
|
||||
* PHP QR Code encoder
|
||||
*
|
||||
* Bitstream class
|
||||
*
|
||||
* Based on libqrencode C library distributed under LGPL 2.1
|
||||
* Copyright (C) 2006, 2007, 2008, 2009 Kentaro Fukuchi <fukuchi@megaui.net>
|
||||
*
|
||||
* PHP QR Code is distributed under LGPL 3
|
||||
* Copyright (C) 2010 Dominik Dzienia <deltalab at poczta dot fm>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 3 of the License, or any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
class QRbitstream {
|
||||
|
||||
public $data = array();
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
public function size()
|
||||
{
|
||||
return count($this->data);
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
public function allocate($setLength)
|
||||
{
|
||||
$this->data = array_fill(0, $setLength, 0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
public static function newFromNum($bits, $num)
|
||||
{
|
||||
$bstream = new QRbitstream();
|
||||
$bstream->allocate($bits);
|
||||
|
||||
$mask = 1 << ($bits - 1);
|
||||
for($i=0; $i<$bits; $i++) {
|
||||
if($num & $mask) {
|
||||
$bstream->data[$i] = 1;
|
||||
} else {
|
||||
$bstream->data[$i] = 0;
|
||||
}
|
||||
$mask = $mask >> 1;
|
||||
}
|
||||
|
||||
return $bstream;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
public static function newFromBytes($size, $data)
|
||||
{
|
||||
$bstream = new QRbitstream();
|
||||
$bstream->allocate($size * 8);
|
||||
$p=0;
|
||||
|
||||
for($i=0; $i<$size; $i++) {
|
||||
$mask = 0x80;
|
||||
for($j=0; $j<8; $j++) {
|
||||
if($data[$i] & $mask) {
|
||||
$bstream->data[$p] = 1;
|
||||
} else {
|
||||
$bstream->data[$p] = 0;
|
||||
}
|
||||
$p++;
|
||||
$mask = $mask >> 1;
|
||||
}
|
||||
}
|
||||
|
||||
return $bstream;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
public function append(QRbitstream $arg)
|
||||
{
|
||||
if (is_null($arg)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if($arg->size() == 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if($this->size() == 0) {
|
||||
$this->data = $arg->data;
|
||||
return 0;
|
||||
}
|
||||
|
||||
$this->data = array_values(array_merge($this->data, $arg->data));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
public function appendNum($bits, $num)
|
||||
{
|
||||
if ($bits == 0)
|
||||
return 0;
|
||||
|
||||
$b = QRbitstream::newFromNum($bits, $num);
|
||||
|
||||
if(is_null($b))
|
||||
return -1;
|
||||
|
||||
$ret = $this->append($b);
|
||||
unset($b);
|
||||
|
||||
return $ret;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
public function appendBytes($size, $data)
|
||||
{
|
||||
if ($size == 0)
|
||||
return 0;
|
||||
|
||||
$b = QRbitstream::newFromBytes($size, $data);
|
||||
|
||||
if(is_null($b))
|
||||
return -1;
|
||||
|
||||
$ret = $this->append($b);
|
||||
unset($b);
|
||||
|
||||
return $ret;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
public function toByte()
|
||||
{
|
||||
|
||||
$size = $this->size();
|
||||
|
||||
if($size == 0) {
|
||||
return array();
|
||||
}
|
||||
|
||||
$data = array_fill(0, (int)(($size + 7) / 8), 0);
|
||||
$bytes = (int)($size / 8);
|
||||
|
||||
$p = 0;
|
||||
|
||||
for($i=0; $i<$bytes; $i++) {
|
||||
$v = 0;
|
||||
for($j=0; $j<8; $j++) {
|
||||
$v = $v << 1;
|
||||
$v |= $this->data[$p];
|
||||
$p++;
|
||||
}
|
||||
$data[$i] = $v;
|
||||
}
|
||||
|
||||
if($size & 7) {
|
||||
$v = 0;
|
||||
for($j=0; $j<($size & 7); $j++) {
|
||||
$v = $v << 1;
|
||||
$v |= $this->data[$p];
|
||||
$p++;
|
||||
}
|
||||
$data[$bytes] = $v;
|
||||
}
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1,17 +1,17 @@
|
|||
<?php
|
||||
/*
|
||||
* PHP QR Code encoder
|
||||
*
|
||||
* Config file, feel free to modify
|
||||
*/
|
||||
|
||||
define('QR_CACHEABLE', true); // use cache - more disk reads but less CPU power, masks and format templates are stored there
|
||||
define('QR_CACHE_DIR', dirname(__FILE__).DIRECTORY_SEPARATOR.'cache'.DIRECTORY_SEPARATOR); // used when QR_CACHEABLE === true
|
||||
define('QR_LOG_DIR', dirname(__FILE__).DIRECTORY_SEPARATOR); // default error logs dir
|
||||
|
||||
define('QR_FIND_BEST_MASK', true); // if true, estimates best mask (spec. default, but extremally slow; set to false to significant performance boost but (propably) worst quality code
|
||||
define('QR_FIND_FROM_RANDOM', false); // if false, checks all masks available, otherwise value tells count of masks need to be checked, mask id are got randomly
|
||||
define('QR_DEFAULT_MASK', 2); // when QR_FIND_BEST_MASK === false
|
||||
|
||||
define('QR_PNG_MAXIMUM_SIZE', 1024); // maximum allowed png image width (in pixels), tune to make sure GD and PHP can handle such big images
|
||||
<?php
|
||||
/*
|
||||
* PHP QR Code encoder
|
||||
*
|
||||
* Config file, feel free to modify
|
||||
*/
|
||||
|
||||
define('QR_CACHEABLE', true); // use cache - more disk reads but less CPU power, masks and format templates are stored there
|
||||
define('QR_CACHE_DIR', dirname(__FILE__).DIRECTORY_SEPARATOR.'cache'.DIRECTORY_SEPARATOR); // used when QR_CACHEABLE === true
|
||||
define('QR_LOG_DIR', dirname(__FILE__).DIRECTORY_SEPARATOR); // default error logs dir
|
||||
|
||||
define('QR_FIND_BEST_MASK', true); // if true, estimates best mask (spec. default, but extremally slow; set to false to significant performance boost but (propably) worst quality code
|
||||
define('QR_FIND_FROM_RANDOM', false); // if false, checks all masks available, otherwise value tells count of masks need to be checked, mask id are got randomly
|
||||
define('QR_DEFAULT_MASK', 2); // when QR_FIND_BEST_MASK === false
|
||||
|
||||
define('QR_PNG_MAXIMUM_SIZE', 1024); // maximum allowed png image width (in pixels), tune to make sure GD and PHP can handle such big images
|
||||
|
|
@ -1,54 +1,54 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* PHP QR Code encoder
|
||||
*
|
||||
* Common constants
|
||||
*
|
||||
* Based on libqrencode C library distributed under LGPL 2.1
|
||||
* Copyright (C) 2006, 2007, 2008, 2009 Kentaro Fukuchi <fukuchi@megaui.net>
|
||||
*
|
||||
* PHP QR Code is distributed under LGPL 3
|
||||
* Copyright (C) 2010 Dominik Dzienia <deltalab at poczta dot fm>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 3 of the License, or any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
// Encoding modes
|
||||
|
||||
define('QR_MODE_NUL', -1);
|
||||
define('QR_MODE_NUM', 0);
|
||||
define('QR_MODE_AN', 1);
|
||||
define('QR_MODE_8', 2);
|
||||
define('QR_MODE_KANJI', 3);
|
||||
define('QR_MODE_STRUCTURE', 4);
|
||||
|
||||
// Levels of error correction.
|
||||
|
||||
define('QR_ECLEVEL_L', 0);
|
||||
define('QR_ECLEVEL_M', 1);
|
||||
define('QR_ECLEVEL_Q', 2);
|
||||
define('QR_ECLEVEL_H', 3);
|
||||
|
||||
// Supported output formats
|
||||
|
||||
define('QR_FORMAT_TEXT', 0);
|
||||
define('QR_FORMAT_PNG', 1);
|
||||
|
||||
class qrstr {
|
||||
public static function set(&$srctab, $x, $y, $repl, $replLen = false) {
|
||||
$srctab[$y] = substr_replace($srctab[$y], ($replLen !== false)?substr($repl,0,$replLen):$repl, $x, ($replLen !== false)?$replLen:strlen($repl));
|
||||
}
|
||||
<?php
|
||||
|
||||
/*
|
||||
* PHP QR Code encoder
|
||||
*
|
||||
* Common constants
|
||||
*
|
||||
* Based on libqrencode C library distributed under LGPL 2.1
|
||||
* Copyright (C) 2006, 2007, 2008, 2009 Kentaro Fukuchi <fukuchi@megaui.net>
|
||||
*
|
||||
* PHP QR Code is distributed under LGPL 3
|
||||
* Copyright (C) 2010 Dominik Dzienia <deltalab at poczta dot fm>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 3 of the License, or any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
// Encoding modes
|
||||
|
||||
define('QR_MODE_NUL', -1);
|
||||
define('QR_MODE_NUM', 0);
|
||||
define('QR_MODE_AN', 1);
|
||||
define('QR_MODE_8', 2);
|
||||
define('QR_MODE_KANJI', 3);
|
||||
define('QR_MODE_STRUCTURE', 4);
|
||||
|
||||
// Levels of error correction.
|
||||
|
||||
define('QR_ECLEVEL_L', 0);
|
||||
define('QR_ECLEVEL_M', 1);
|
||||
define('QR_ECLEVEL_Q', 2);
|
||||
define('QR_ECLEVEL_H', 3);
|
||||
|
||||
// Supported output formats
|
||||
|
||||
define('QR_FORMAT_TEXT', 0);
|
||||
define('QR_FORMAT_PNG', 1);
|
||||
|
||||
class qrstr {
|
||||
public static function set(&$srctab, $x, $y, $repl, $replLen = false) {
|
||||
$srctab[$y] = substr_replace($srctab[$y], ($replLen !== false)?substr($repl,0,$replLen):$repl, $x, ($replLen !== false)?$replLen:strlen($repl));
|
||||
}
|
||||
}
|
|
@ -1,95 +1,95 @@
|
|||
<?php
|
||||
/*
|
||||
* PHP QR Code encoder
|
||||
*
|
||||
* Image output of code using GD2
|
||||
*
|
||||
* PHP QR Code is distributed under LGPL 3
|
||||
* Copyright (C) 2010 Dominik Dzienia <deltalab at poczta dot fm>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 3 of the License, or any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
define('QR_IMAGE', true);
|
||||
|
||||
class QRimage {
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
public static function png($frame, $filename = false, $pixelPerPoint = 4, $outerFrame = 4,$saveandprint=FALSE)
|
||||
{
|
||||
$image = self::image($frame, $pixelPerPoint, $outerFrame);
|
||||
|
||||
if ($filename === false) {
|
||||
Header("Content-type: image/png");
|
||||
ImagePng($image);
|
||||
} else {
|
||||
if($saveandprint===TRUE){
|
||||
ImagePng($image, $filename);
|
||||
header("Content-type: image/png");
|
||||
ImagePng($image);
|
||||
}else{
|
||||
ImagePng($image, $filename);
|
||||
}
|
||||
}
|
||||
|
||||
ImageDestroy($image);
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
public static function jpg($frame, $filename = false, $pixelPerPoint = 8, $outerFrame = 4, $q = 85)
|
||||
{
|
||||
$image = self::image($frame, $pixelPerPoint, $outerFrame);
|
||||
|
||||
if ($filename === false) {
|
||||
Header("Content-type: image/jpeg");
|
||||
ImageJpeg($image, null, $q);
|
||||
} else {
|
||||
ImageJpeg($image, $filename, $q);
|
||||
}
|
||||
|
||||
ImageDestroy($image);
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
private static function image($frame, $pixelPerPoint = 4, $outerFrame = 4)
|
||||
{
|
||||
$h = count($frame);
|
||||
$w = strlen($frame[0]);
|
||||
|
||||
$imgW = $w + 2*$outerFrame;
|
||||
$imgH = $h + 2*$outerFrame;
|
||||
|
||||
$base_image =ImageCreate($imgW, $imgH);
|
||||
|
||||
$col[0] = ImageColorAllocate($base_image,255,255,255);
|
||||
$col[1] = ImageColorAllocate($base_image,0,0,0);
|
||||
|
||||
imagefill($base_image, 0, 0, $col[0]);
|
||||
|
||||
for($y=0; $y<$h; $y++) {
|
||||
for($x=0; $x<$w; $x++) {
|
||||
if ($frame[$y][$x] == '1') {
|
||||
ImageSetPixel($base_image,$x+$outerFrame,$y+$outerFrame,$col[1]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$target_image =ImageCreate($imgW * $pixelPerPoint, $imgH * $pixelPerPoint);
|
||||
ImageCopyResized($target_image, $base_image, 0, 0, 0, 0, $imgW * $pixelPerPoint, $imgH * $pixelPerPoint, $imgW, $imgH);
|
||||
ImageDestroy($base_image);
|
||||
|
||||
return $target_image;
|
||||
}
|
||||
<?php
|
||||
/*
|
||||
* PHP QR Code encoder
|
||||
*
|
||||
* Image output of code using GD2
|
||||
*
|
||||
* PHP QR Code is distributed under LGPL 3
|
||||
* Copyright (C) 2010 Dominik Dzienia <deltalab at poczta dot fm>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 3 of the License, or any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
define('QR_IMAGE', true);
|
||||
|
||||
class QRimage {
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
public static function png($frame, $filename = false, $pixelPerPoint = 4, $outerFrame = 4,$saveandprint=FALSE)
|
||||
{
|
||||
$image = self::image($frame, $pixelPerPoint, $outerFrame);
|
||||
|
||||
if ($filename === false) {
|
||||
Header("Content-type: image/png");
|
||||
ImagePng($image);
|
||||
} else {
|
||||
if($saveandprint===TRUE){
|
||||
ImagePng($image, $filename);
|
||||
header("Content-type: image/png");
|
||||
ImagePng($image);
|
||||
}else{
|
||||
ImagePng($image, $filename);
|
||||
}
|
||||
}
|
||||
|
||||
ImageDestroy($image);
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
public static function jpg($frame, $filename = false, $pixelPerPoint = 8, $outerFrame = 4, $q = 85)
|
||||
{
|
||||
$image = self::image($frame, $pixelPerPoint, $outerFrame);
|
||||
|
||||
if ($filename === false) {
|
||||
Header("Content-type: image/jpeg");
|
||||
ImageJpeg($image, null, $q);
|
||||
} else {
|
||||
ImageJpeg($image, $filename, $q);
|
||||
}
|
||||
|
||||
ImageDestroy($image);
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
private static function image($frame, $pixelPerPoint = 4, $outerFrame = 4)
|
||||
{
|
||||
$h = count($frame);
|
||||
$w = strlen($frame[0]);
|
||||
|
||||
$imgW = $w + 2*$outerFrame;
|
||||
$imgH = $h + 2*$outerFrame;
|
||||
|
||||
$base_image =ImageCreate($imgW, $imgH);
|
||||
|
||||
$col[0] = ImageColorAllocate($base_image,255,255,255);
|
||||
$col[1] = ImageColorAllocate($base_image,0,0,0);
|
||||
|
||||
imagefill($base_image, 0, 0, $col[0]);
|
||||
|
||||
for($y=0; $y<$h; $y++) {
|
||||
for($x=0; $x<$w; $x++) {
|
||||
if ($frame[$y][$x] == '1') {
|
||||
ImageSetPixel($base_image,$x+$outerFrame,$y+$outerFrame,$col[1]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$target_image =ImageCreate($imgW * $pixelPerPoint, $imgH * $pixelPerPoint);
|
||||
ImageCopyResized($target_image, $base_image, 0, 0, 0, 0, $imgW * $pixelPerPoint, $imgH * $pixelPerPoint, $imgW, $imgH);
|
||||
ImageDestroy($base_image);
|
||||
|
||||
return $target_image;
|
||||
}
|
||||
}
|
|
@ -1,43 +1,43 @@
|
|||
<?php
|
||||
/*
|
||||
* PHP QR Code encoder
|
||||
*
|
||||
* Root library file, prepares environment and includes dependencies
|
||||
*
|
||||
* Based on libqrencode C library distributed under LGPL 2.1
|
||||
* Copyright (C) 2006, 2007, 2008, 2009 Kentaro Fukuchi <fukuchi@megaui.net>
|
||||
*
|
||||
* PHP QR Code is distributed under LGPL 3
|
||||
* Copyright (C) 2010 Dominik Dzienia <deltalab at poczta dot fm>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 3 of the License, or any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
$QR_BASEDIR = dirname(__FILE__).DIRECTORY_SEPARATOR;
|
||||
|
||||
// Required libs
|
||||
|
||||
include $QR_BASEDIR."qrconst.php";
|
||||
include $QR_BASEDIR."qrconfig.php";
|
||||
include $QR_BASEDIR."qrtools.php";
|
||||
include $QR_BASEDIR."qrspec.php";
|
||||
include $QR_BASEDIR."qrimage.php";
|
||||
include $QR_BASEDIR."qrinput.php";
|
||||
include $QR_BASEDIR."qrbitstream.php";
|
||||
include $QR_BASEDIR."qrsplit.php";
|
||||
include $QR_BASEDIR."qrrscode.php";
|
||||
include $QR_BASEDIR."qrmask.php";
|
||||
include $QR_BASEDIR."qrencode.php";
|
||||
|
||||
<?php
|
||||
/*
|
||||
* PHP QR Code encoder
|
||||
*
|
||||
* Root library file, prepares environment and includes dependencies
|
||||
*
|
||||
* Based on libqrencode C library distributed under LGPL 2.1
|
||||
* Copyright (C) 2006, 2007, 2008, 2009 Kentaro Fukuchi <fukuchi@megaui.net>
|
||||
*
|
||||
* PHP QR Code is distributed under LGPL 3
|
||||
* Copyright (C) 2010 Dominik Dzienia <deltalab at poczta dot fm>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 3 of the License, or any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
$QR_BASEDIR = dirname(__FILE__).DIRECTORY_SEPARATOR;
|
||||
|
||||
// Required libs
|
||||
|
||||
include $QR_BASEDIR."qrconst.php";
|
||||
include $QR_BASEDIR."qrconfig.php";
|
||||
include $QR_BASEDIR."qrtools.php";
|
||||
include $QR_BASEDIR."qrspec.php";
|
||||
include $QR_BASEDIR."qrimage.php";
|
||||
include $QR_BASEDIR."qrinput.php";
|
||||
include $QR_BASEDIR."qrbitstream.php";
|
||||
include $QR_BASEDIR."qrsplit.php";
|
||||
include $QR_BASEDIR."qrrscode.php";
|
||||
include $QR_BASEDIR."qrmask.php";
|
||||
include $QR_BASEDIR."qrencode.php";
|
||||
|
||||
|
|
|
@ -1,328 +1,328 @@
|
|||
<?php
|
||||
/*
|
||||
* PHP QR Code encoder
|
||||
*
|
||||
* Masking
|
||||
*
|
||||
* Based on libqrencode C library distributed under LGPL 2.1
|
||||
* Copyright (C) 2006, 2007, 2008, 2009 Kentaro Fukuchi <fukuchi@megaui.net>
|
||||
*
|
||||
* PHP QR Code is distributed under LGPL 3
|
||||
* Copyright (C) 2010 Dominik Dzienia <deltalab at poczta dot fm>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 3 of the License, or any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
define('N1', 3);
|
||||
define('N2', 3);
|
||||
define('N3', 40);
|
||||
define('N4', 10);
|
||||
|
||||
class QRmask {
|
||||
|
||||
public $runLength = array();
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
public function __construct()
|
||||
{
|
||||
$this->runLength = array_fill(0, QRSPEC_WIDTH_MAX + 1, 0);
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
public function writeFormatInformation($width, &$frame, $mask, $level)
|
||||
{
|
||||
$blacks = 0;
|
||||
$format = QRspec::getFormatInfo($mask, $level);
|
||||
|
||||
for($i=0; $i<8; $i++) {
|
||||
if($format & 1) {
|
||||
$blacks += 2;
|
||||
$v = 0x85;
|
||||
} else {
|
||||
$v = 0x84;
|
||||
}
|
||||
|
||||
$frame[8][$width - 1 - $i] = chr($v);
|
||||
if($i < 6) {
|
||||
$frame[$i][8] = chr($v);
|
||||
} else {
|
||||
$frame[$i + 1][8] = chr($v);
|
||||
}
|
||||
$format = $format >> 1;
|
||||
}
|
||||
|
||||
for($i=0; $i<7; $i++) {
|
||||
if($format & 1) {
|
||||
$blacks += 2;
|
||||
$v = 0x85;
|
||||
} else {
|
||||
$v = 0x84;
|
||||
}
|
||||
|
||||
$frame[$width - 7 + $i][8] = chr($v);
|
||||
if($i == 0) {
|
||||
$frame[8][7] = chr($v);
|
||||
} else {
|
||||
$frame[8][6 - $i] = chr($v);
|
||||
}
|
||||
|
||||
$format = $format >> 1;
|
||||
}
|
||||
|
||||
return $blacks;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
public function mask0($x, $y) { return ($x+$y)&1; }
|
||||
public function mask1($x, $y) { return ($y&1); }
|
||||
public function mask2($x, $y) { return ($x%3); }
|
||||
public function mask3($x, $y) { return ($x+$y)%3; }
|
||||
public function mask4($x, $y) { return (((int)($y/2))+((int)($x/3)))&1; }
|
||||
public function mask5($x, $y) { return (($x*$y)&1)+($x*$y)%3; }
|
||||
public function mask6($x, $y) { return ((($x*$y)&1)+($x*$y)%3)&1; }
|
||||
public function mask7($x, $y) { return ((($x*$y)%3)+(($x+$y)&1))&1; }
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
private function generateMaskNo($maskNo, $width, $frame)
|
||||
{
|
||||
$bitMask = array_fill(0, $width, array_fill(0, $width, 0));
|
||||
|
||||
for($y=0; $y<$width; $y++) {
|
||||
for($x=0; $x<$width; $x++) {
|
||||
if(ord($frame[$y][$x]) & 0x80) {
|
||||
$bitMask[$y][$x] = 0;
|
||||
} else {
|
||||
$maskFunc = call_user_func(array($this, 'mask'.$maskNo), $x, $y);
|
||||
$bitMask[$y][$x] = ($maskFunc == 0)?1:0;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
return $bitMask;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
public static function serial($bitFrame)
|
||||
{
|
||||
$codeArr = array();
|
||||
|
||||
foreach ($bitFrame as $line)
|
||||
$codeArr[] = join('', $line);
|
||||
|
||||
return gzcompress(join("\n", $codeArr), 9);
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
public static function unserial($code)
|
||||
{
|
||||
$codeArr = array();
|
||||
|
||||
$codeLines = explode("\n", gzuncompress($code));
|
||||
foreach ($codeLines as $line)
|
||||
$codeArr[] = str_split($line);
|
||||
|
||||
return $codeArr;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
public function makeMaskNo($maskNo, $width, $s, &$d, $maskGenOnly = false)
|
||||
{
|
||||
$b = 0;
|
||||
$bitMask = array();
|
||||
|
||||
$fileName = QR_CACHE_DIR.'mask_'.$maskNo.DIRECTORY_SEPARATOR.'mask_'.$width.'_'.$maskNo.'.dat';
|
||||
|
||||
if (QR_CACHEABLE) {
|
||||
if (file_exists($fileName)) {
|
||||
$bitMask = self::unserial(file_get_contents($fileName));
|
||||
} else {
|
||||
$bitMask = $this->generateMaskNo($maskNo, $width, $s);
|
||||
if (!file_exists(QR_CACHE_DIR.'mask_'.$maskNo))
|
||||
mkdir(QR_CACHE_DIR.'mask_'.$maskNo);
|
||||
file_put_contents($fileName, self::serial($bitMask));
|
||||
}
|
||||
} else {
|
||||
$bitMask = $this->generateMaskNo($maskNo, $width, $s);
|
||||
}
|
||||
|
||||
if ($maskGenOnly)
|
||||
return;
|
||||
|
||||
$d = $s;
|
||||
|
||||
for($y=0; $y<$width; $y++) {
|
||||
for($x=0; $x<$width; $x++) {
|
||||
if($bitMask[$y][$x] == 1) {
|
||||
$d[$y][$x] = chr(ord($s[$y][$x]) ^ (int)$bitMask[$y][$x]);
|
||||
}
|
||||
$b += (int)(ord($d[$y][$x]) & 1);
|
||||
}
|
||||
}
|
||||
|
||||
return $b;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
public function makeMask($width, $frame, $maskNo, $level)
|
||||
{
|
||||
$masked = array_fill(0, $width, str_repeat("\0", $width));
|
||||
$this->makeMaskNo($maskNo, $width, $frame, $masked);
|
||||
$this->writeFormatInformation($width, $masked, $maskNo, $level);
|
||||
|
||||
return $masked;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
public function calcN1N3($length)
|
||||
{
|
||||
$demerit = 0;
|
||||
|
||||
for($i=0; $i<$length; $i++) {
|
||||
|
||||
if($this->runLength[$i] >= 5) {
|
||||
$demerit += (N1 + ($this->runLength[$i] - 5));
|
||||
}
|
||||
if($i & 1) {
|
||||
if(($i >= 3) && ($i < ($length-2)) && ($this->runLength[$i] % 3 == 0)) {
|
||||
$fact = (int)($this->runLength[$i] / 3);
|
||||
if(($this->runLength[$i-2] == $fact) &&
|
||||
($this->runLength[$i-1] == $fact) &&
|
||||
($this->runLength[$i+1] == $fact) &&
|
||||
($this->runLength[$i+2] == $fact)) {
|
||||
if(($this->runLength[$i-3] < 0) || ($this->runLength[$i-3] >= (4 * $fact))) {
|
||||
$demerit += N3;
|
||||
} else if((($i+3) >= $length) || ($this->runLength[$i+3] >= (4 * $fact))) {
|
||||
$demerit += N3;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return $demerit;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
public function evaluateSymbol($width, $frame)
|
||||
{
|
||||
$head = 0;
|
||||
$demerit = 0;
|
||||
|
||||
for($y=0; $y<$width; $y++) {
|
||||
$head = 0;
|
||||
$this->runLength[0] = 1;
|
||||
|
||||
$frameY = $frame[$y];
|
||||
|
||||
if ($y>0)
|
||||
$frameYM = $frame[$y-1];
|
||||
|
||||
for($x=0; $x<$width; $x++) {
|
||||
if(($x > 0) && ($y > 0)) {
|
||||
$b22 = ord($frameY[$x]) & ord($frameY[$x-1]) & ord($frameYM[$x]) & ord($frameYM[$x-1]);
|
||||
$w22 = ord($frameY[$x]) | ord($frameY[$x-1]) | ord($frameYM[$x]) | ord($frameYM[$x-1]);
|
||||
|
||||
if(($b22 | ($w22 ^ 1))&1) {
|
||||
$demerit += N2;
|
||||
}
|
||||
}
|
||||
if(($x == 0) && (ord($frameY[$x]) & 1)) {
|
||||
$this->runLength[0] = -1;
|
||||
$head = 1;
|
||||
$this->runLength[$head] = 1;
|
||||
} else if($x > 0) {
|
||||
if((ord($frameY[$x]) ^ ord($frameY[$x-1])) & 1) {
|
||||
$head++;
|
||||
$this->runLength[$head] = 1;
|
||||
} else {
|
||||
$this->runLength[$head]++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$demerit += $this->calcN1N3($head+1);
|
||||
}
|
||||
|
||||
for($x=0; $x<$width; $x++) {
|
||||
$head = 0;
|
||||
$this->runLength[0] = 1;
|
||||
|
||||
for($y=0; $y<$width; $y++) {
|
||||
if($y == 0 && (ord($frame[$y][$x]) & 1)) {
|
||||
$this->runLength[0] = -1;
|
||||
$head = 1;
|
||||
$this->runLength[$head] = 1;
|
||||
} else if($y > 0) {
|
||||
if((ord($frame[$y][$x]) ^ ord($frame[$y-1][$x])) & 1) {
|
||||
$head++;
|
||||
$this->runLength[$head] = 1;
|
||||
} else {
|
||||
$this->runLength[$head]++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$demerit += $this->calcN1N3($head+1);
|
||||
}
|
||||
|
||||
return $demerit;
|
||||
}
|
||||
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
public function mask($width, $frame, $level)
|
||||
{
|
||||
$minDemerit = PHP_INT_MAX;
|
||||
$bestMaskNum = 0;
|
||||
$bestMask = array();
|
||||
|
||||
$checked_masks = array(0,1,2,3,4,5,6,7);
|
||||
|
||||
if (QR_FIND_FROM_RANDOM !== false) {
|
||||
|
||||
$howManuOut = 8-(QR_FIND_FROM_RANDOM % 9);
|
||||
for ($i = 0; $i < $howManuOut; $i++) {
|
||||
$remPos = rand (0, count($checked_masks)-1);
|
||||
unset($checked_masks[$remPos]);
|
||||
$checked_masks = array_values($checked_masks);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
$bestMask = $frame;
|
||||
|
||||
foreach($checked_masks as $i) {
|
||||
$mask = array_fill(0, $width, str_repeat("\0", $width));
|
||||
|
||||
$demerit = 0;
|
||||
$blacks = 0;
|
||||
$blacks = $this->makeMaskNo($i, $width, $frame, $mask);
|
||||
$blacks += $this->writeFormatInformation($width, $mask, $i, $level);
|
||||
$blacks = (int)(100 * $blacks / ($width * $width));
|
||||
$demerit = (int)((int)(abs($blacks - 50) / 5) * N4);
|
||||
$demerit += $this->evaluateSymbol($width, $mask);
|
||||
|
||||
if($demerit < $minDemerit) {
|
||||
$minDemerit = $demerit;
|
||||
$bestMask = $mask;
|
||||
$bestMaskNum = $i;
|
||||
}
|
||||
}
|
||||
|
||||
return $bestMask;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
}
|
||||
<?php
|
||||
/*
|
||||
* PHP QR Code encoder
|
||||
*
|
||||
* Masking
|
||||
*
|
||||
* Based on libqrencode C library distributed under LGPL 2.1
|
||||
* Copyright (C) 2006, 2007, 2008, 2009 Kentaro Fukuchi <fukuchi@megaui.net>
|
||||
*
|
||||
* PHP QR Code is distributed under LGPL 3
|
||||
* Copyright (C) 2010 Dominik Dzienia <deltalab at poczta dot fm>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 3 of the License, or any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
define('N1', 3);
|
||||
define('N2', 3);
|
||||
define('N3', 40);
|
||||
define('N4', 10);
|
||||
|
||||
class QRmask {
|
||||
|
||||
public $runLength = array();
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
public function __construct()
|
||||
{
|
||||
$this->runLength = array_fill(0, QRSPEC_WIDTH_MAX + 1, 0);
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
public function writeFormatInformation($width, &$frame, $mask, $level)
|
||||
{
|
||||
$blacks = 0;
|
||||
$format = QRspec::getFormatInfo($mask, $level);
|
||||
|
||||
for($i=0; $i<8; $i++) {
|
||||
if($format & 1) {
|
||||
$blacks += 2;
|
||||
$v = 0x85;
|
||||
} else {
|
||||
$v = 0x84;
|
||||
}
|
||||
|
||||
$frame[8][$width - 1 - $i] = chr($v);
|
||||
if($i < 6) {
|
||||
$frame[$i][8] = chr($v);
|
||||
} else {
|
||||
$frame[$i + 1][8] = chr($v);
|
||||
}
|
||||
$format = $format >> 1;
|
||||
}
|
||||
|
||||
for($i=0; $i<7; $i++) {
|
||||
if($format & 1) {
|
||||
$blacks += 2;
|
||||
$v = 0x85;
|
||||
} else {
|
||||
$v = 0x84;
|
||||
}
|
||||
|
||||
$frame[$width - 7 + $i][8] = chr($v);
|
||||
if($i == 0) {
|
||||
$frame[8][7] = chr($v);
|
||||
} else {
|
||||
$frame[8][6 - $i] = chr($v);
|
||||
}
|
||||
|
||||
$format = $format >> 1;
|
||||
}
|
||||
|
||||
return $blacks;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
public function mask0($x, $y) { return ($x+$y)&1; }
|
||||
public function mask1($x, $y) { return ($y&1); }
|
||||
public function mask2($x, $y) { return ($x%3); }
|
||||
public function mask3($x, $y) { return ($x+$y)%3; }
|
||||
public function mask4($x, $y) { return (((int)($y/2))+((int)($x/3)))&1; }
|
||||
public function mask5($x, $y) { return (($x*$y)&1)+($x*$y)%3; }
|
||||
public function mask6($x, $y) { return ((($x*$y)&1)+($x*$y)%3)&1; }
|
||||
public function mask7($x, $y) { return ((($x*$y)%3)+(($x+$y)&1))&1; }
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
private function generateMaskNo($maskNo, $width, $frame)
|
||||
{
|
||||
$bitMask = array_fill(0, $width, array_fill(0, $width, 0));
|
||||
|
||||
for($y=0; $y<$width; $y++) {
|
||||
for($x=0; $x<$width; $x++) {
|
||||
if(ord($frame[$y][$x]) & 0x80) {
|
||||
$bitMask[$y][$x] = 0;
|
||||
} else {
|
||||
$maskFunc = call_user_func(array($this, 'mask'.$maskNo), $x, $y);
|
||||
$bitMask[$y][$x] = ($maskFunc == 0)?1:0;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
return $bitMask;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
public static function serial($bitFrame)
|
||||
{
|
||||
$codeArr = array();
|
||||
|
||||
foreach ($bitFrame as $line)
|
||||
$codeArr[] = join('', $line);
|
||||
|
||||
return gzcompress(join("\n", $codeArr), 9);
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
public static function unserial($code)
|
||||
{
|
||||
$codeArr = array();
|
||||
|
||||
$codeLines = explode("\n", gzuncompress($code));
|
||||
foreach ($codeLines as $line)
|
||||
$codeArr[] = str_split($line);
|
||||
|
||||
return $codeArr;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
public function makeMaskNo($maskNo, $width, $s, &$d, $maskGenOnly = false)
|
||||
{
|
||||
$b = 0;
|
||||
$bitMask = array();
|
||||
|
||||
$fileName = QR_CACHE_DIR.'mask_'.$maskNo.DIRECTORY_SEPARATOR.'mask_'.$width.'_'.$maskNo.'.dat';
|
||||
|
||||
if (QR_CACHEABLE) {
|
||||
if (file_exists($fileName)) {
|
||||
$bitMask = self::unserial(file_get_contents($fileName));
|
||||
} else {
|
||||
$bitMask = $this->generateMaskNo($maskNo, $width, $s);
|
||||
if (!file_exists(QR_CACHE_DIR.'mask_'.$maskNo))
|
||||
mkdir(QR_CACHE_DIR.'mask_'.$maskNo);
|
||||
file_put_contents($fileName, self::serial($bitMask));
|
||||
}
|
||||
} else {
|
||||
$bitMask = $this->generateMaskNo($maskNo, $width, $s);
|
||||
}
|
||||
|
||||
if ($maskGenOnly)
|
||||
return;
|
||||
|
||||
$d = $s;
|
||||
|
||||
for($y=0; $y<$width; $y++) {
|
||||
for($x=0; $x<$width; $x++) {
|
||||
if($bitMask[$y][$x] == 1) {
|
||||
$d[$y][$x] = chr(ord($s[$y][$x]) ^ (int)$bitMask[$y][$x]);
|
||||
}
|
||||
$b += (int)(ord($d[$y][$x]) & 1);
|
||||
}
|
||||
}
|
||||
|
||||
return $b;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
public function makeMask($width, $frame, $maskNo, $level)
|
||||
{
|
||||
$masked = array_fill(0, $width, str_repeat("\0", $width));
|
||||
$this->makeMaskNo($maskNo, $width, $frame, $masked);
|
||||
$this->writeFormatInformation($width, $masked, $maskNo, $level);
|
||||
|
||||
return $masked;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
public function calcN1N3($length)
|
||||
{
|
||||
$demerit = 0;
|
||||
|
||||
for($i=0; $i<$length; $i++) {
|
||||
|
||||
if($this->runLength[$i] >= 5) {
|
||||
$demerit += (N1 + ($this->runLength[$i] - 5));
|
||||
}
|
||||
if($i & 1) {
|
||||
if(($i >= 3) && ($i < ($length-2)) && ($this->runLength[$i] % 3 == 0)) {
|
||||
$fact = (int)($this->runLength[$i] / 3);
|
||||
if(($this->runLength[$i-2] == $fact) &&
|
||||
($this->runLength[$i-1] == $fact) &&
|
||||
($this->runLength[$i+1] == $fact) &&
|
||||
($this->runLength[$i+2] == $fact)) {
|
||||
if(($this->runLength[$i-3] < 0) || ($this->runLength[$i-3] >= (4 * $fact))) {
|
||||
$demerit += N3;
|
||||
} else if((($i+3) >= $length) || ($this->runLength[$i+3] >= (4 * $fact))) {
|
||||
$demerit += N3;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return $demerit;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
public function evaluateSymbol($width, $frame)
|
||||
{
|
||||
$head = 0;
|
||||
$demerit = 0;
|
||||
|
||||
for($y=0; $y<$width; $y++) {
|
||||
$head = 0;
|
||||
$this->runLength[0] = 1;
|
||||
|
||||
$frameY = $frame[$y];
|
||||
|
||||
if ($y>0)
|
||||
$frameYM = $frame[$y-1];
|
||||
|
||||
for($x=0; $x<$width; $x++) {
|
||||
if(($x > 0) && ($y > 0)) {
|
||||
$b22 = ord($frameY[$x]) & ord($frameY[$x-1]) & ord($frameYM[$x]) & ord($frameYM[$x-1]);
|
||||
$w22 = ord($frameY[$x]) | ord($frameY[$x-1]) | ord($frameYM[$x]) | ord($frameYM[$x-1]);
|
||||
|
||||
if(($b22 | ($w22 ^ 1))&1) {
|
||||
$demerit += N2;
|
||||
}
|
||||
}
|
||||
if(($x == 0) && (ord($frameY[$x]) & 1)) {
|
||||
$this->runLength[0] = -1;
|
||||
$head = 1;
|
||||
$this->runLength[$head] = 1;
|
||||
} else if($x > 0) {
|
||||
if((ord($frameY[$x]) ^ ord($frameY[$x-1])) & 1) {
|
||||
$head++;
|
||||
$this->runLength[$head] = 1;
|
||||
} else {
|
||||
$this->runLength[$head]++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$demerit += $this->calcN1N3($head+1);
|
||||
}
|
||||
|
||||
for($x=0; $x<$width; $x++) {
|
||||
$head = 0;
|
||||
$this->runLength[0] = 1;
|
||||
|
||||
for($y=0; $y<$width; $y++) {
|
||||
if($y == 0 && (ord($frame[$y][$x]) & 1)) {
|
||||
$this->runLength[0] = -1;
|
||||
$head = 1;
|
||||
$this->runLength[$head] = 1;
|
||||
} else if($y > 0) {
|
||||
if((ord($frame[$y][$x]) ^ ord($frame[$y-1][$x])) & 1) {
|
||||
$head++;
|
||||
$this->runLength[$head] = 1;
|
||||
} else {
|
||||
$this->runLength[$head]++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$demerit += $this->calcN1N3($head+1);
|
||||
}
|
||||
|
||||
return $demerit;
|
||||
}
|
||||
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
public function mask($width, $frame, $level)
|
||||
{
|
||||
$minDemerit = PHP_INT_MAX;
|
||||
$bestMaskNum = 0;
|
||||
$bestMask = array();
|
||||
|
||||
$checked_masks = array(0,1,2,3,4,5,6,7);
|
||||
|
||||
if (QR_FIND_FROM_RANDOM !== false) {
|
||||
|
||||
$howManuOut = 8-(QR_FIND_FROM_RANDOM % 9);
|
||||
for ($i = 0; $i < $howManuOut; $i++) {
|
||||
$remPos = rand (0, count($checked_masks)-1);
|
||||
unset($checked_masks[$remPos]);
|
||||
$checked_masks = array_values($checked_masks);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
$bestMask = $frame;
|
||||
|
||||
foreach($checked_masks as $i) {
|
||||
$mask = array_fill(0, $width, str_repeat("\0", $width));
|
||||
|
||||
$demerit = 0;
|
||||
$blacks = 0;
|
||||
$blacks = $this->makeMaskNo($i, $width, $frame, $mask);
|
||||
$blacks += $this->writeFormatInformation($width, $mask, $i, $level);
|
||||
$blacks = (int)(100 * $blacks / ($width * $width));
|
||||
$demerit = (int)((int)(abs($blacks - 50) / 5) * N4);
|
||||
$demerit += $this->evaluateSymbol($width, $mask);
|
||||
|
||||
if($demerit < $minDemerit) {
|
||||
$minDemerit = $demerit;
|
||||
$bestMask = $mask;
|
||||
$bestMaskNum = $i;
|
||||
}
|
||||
}
|
||||
|
||||
return $bestMask;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
}
|
||||
|
|
|
@ -1,210 +1,210 @@
|
|||
<?php
|
||||
/*
|
||||
* PHP QR Code encoder
|
||||
*
|
||||
* Reed-Solomon error correction support
|
||||
*
|
||||
* Copyright (C) 2002, 2003, 2004, 2006 Phil Karn, KA9Q
|
||||
* (libfec is released under the GNU Lesser General Public License.)
|
||||
*
|
||||
* Based on libqrencode C library distributed under LGPL 2.1
|
||||
* Copyright (C) 2006, 2007, 2008, 2009 Kentaro Fukuchi <fukuchi@megaui.net>
|
||||
*
|
||||
* PHP QR Code is distributed under LGPL 3
|
||||
* Copyright (C) 2010 Dominik Dzienia <deltalab at poczta dot fm>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 3 of the License, or any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
class QRrsItem {
|
||||
|
||||
public $mm; // Bits per symbol
|
||||
public $nn; // Symbols per block (= (1<<mm)-1)
|
||||
public $alpha_to = array(); // log lookup table
|
||||
public $index_of = array(); // Antilog lookup table
|
||||
public $genpoly = array(); // Generator polynomial
|
||||
public $nroots; // Number of generator roots = number of parity symbols
|
||||
public $fcr; // First consecutive root, index form
|
||||
public $prim; // Primitive element, index form
|
||||
public $iprim; // prim-th root of 1, index form
|
||||
public $pad; // Padding bytes in shortened block
|
||||
public $gfpoly;
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
public function modnn($x)
|
||||
{
|
||||
while ($x >= $this->nn) {
|
||||
$x -= $this->nn;
|
||||
$x = ($x >> $this->mm) + ($x & $this->nn);
|
||||
}
|
||||
|
||||
return $x;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
public static function init_rs_char($symsize, $gfpoly, $fcr, $prim, $nroots, $pad)
|
||||
{
|
||||
// Common code for intializing a Reed-Solomon control block (char or int symbols)
|
||||
// Copyright 2004 Phil Karn, KA9Q
|
||||
// May be used under the terms of the GNU Lesser General Public License (LGPL)
|
||||
|
||||
$rs = null;
|
||||
|
||||
// Check parameter ranges
|
||||
if($symsize < 0 || $symsize > 8) return $rs;
|
||||
if($fcr < 0 || $fcr >= (1<<$symsize)) return $rs;
|
||||
if($prim <= 0 || $prim >= (1<<$symsize)) return $rs;
|
||||
if($nroots < 0 || $nroots >= (1<<$symsize)) return $rs; // Can't have more roots than symbol values!
|
||||
if($pad < 0 || $pad >= ((1<<$symsize) -1 - $nroots)) return $rs; // Too much padding
|
||||
|
||||
$rs = new QRrsItem();
|
||||
$rs->mm = $symsize;
|
||||
$rs->nn = (1<<$symsize)-1;
|
||||
$rs->pad = $pad;
|
||||
|
||||
$rs->alpha_to = array_fill(0, $rs->nn+1, 0);
|
||||
$rs->index_of = array_fill(0, $rs->nn+1, 0);
|
||||
|
||||
// PHP style macro replacement ;)
|
||||
$NN =& $rs->nn;
|
||||
$A0 =& $NN;
|
||||
|
||||
// Generate Galois field lookup tables
|
||||
$rs->index_of[0] = $A0; // log(zero) = -inf
|
||||
$rs->alpha_to[$A0] = 0; // alpha**-inf = 0
|
||||
$sr = 1;
|
||||
|
||||
for($i=0; $i<$rs->nn; $i++) {
|
||||
$rs->index_of[$sr] = $i;
|
||||
$rs->alpha_to[$i] = $sr;
|
||||
$sr <<= 1;
|
||||
if($sr & (1<<$symsize)) {
|
||||
$sr ^= $gfpoly;
|
||||
}
|
||||
$sr &= $rs->nn;
|
||||
}
|
||||
|
||||
if($sr != 1){
|
||||
// field generator polynomial is not primitive!
|
||||
$rs = NULL;
|
||||
return $rs;
|
||||
}
|
||||
|
||||
/* Form RS code generator polynomial from its roots */
|
||||
$rs->genpoly = array_fill(0, $nroots+1, 0);
|
||||
|
||||
$rs->fcr = $fcr;
|
||||
$rs->prim = $prim;
|
||||
$rs->nroots = $nroots;
|
||||
$rs->gfpoly = $gfpoly;
|
||||
|
||||
/* Find prim-th root of 1, used in decoding */
|
||||
for($iprim=1;($iprim % $prim) != 0;$iprim += $rs->nn)
|
||||
; // intentional empty-body loop!
|
||||
|
||||
$rs->iprim = (int)($iprim / $prim);
|
||||
$rs->genpoly[0] = 1;
|
||||
|
||||
for ($i = 0,$root=$fcr*$prim; $i < $nroots; $i++, $root += $prim) {
|
||||
$rs->genpoly[$i+1] = 1;
|
||||
|
||||
// Multiply rs->genpoly[] by @**(root + x)
|
||||
for ($j = $i; $j > 0; $j--) {
|
||||
if ($rs->genpoly[$j] != 0) {
|
||||
$rs->genpoly[$j] = $rs->genpoly[$j-1] ^ $rs->alpha_to[$rs->modnn($rs->index_of[$rs->genpoly[$j]] + $root)];
|
||||
} else {
|
||||
$rs->genpoly[$j] = $rs->genpoly[$j-1];
|
||||
}
|
||||
}
|
||||
// rs->genpoly[0] can never be zero
|
||||
$rs->genpoly[0] = $rs->alpha_to[$rs->modnn($rs->index_of[$rs->genpoly[0]] + $root)];
|
||||
}
|
||||
|
||||
// convert rs->genpoly[] to index form for quicker encoding
|
||||
for ($i = 0; $i <= $nroots; $i++)
|
||||
$rs->genpoly[$i] = $rs->index_of[$rs->genpoly[$i]];
|
||||
|
||||
return $rs;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
public function encode_rs_char($data, &$parity)
|
||||
{
|
||||
$MM =& $this->mm;
|
||||
$NN =& $this->nn;
|
||||
$ALPHA_TO =& $this->alpha_to;
|
||||
$INDEX_OF =& $this->index_of;
|
||||
$GENPOLY =& $this->genpoly;
|
||||
$NROOTS =& $this->nroots;
|
||||
$FCR =& $this->fcr;
|
||||
$PRIM =& $this->prim;
|
||||
$IPRIM =& $this->iprim;
|
||||
$PAD =& $this->pad;
|
||||
$A0 =& $NN;
|
||||
|
||||
$parity = array_fill(0, $NROOTS, 0);
|
||||
|
||||
for($i=0; $i< ($NN-$NROOTS-$PAD); $i++) {
|
||||
|
||||
$feedback = $INDEX_OF[$data[$i] ^ $parity[0]];
|
||||
if($feedback != $A0) {
|
||||
// feedback term is non-zero
|
||||
|
||||
// This line is unnecessary when GENPOLY[NROOTS] is unity, as it must
|
||||
// always be for the polynomials constructed by init_rs()
|
||||
$feedback = $this->modnn($NN - $GENPOLY[$NROOTS] + $feedback);
|
||||
|
||||
for($j=1;$j<$NROOTS;$j++) {
|
||||
$parity[$j] ^= $ALPHA_TO[$this->modnn($feedback + $GENPOLY[$NROOTS-$j])];
|
||||
}
|
||||
}
|
||||
|
||||
// Shift
|
||||
array_shift($parity);
|
||||
if($feedback != $A0) {
|
||||
array_push($parity, $ALPHA_TO[$this->modnn($feedback + $GENPOLY[0])]);
|
||||
} else {
|
||||
array_push($parity, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//##########################################################################
|
||||
|
||||
class QRrs {
|
||||
|
||||
public static $items = array();
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
public static function init_rs($symsize, $gfpoly, $fcr, $prim, $nroots, $pad)
|
||||
{
|
||||
foreach(self::$items as $rs) {
|
||||
if($rs->pad != $pad) continue;
|
||||
if($rs->nroots != $nroots) continue;
|
||||
if($rs->mm != $symsize) continue;
|
||||
if($rs->gfpoly != $gfpoly) continue;
|
||||
if($rs->fcr != $fcr) continue;
|
||||
if($rs->prim != $prim) continue;
|
||||
|
||||
return $rs;
|
||||
}
|
||||
|
||||
$rs = QRrsItem::init_rs_char($symsize, $gfpoly, $fcr, $prim, $nroots, $pad);
|
||||
array_unshift(self::$items, $rs);
|
||||
|
||||
return $rs;
|
||||
}
|
||||
<?php
|
||||
/*
|
||||
* PHP QR Code encoder
|
||||
*
|
||||
* Reed-Solomon error correction support
|
||||
*
|
||||
* Copyright (C) 2002, 2003, 2004, 2006 Phil Karn, KA9Q
|
||||
* (libfec is released under the GNU Lesser General Public License.)
|
||||
*
|
||||
* Based on libqrencode C library distributed under LGPL 2.1
|
||||
* Copyright (C) 2006, 2007, 2008, 2009 Kentaro Fukuchi <fukuchi@megaui.net>
|
||||
*
|
||||
* PHP QR Code is distributed under LGPL 3
|
||||
* Copyright (C) 2010 Dominik Dzienia <deltalab at poczta dot fm>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 3 of the License, or any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
class QRrsItem {
|
||||
|
||||
public $mm; // Bits per symbol
|
||||
public $nn; // Symbols per block (= (1<<mm)-1)
|
||||
public $alpha_to = array(); // log lookup table
|
||||
public $index_of = array(); // Antilog lookup table
|
||||
public $genpoly = array(); // Generator polynomial
|
||||
public $nroots; // Number of generator roots = number of parity symbols
|
||||
public $fcr; // First consecutive root, index form
|
||||
public $prim; // Primitive element, index form
|
||||
public $iprim; // prim-th root of 1, index form
|
||||
public $pad; // Padding bytes in shortened block
|
||||
public $gfpoly;
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
public function modnn($x)
|
||||
{
|
||||
while ($x >= $this->nn) {
|
||||
$x -= $this->nn;
|
||||
$x = ($x >> $this->mm) + ($x & $this->nn);
|
||||
}
|
||||
|
||||
return $x;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
public static function init_rs_char($symsize, $gfpoly, $fcr, $prim, $nroots, $pad)
|
||||
{
|
||||
// Common code for intializing a Reed-Solomon control block (char or int symbols)
|
||||
// Copyright 2004 Phil Karn, KA9Q
|
||||
// May be used under the terms of the GNU Lesser General Public License (LGPL)
|
||||
|
||||
$rs = null;
|
||||
|
||||
// Check parameter ranges
|
||||
if($symsize < 0 || $symsize > 8) return $rs;
|
||||
if($fcr < 0 || $fcr >= (1<<$symsize)) return $rs;
|
||||
if($prim <= 0 || $prim >= (1<<$symsize)) return $rs;
|
||||
if($nroots < 0 || $nroots >= (1<<$symsize)) return $rs; // Can't have more roots than symbol values!
|
||||
if($pad < 0 || $pad >= ((1<<$symsize) -1 - $nroots)) return $rs; // Too much padding
|
||||
|
||||
$rs = new QRrsItem();
|
||||
$rs->mm = $symsize;
|
||||
$rs->nn = (1<<$symsize)-1;
|
||||
$rs->pad = $pad;
|
||||
|
||||
$rs->alpha_to = array_fill(0, $rs->nn+1, 0);
|
||||
$rs->index_of = array_fill(0, $rs->nn+1, 0);
|
||||
|
||||
// PHP style macro replacement ;)
|
||||
$NN =& $rs->nn;
|
||||
$A0 =& $NN;
|
||||
|
||||
// Generate Galois field lookup tables
|
||||
$rs->index_of[0] = $A0; // log(zero) = -inf
|
||||
$rs->alpha_to[$A0] = 0; // alpha**-inf = 0
|
||||
$sr = 1;
|
||||
|
||||
for($i=0; $i<$rs->nn; $i++) {
|
||||
$rs->index_of[$sr] = $i;
|
||||
$rs->alpha_to[$i] = $sr;
|
||||
$sr <<= 1;
|
||||
if($sr & (1<<$symsize)) {
|
||||
$sr ^= $gfpoly;
|
||||
}
|
||||
$sr &= $rs->nn;
|
||||
}
|
||||
|
||||
if($sr != 1){
|
||||
// field generator polynomial is not primitive!
|
||||
$rs = NULL;
|
||||
return $rs;
|
||||
}
|
||||
|
||||
/* Form RS code generator polynomial from its roots */
|
||||
$rs->genpoly = array_fill(0, $nroots+1, 0);
|
||||
|
||||
$rs->fcr = $fcr;
|
||||
$rs->prim = $prim;
|
||||
$rs->nroots = $nroots;
|
||||
$rs->gfpoly = $gfpoly;
|
||||
|
||||
/* Find prim-th root of 1, used in decoding */
|
||||
for($iprim=1;($iprim % $prim) != 0;$iprim += $rs->nn)
|
||||
; // intentional empty-body loop!
|
||||
|
||||
$rs->iprim = (int)($iprim / $prim);
|
||||
$rs->genpoly[0] = 1;
|
||||
|
||||
for ($i = 0,$root=$fcr*$prim; $i < $nroots; $i++, $root += $prim) {
|
||||
$rs->genpoly[$i+1] = 1;
|
||||
|
||||
// Multiply rs->genpoly[] by @**(root + x)
|
||||
for ($j = $i; $j > 0; $j--) {
|
||||
if ($rs->genpoly[$j] != 0) {
|
||||
$rs->genpoly[$j] = $rs->genpoly[$j-1] ^ $rs->alpha_to[$rs->modnn($rs->index_of[$rs->genpoly[$j]] + $root)];
|
||||
} else {
|
||||
$rs->genpoly[$j] = $rs->genpoly[$j-1];
|
||||
}
|
||||
}
|
||||
// rs->genpoly[0] can never be zero
|
||||
$rs->genpoly[0] = $rs->alpha_to[$rs->modnn($rs->index_of[$rs->genpoly[0]] + $root)];
|
||||
}
|
||||
|
||||
// convert rs->genpoly[] to index form for quicker encoding
|
||||
for ($i = 0; $i <= $nroots; $i++)
|
||||
$rs->genpoly[$i] = $rs->index_of[$rs->genpoly[$i]];
|
||||
|
||||
return $rs;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
public function encode_rs_char($data, &$parity)
|
||||
{
|
||||
$MM =& $this->mm;
|
||||
$NN =& $this->nn;
|
||||
$ALPHA_TO =& $this->alpha_to;
|
||||
$INDEX_OF =& $this->index_of;
|
||||
$GENPOLY =& $this->genpoly;
|
||||
$NROOTS =& $this->nroots;
|
||||
$FCR =& $this->fcr;
|
||||
$PRIM =& $this->prim;
|
||||
$IPRIM =& $this->iprim;
|
||||
$PAD =& $this->pad;
|
||||
$A0 =& $NN;
|
||||
|
||||
$parity = array_fill(0, $NROOTS, 0);
|
||||
|
||||
for($i=0; $i< ($NN-$NROOTS-$PAD); $i++) {
|
||||
|
||||
$feedback = $INDEX_OF[$data[$i] ^ $parity[0]];
|
||||
if($feedback != $A0) {
|
||||
// feedback term is non-zero
|
||||
|
||||
// This line is unnecessary when GENPOLY[NROOTS] is unity, as it must
|
||||
// always be for the polynomials constructed by init_rs()
|
||||
$feedback = $this->modnn($NN - $GENPOLY[$NROOTS] + $feedback);
|
||||
|
||||
for($j=1;$j<$NROOTS;$j++) {
|
||||
$parity[$j] ^= $ALPHA_TO[$this->modnn($feedback + $GENPOLY[$NROOTS-$j])];
|
||||
}
|
||||
}
|
||||
|
||||
// Shift
|
||||
array_shift($parity);
|
||||
if($feedback != $A0) {
|
||||
array_push($parity, $ALPHA_TO[$this->modnn($feedback + $GENPOLY[0])]);
|
||||
} else {
|
||||
array_push($parity, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//##########################################################################
|
||||
|
||||
class QRrs {
|
||||
|
||||
public static $items = array();
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
public static function init_rs($symsize, $gfpoly, $fcr, $prim, $nroots, $pad)
|
||||
{
|
||||
foreach(self::$items as $rs) {
|
||||
if($rs->pad != $pad) continue;
|
||||
if($rs->nroots != $nroots) continue;
|
||||
if($rs->mm != $symsize) continue;
|
||||
if($rs->gfpoly != $gfpoly) continue;
|
||||
if($rs->fcr != $fcr) continue;
|
||||
if($rs->prim != $prim) continue;
|
||||
|
||||
return $rs;
|
||||
}
|
||||
|
||||
$rs = QRrsItem::init_rs_char($symsize, $gfpoly, $fcr, $prim, $nroots, $pad);
|
||||
array_unshift(self::$items, $rs);
|
||||
|
||||
return $rs;
|
||||
}
|
||||
}
|
|
@ -1,311 +1,311 @@
|
|||
<?php
|
||||
/*
|
||||
* PHP QR Code encoder
|
||||
*
|
||||
* Input splitting classes
|
||||
*
|
||||
* Based on libqrencode C library distributed under LGPL 2.1
|
||||
* Copyright (C) 2006, 2007, 2008, 2009 Kentaro Fukuchi <fukuchi@megaui.net>
|
||||
*
|
||||
* PHP QR Code is distributed under LGPL 3
|
||||
* Copyright (C) 2010 Dominik Dzienia <deltalab at poczta dot fm>
|
||||
*
|
||||
* The following data / specifications are taken from
|
||||
* "Two dimensional symbol -- QR-code -- Basic Specification" (JIS X0510:2004)
|
||||
* or
|
||||
* "Automatic identification and data capture techniques --
|
||||
* QR Code 2005 bar code symbology specification" (ISO/IEC 18004:2006)
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 3 of the License, or any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
class QRsplit {
|
||||
|
||||
public $dataStr = '';
|
||||
public $input;
|
||||
public $modeHint;
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
public function __construct($dataStr, $input, $modeHint)
|
||||
{
|
||||
$this->dataStr = $dataStr;
|
||||
$this->input = $input;
|
||||
$this->modeHint = $modeHint;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
public static function isdigitat($str, $pos)
|
||||
{
|
||||
if ($pos >= strlen($str))
|
||||
return false;
|
||||
|
||||
return ((ord($str[$pos]) >= ord('0'))&&(ord($str[$pos]) <= ord('9')));
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
public static function isalnumat($str, $pos)
|
||||
{
|
||||
if ($pos >= strlen($str))
|
||||
return false;
|
||||
|
||||
return (QRinput::lookAnTable(ord($str[$pos])) >= 0);
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
public function identifyMode($pos)
|
||||
{
|
||||
if ($pos >= strlen($this->dataStr))
|
||||
return QR_MODE_NUL;
|
||||
|
||||
$c = $this->dataStr[$pos];
|
||||
|
||||
if(self::isdigitat($this->dataStr, $pos)) {
|
||||
return QR_MODE_NUM;
|
||||
} else if(self::isalnumat($this->dataStr, $pos)) {
|
||||
return QR_MODE_AN;
|
||||
} else if($this->modeHint == QR_MODE_KANJI) {
|
||||
|
||||
if ($pos+1 < strlen($this->dataStr))
|
||||
{
|
||||
$d = $this->dataStr[$pos+1];
|
||||
$word = (ord($c) << 8) | ord($d);
|
||||
if(($word >= 0x8140 && $word <= 0x9ffc) || ($word >= 0xe040 && $word <= 0xebbf)) {
|
||||
return QR_MODE_KANJI;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return QR_MODE_8;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
public function eatNum()
|
||||
{
|
||||
$ln = QRspec::lengthIndicator(QR_MODE_NUM, $this->input->getVersion());
|
||||
|
||||
$p = 0;
|
||||
while(self::isdigitat($this->dataStr, $p)) {
|
||||
$p++;
|
||||
}
|
||||
|
||||
$run = $p;
|
||||
$mode = $this->identifyMode($p);
|
||||
|
||||
if($mode == QR_MODE_8) {
|
||||
$dif = QRinput::estimateBitsModeNum($run) + 4 + $ln
|
||||
+ QRinput::estimateBitsMode8(1) // + 4 + l8
|
||||
- QRinput::estimateBitsMode8($run + 1); // - 4 - l8
|
||||
if($dif > 0) {
|
||||
return $this->eat8();
|
||||
}
|
||||
}
|
||||
if($mode == QR_MODE_AN) {
|
||||
$dif = QRinput::estimateBitsModeNum($run) + 4 + $ln
|
||||
+ QRinput::estimateBitsModeAn(1) // + 4 + la
|
||||
- QRinput::estimateBitsModeAn($run + 1);// - 4 - la
|
||||
if($dif > 0) {
|
||||
return $this->eatAn();
|
||||
}
|
||||
}
|
||||
|
||||
$ret = $this->input->append(QR_MODE_NUM, $run, str_split($this->dataStr));
|
||||
if($ret < 0)
|
||||
return -1;
|
||||
|
||||
return $run;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
public function eatAn()
|
||||
{
|
||||
$la = QRspec::lengthIndicator(QR_MODE_AN, $this->input->getVersion());
|
||||
$ln = QRspec::lengthIndicator(QR_MODE_NUM, $this->input->getVersion());
|
||||
|
||||
$p = 0;
|
||||
|
||||
while(self::isalnumat($this->dataStr, $p)) {
|
||||
if(self::isdigitat($this->dataStr, $p)) {
|
||||
$q = $p;
|
||||
while(self::isdigitat($this->dataStr, $q)) {
|
||||
$q++;
|
||||
}
|
||||
|
||||
$dif = QRinput::estimateBitsModeAn($p) // + 4 + la
|
||||
+ QRinput::estimateBitsModeNum($q - $p) + 4 + $ln
|
||||
- QRinput::estimateBitsModeAn($q); // - 4 - la
|
||||
|
||||
if($dif < 0) {
|
||||
break;
|
||||
} else {
|
||||
$p = $q;
|
||||
}
|
||||
} else {
|
||||
$p++;
|
||||
}
|
||||
}
|
||||
|
||||
$run = $p;
|
||||
|
||||
if(!self::isalnumat($this->dataStr, $p)) {
|
||||
$dif = QRinput::estimateBitsModeAn($run) + 4 + $la
|
||||
+ QRinput::estimateBitsMode8(1) // + 4 + l8
|
||||
- QRinput::estimateBitsMode8($run + 1); // - 4 - l8
|
||||
if($dif > 0) {
|
||||
return $this->eat8();
|
||||
}
|
||||
}
|
||||
|
||||
$ret = $this->input->append(QR_MODE_AN, $run, str_split($this->dataStr));
|
||||
if($ret < 0)
|
||||
return -1;
|
||||
|
||||
return $run;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
public function eatKanji()
|
||||
{
|
||||
$p = 0;
|
||||
|
||||
while($this->identifyMode($p) == QR_MODE_KANJI) {
|
||||
$p += 2;
|
||||
}
|
||||
|
||||
$ret = $this->input->append(QR_MODE_KANJI, $p, str_split($this->dataStr));
|
||||
if($ret < 0)
|
||||
return -1;
|
||||
|
||||
return $ret;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
public function eat8()
|
||||
{
|
||||
$la = QRspec::lengthIndicator(QR_MODE_AN, $this->input->getVersion());
|
||||
$ln = QRspec::lengthIndicator(QR_MODE_NUM, $this->input->getVersion());
|
||||
|
||||
$p = 1;
|
||||
$dataStrLen = strlen($this->dataStr);
|
||||
|
||||
while($p < $dataStrLen) {
|
||||
|
||||
$mode = $this->identifyMode($p);
|
||||
if($mode == QR_MODE_KANJI) {
|
||||
break;
|
||||
}
|
||||
if($mode == QR_MODE_NUM) {
|
||||
$q = $p;
|
||||
while(self::isdigitat($this->dataStr, $q)) {
|
||||
$q++;
|
||||
}
|
||||
$dif = QRinput::estimateBitsMode8($p) // + 4 + l8
|
||||
+ QRinput::estimateBitsModeNum($q - $p) + 4 + $ln
|
||||
- QRinput::estimateBitsMode8($q); // - 4 - l8
|
||||
if($dif < 0) {
|
||||
break;
|
||||
} else {
|
||||
$p = $q;
|
||||
}
|
||||
} else if($mode == QR_MODE_AN) {
|
||||
$q = $p;
|
||||
while(self::isalnumat($this->dataStr, $q)) {
|
||||
$q++;
|
||||
}
|
||||
$dif = QRinput::estimateBitsMode8($p) // + 4 + l8
|
||||
+ QRinput::estimateBitsModeAn($q - $p) + 4 + $la
|
||||
- QRinput::estimateBitsMode8($q); // - 4 - l8
|
||||
if($dif < 0) {
|
||||
break;
|
||||
} else {
|
||||
$p = $q;
|
||||
}
|
||||
} else {
|
||||
$p++;
|
||||
}
|
||||
}
|
||||
|
||||
$run = $p;
|
||||
$ret = $this->input->append(QR_MODE_8, $run, str_split($this->dataStr));
|
||||
|
||||
if($ret < 0)
|
||||
return -1;
|
||||
|
||||
return $run;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
public function splitString()
|
||||
{
|
||||
while (strlen($this->dataStr) > 0)
|
||||
{
|
||||
if($this->dataStr == '')
|
||||
return 0;
|
||||
|
||||
$mode = $this->identifyMode(0);
|
||||
|
||||
switch ($mode) {
|
||||
case QR_MODE_NUM: $length = $this->eatNum(); break;
|
||||
case QR_MODE_AN: $length = $this->eatAn(); break;
|
||||
case QR_MODE_KANJI:
|
||||
if ($this->modeHint == QR_MODE_KANJI)
|
||||
$length = $this->eatKanji();
|
||||
else $length = $this->eat8();
|
||||
break;
|
||||
default: $length = $this->eat8(); break;
|
||||
|
||||
}
|
||||
|
||||
if($length == 0) return 0;
|
||||
if($length < 0) return -1;
|
||||
|
||||
$this->dataStr = substr($this->dataStr, $length);
|
||||
}
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
public function toUpper()
|
||||
{
|
||||
$stringLen = strlen($this->dataStr);
|
||||
$p = 0;
|
||||
|
||||
while ($p<$stringLen) {
|
||||
$mode = self::identifyMode(substr($this->dataStr, $p));
|
||||
if($mode == QR_MODE_KANJI) {
|
||||
$p += 2;
|
||||
} else {
|
||||
if (ord($this->dataStr[$p]) >= ord('a') && ord($this->dataStr[$p]) <= ord('z')) {
|
||||
$this->dataStr[$p] = chr(ord($this->dataStr[$p]) - 32);
|
||||
}
|
||||
$p++;
|
||||
}
|
||||
}
|
||||
|
||||
return $this->dataStr;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
public static function splitStringToQRinput($string, QRinput $input, $modeHint, $casesensitive = true)
|
||||
{
|
||||
if(is_null($string) || $string == '\0' || $string == '') {
|
||||
throw new Exception('empty string!!!');
|
||||
}
|
||||
|
||||
$split = new QRsplit($string, $input, $modeHint);
|
||||
|
||||
if(!$casesensitive)
|
||||
$split->toUpper();
|
||||
|
||||
return $split->splitString();
|
||||
}
|
||||
<?php
|
||||
/*
|
||||
* PHP QR Code encoder
|
||||
*
|
||||
* Input splitting classes
|
||||
*
|
||||
* Based on libqrencode C library distributed under LGPL 2.1
|
||||
* Copyright (C) 2006, 2007, 2008, 2009 Kentaro Fukuchi <fukuchi@megaui.net>
|
||||
*
|
||||
* PHP QR Code is distributed under LGPL 3
|
||||
* Copyright (C) 2010 Dominik Dzienia <deltalab at poczta dot fm>
|
||||
*
|
||||
* The following data / specifications are taken from
|
||||
* "Two dimensional symbol -- QR-code -- Basic Specification" (JIS X0510:2004)
|
||||
* or
|
||||
* "Automatic identification and data capture techniques --
|
||||
* QR Code 2005 bar code symbology specification" (ISO/IEC 18004:2006)
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 3 of the License, or any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
class QRsplit {
|
||||
|
||||
public $dataStr = '';
|
||||
public $input;
|
||||
public $modeHint;
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
public function __construct($dataStr, $input, $modeHint)
|
||||
{
|
||||
$this->dataStr = $dataStr;
|
||||
$this->input = $input;
|
||||
$this->modeHint = $modeHint;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
public static function isdigitat($str, $pos)
|
||||
{
|
||||
if ($pos >= strlen($str))
|
||||
return false;
|
||||
|
||||
return ((ord($str[$pos]) >= ord('0'))&&(ord($str[$pos]) <= ord('9')));
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
public static function isalnumat($str, $pos)
|
||||
{
|
||||
if ($pos >= strlen($str))
|
||||
return false;
|
||||
|
||||
return (QRinput::lookAnTable(ord($str[$pos])) >= 0);
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
public function identifyMode($pos)
|
||||
{
|
||||
if ($pos >= strlen($this->dataStr))
|
||||
return QR_MODE_NUL;
|
||||
|
||||
$c = $this->dataStr[$pos];
|
||||
|
||||
if(self::isdigitat($this->dataStr, $pos)) {
|
||||
return QR_MODE_NUM;
|
||||
} else if(self::isalnumat($this->dataStr, $pos)) {
|
||||
return QR_MODE_AN;
|
||||
} else if($this->modeHint == QR_MODE_KANJI) {
|
||||
|
||||
if ($pos+1 < strlen($this->dataStr))
|
||||
{
|
||||
$d = $this->dataStr[$pos+1];
|
||||
$word = (ord($c) << 8) | ord($d);
|
||||
if(($word >= 0x8140 && $word <= 0x9ffc) || ($word >= 0xe040 && $word <= 0xebbf)) {
|
||||
return QR_MODE_KANJI;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return QR_MODE_8;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
public function eatNum()
|
||||
{
|
||||
$ln = QRspec::lengthIndicator(QR_MODE_NUM, $this->input->getVersion());
|
||||
|
||||
$p = 0;
|
||||
while(self::isdigitat($this->dataStr, $p)) {
|
||||
$p++;
|
||||
}
|
||||
|
||||
$run = $p;
|
||||
$mode = $this->identifyMode($p);
|
||||
|
||||
if($mode == QR_MODE_8) {
|
||||
$dif = QRinput::estimateBitsModeNum($run) + 4 + $ln
|
||||
+ QRinput::estimateBitsMode8(1) // + 4 + l8
|
||||
- QRinput::estimateBitsMode8($run + 1); // - 4 - l8
|
||||
if($dif > 0) {
|
||||
return $this->eat8();
|
||||
}
|
||||
}
|
||||
if($mode == QR_MODE_AN) {
|
||||
$dif = QRinput::estimateBitsModeNum($run) + 4 + $ln
|
||||
+ QRinput::estimateBitsModeAn(1) // + 4 + la
|
||||
- QRinput::estimateBitsModeAn($run + 1);// - 4 - la
|
||||
if($dif > 0) {
|
||||
return $this->eatAn();
|
||||
}
|
||||
}
|
||||
|
||||
$ret = $this->input->append(QR_MODE_NUM, $run, str_split($this->dataStr));
|
||||
if($ret < 0)
|
||||
return -1;
|
||||
|
||||
return $run;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
public function eatAn()
|
||||
{
|
||||
$la = QRspec::lengthIndicator(QR_MODE_AN, $this->input->getVersion());
|
||||
$ln = QRspec::lengthIndicator(QR_MODE_NUM, $this->input->getVersion());
|
||||
|
||||
$p = 0;
|
||||
|
||||
while(self::isalnumat($this->dataStr, $p)) {
|
||||
if(self::isdigitat($this->dataStr, $p)) {
|
||||
$q = $p;
|
||||
while(self::isdigitat($this->dataStr, $q)) {
|
||||
$q++;
|
||||
}
|
||||
|
||||
$dif = QRinput::estimateBitsModeAn($p) // + 4 + la
|
||||
+ QRinput::estimateBitsModeNum($q - $p) + 4 + $ln
|
||||
- QRinput::estimateBitsModeAn($q); // - 4 - la
|
||||
|
||||
if($dif < 0) {
|
||||
break;
|
||||
} else {
|
||||
$p = $q;
|
||||
}
|
||||
} else {
|
||||
$p++;
|
||||
}
|
||||
}
|
||||
|
||||
$run = $p;
|
||||
|
||||
if(!self::isalnumat($this->dataStr, $p)) {
|
||||
$dif = QRinput::estimateBitsModeAn($run) + 4 + $la
|
||||
+ QRinput::estimateBitsMode8(1) // + 4 + l8
|
||||
- QRinput::estimateBitsMode8($run + 1); // - 4 - l8
|
||||
if($dif > 0) {
|
||||
return $this->eat8();
|
||||
}
|
||||
}
|
||||
|
||||
$ret = $this->input->append(QR_MODE_AN, $run, str_split($this->dataStr));
|
||||
if($ret < 0)
|
||||
return -1;
|
||||
|
||||
return $run;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
public function eatKanji()
|
||||
{
|
||||
$p = 0;
|
||||
|
||||
while($this->identifyMode($p) == QR_MODE_KANJI) {
|
||||
$p += 2;
|
||||
}
|
||||
|
||||
$ret = $this->input->append(QR_MODE_KANJI, $p, str_split($this->dataStr));
|
||||
if($ret < 0)
|
||||
return -1;
|
||||
|
||||
return $ret;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
public function eat8()
|
||||
{
|
||||
$la = QRspec::lengthIndicator(QR_MODE_AN, $this->input->getVersion());
|
||||
$ln = QRspec::lengthIndicator(QR_MODE_NUM, $this->input->getVersion());
|
||||
|
||||
$p = 1;
|
||||
$dataStrLen = strlen($this->dataStr);
|
||||
|
||||
while($p < $dataStrLen) {
|
||||
|
||||
$mode = $this->identifyMode($p);
|
||||
if($mode == QR_MODE_KANJI) {
|
||||
break;
|
||||
}
|
||||
if($mode == QR_MODE_NUM) {
|
||||
$q = $p;
|
||||
while(self::isdigitat($this->dataStr, $q)) {
|
||||
$q++;
|
||||
}
|
||||
$dif = QRinput::estimateBitsMode8($p) // + 4 + l8
|
||||
+ QRinput::estimateBitsModeNum($q - $p) + 4 + $ln
|
||||
- QRinput::estimateBitsMode8($q); // - 4 - l8
|
||||
if($dif < 0) {
|
||||
break;
|
||||
} else {
|
||||
$p = $q;
|
||||
}
|
||||
} else if($mode == QR_MODE_AN) {
|
||||
$q = $p;
|
||||
while(self::isalnumat($this->dataStr, $q)) {
|
||||
$q++;
|
||||
}
|
||||
$dif = QRinput::estimateBitsMode8($p) // + 4 + l8
|
||||
+ QRinput::estimateBitsModeAn($q - $p) + 4 + $la
|
||||
- QRinput::estimateBitsMode8($q); // - 4 - l8
|
||||
if($dif < 0) {
|
||||
break;
|
||||
} else {
|
||||
$p = $q;
|
||||
}
|
||||
} else {
|
||||
$p++;
|
||||
}
|
||||
}
|
||||
|
||||
$run = $p;
|
||||
$ret = $this->input->append(QR_MODE_8, $run, str_split($this->dataStr));
|
||||
|
||||
if($ret < 0)
|
||||
return -1;
|
||||
|
||||
return $run;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
public function splitString()
|
||||
{
|
||||
while (strlen($this->dataStr) > 0)
|
||||
{
|
||||
if($this->dataStr == '')
|
||||
return 0;
|
||||
|
||||
$mode = $this->identifyMode(0);
|
||||
|
||||
switch ($mode) {
|
||||
case QR_MODE_NUM: $length = $this->eatNum(); break;
|
||||
case QR_MODE_AN: $length = $this->eatAn(); break;
|
||||
case QR_MODE_KANJI:
|
||||
if ($this->modeHint == QR_MODE_KANJI)
|
||||
$length = $this->eatKanji();
|
||||
else $length = $this->eat8();
|
||||
break;
|
||||
default: $length = $this->eat8(); break;
|
||||
|
||||
}
|
||||
|
||||
if($length == 0) return 0;
|
||||
if($length < 0) return -1;
|
||||
|
||||
$this->dataStr = substr($this->dataStr, $length);
|
||||
}
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
public function toUpper()
|
||||
{
|
||||
$stringLen = strlen($this->dataStr);
|
||||
$p = 0;
|
||||
|
||||
while ($p<$stringLen) {
|
||||
$mode = self::identifyMode(substr($this->dataStr, $p));
|
||||
if($mode == QR_MODE_KANJI) {
|
||||
$p += 2;
|
||||
} else {
|
||||
if (ord($this->dataStr[$p]) >= ord('a') && ord($this->dataStr[$p]) <= ord('z')) {
|
||||
$this->dataStr[$p] = chr(ord($this->dataStr[$p]) - 32);
|
||||
}
|
||||
$p++;
|
||||
}
|
||||
}
|
||||
|
||||
return $this->dataStr;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
public static function splitStringToQRinput($string, QRinput $input, $modeHint, $casesensitive = true)
|
||||
{
|
||||
if(is_null($string) || $string == '\0' || $string == '') {
|
||||
throw new Exception('empty string!!!');
|
||||
}
|
||||
|
||||
$split = new QRsplit($string, $input, $modeHint);
|
||||
|
||||
if(!$casesensitive)
|
||||
$split->toUpper();
|
||||
|
||||
return $split->splitString();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,172 +1,172 @@
|
|||
<?php
|
||||
/*
|
||||
* PHP QR Code encoder
|
||||
*
|
||||
* Toolset, handy and debug utilites.
|
||||
*
|
||||
* PHP QR Code is distributed under LGPL 3
|
||||
* Copyright (C) 2010 Dominik Dzienia <deltalab at poczta dot fm>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 3 of the License, or any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
class QRtools {
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
public static function binarize($frame)
|
||||
{
|
||||
$len = count($frame);
|
||||
foreach ($frame as &$frameLine) {
|
||||
|
||||
for($i=0; $i<$len; $i++) {
|
||||
$frameLine[$i] = (ord($frameLine[$i])&1)?'1':'0';
|
||||
}
|
||||
}
|
||||
|
||||
return $frame;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
public static function tcpdfBarcodeArray($code, $mode = 'QR,L', $tcPdfVersion = '4.5.037')
|
||||
{
|
||||
$barcode_array = array();
|
||||
|
||||
if (!is_array($mode))
|
||||
$mode = explode(',', $mode);
|
||||
|
||||
$eccLevel = 'L';
|
||||
|
||||
if (count($mode) > 1) {
|
||||
$eccLevel = $mode[1];
|
||||
}
|
||||
|
||||
$qrTab = QRcode::text($code, false, $eccLevel);
|
||||
$size = count($qrTab);
|
||||
|
||||
$barcode_array['num_rows'] = $size;
|
||||
$barcode_array['num_cols'] = $size;
|
||||
$barcode_array['bcode'] = array();
|
||||
|
||||
foreach ($qrTab as $line) {
|
||||
$arrAdd = array();
|
||||
foreach(str_split($line) as $char)
|
||||
$arrAdd[] = ($char=='1')?1:0;
|
||||
$barcode_array['bcode'][] = $arrAdd;
|
||||
}
|
||||
|
||||
return $barcode_array;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
public static function clearCache()
|
||||
{
|
||||
self::$frames = array();
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
public static function buildCache()
|
||||
{
|
||||
QRtools::markTime('before_build_cache');
|
||||
|
||||
$mask = new QRmask();
|
||||
for ($a=1; $a <= QRSPEC_VERSION_MAX; $a++) {
|
||||
$frame = QRspec::newFrame($a);
|
||||
if (QR_IMAGE) {
|
||||
$fileName = QR_CACHE_DIR.'frame_'.$a.'.png';
|
||||
QRimage::png(self::binarize($frame), $fileName, 1, 0);
|
||||
}
|
||||
|
||||
$width = count($frame);
|
||||
$bitMask = array_fill(0, $width, array_fill(0, $width, 0));
|
||||
for ($maskNo=0; $maskNo<8; $maskNo++)
|
||||
$mask->makeMaskNo($maskNo, $width, $frame, $bitMask, true);
|
||||
}
|
||||
|
||||
QRtools::markTime('after_build_cache');
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
public static function log($outfile, $err)
|
||||
{
|
||||
if (QR_LOG_DIR !== false) {
|
||||
if ($err != '') {
|
||||
if ($outfile !== false) {
|
||||
file_put_contents(QR_LOG_DIR.basename($outfile).'-errors.txt', date('Y-m-d H:i:s').': '.$err, FILE_APPEND);
|
||||
} else {
|
||||
file_put_contents(QR_LOG_DIR.'errors.txt', date('Y-m-d H:i:s').': '.$err, FILE_APPEND);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
public static function dumpMask($frame)
|
||||
{
|
||||
$width = count($frame);
|
||||
for($y=0;$y<$width;$y++) {
|
||||
for($x=0;$x<$width;$x++) {
|
||||
echo ord($frame[$y][$x]).',';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
public static function markTime($markerId)
|
||||
{
|
||||
list($usec, $sec) = explode(" ", microtime());
|
||||
$time = ((float)$usec + (float)$sec);
|
||||
|
||||
if (!isset($GLOBALS['qr_time_bench']))
|
||||
$GLOBALS['qr_time_bench'] = array();
|
||||
|
||||
$GLOBALS['qr_time_bench'][$markerId] = $time;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
public static function timeBenchmark()
|
||||
{
|
||||
self::markTime('finish');
|
||||
|
||||
$lastTime = 0;
|
||||
$startTime = 0;
|
||||
$p = 0;
|
||||
|
||||
echo '<table cellpadding="3" cellspacing="1">
|
||||
<thead><tr style="border-bottom:1px solid silver"><td colspan="2" style="text-align:center">BENCHMARK</td></tr></thead>
|
||||
<tbody>';
|
||||
|
||||
foreach($GLOBALS['qr_time_bench'] as $markerId=>$thisTime) {
|
||||
if ($p > 0) {
|
||||
echo '<tr><th style="text-align:right">till '.$markerId.': </th><td>'.number_format($thisTime-$lastTime, 6).'s</td></tr>';
|
||||
} else {
|
||||
$startTime = $thisTime;
|
||||
}
|
||||
|
||||
$p++;
|
||||
$lastTime = $thisTime;
|
||||
}
|
||||
|
||||
echo '</tbody><tfoot>
|
||||
<tr style="border-top:2px solid black"><th style="text-align:right">TOTAL: </th><td>'.number_format($lastTime-$startTime, 6).'s</td></tr>
|
||||
</tfoot>
|
||||
</table>';
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
//##########################################################################
|
||||
|
||||
QRtools::markTime('start');
|
||||
<?php
|
||||
/*
|
||||
* PHP QR Code encoder
|
||||
*
|
||||
* Toolset, handy and debug utilites.
|
||||
*
|
||||
* PHP QR Code is distributed under LGPL 3
|
||||
* Copyright (C) 2010 Dominik Dzienia <deltalab at poczta dot fm>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 3 of the License, or any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
class QRtools {
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
public static function binarize($frame)
|
||||
{
|
||||
$len = count($frame);
|
||||
foreach ($frame as &$frameLine) {
|
||||
|
||||
for($i=0; $i<$len; $i++) {
|
||||
$frameLine[$i] = (ord($frameLine[$i])&1)?'1':'0';
|
||||
}
|
||||
}
|
||||
|
||||
return $frame;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
public static function tcpdfBarcodeArray($code, $mode = 'QR,L', $tcPdfVersion = '4.5.037')
|
||||
{
|
||||
$barcode_array = array();
|
||||
|
||||
if (!is_array($mode))
|
||||
$mode = explode(',', $mode);
|
||||
|
||||
$eccLevel = 'L';
|
||||
|
||||
if (count($mode) > 1) {
|
||||
$eccLevel = $mode[1];
|
||||
}
|
||||
|
||||
$qrTab = QRcode::text($code, false, $eccLevel);
|
||||
$size = count($qrTab);
|
||||
|
||||
$barcode_array['num_rows'] = $size;
|
||||
$barcode_array['num_cols'] = $size;
|
||||
$barcode_array['bcode'] = array();
|
||||
|
||||
foreach ($qrTab as $line) {
|
||||
$arrAdd = array();
|
||||
foreach(str_split($line) as $char)
|
||||
$arrAdd[] = ($char=='1')?1:0;
|
||||
$barcode_array['bcode'][] = $arrAdd;
|
||||
}
|
||||
|
||||
return $barcode_array;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
public static function clearCache()
|
||||
{
|
||||
self::$frames = array();
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
public static function buildCache()
|
||||
{
|
||||
QRtools::markTime('before_build_cache');
|
||||
|
||||
$mask = new QRmask();
|
||||
for ($a=1; $a <= QRSPEC_VERSION_MAX; $a++) {
|
||||
$frame = QRspec::newFrame($a);
|
||||
if (QR_IMAGE) {
|
||||
$fileName = QR_CACHE_DIR.'frame_'.$a.'.png';
|
||||
QRimage::png(self::binarize($frame), $fileName, 1, 0);
|
||||
}
|
||||
|
||||
$width = count($frame);
|
||||
$bitMask = array_fill(0, $width, array_fill(0, $width, 0));
|
||||
for ($maskNo=0; $maskNo<8; $maskNo++)
|
||||
$mask->makeMaskNo($maskNo, $width, $frame, $bitMask, true);
|
||||
}
|
||||
|
||||
QRtools::markTime('after_build_cache');
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
public static function log($outfile, $err)
|
||||
{
|
||||
if (QR_LOG_DIR !== false) {
|
||||
if ($err != '') {
|
||||
if ($outfile !== false) {
|
||||
file_put_contents(QR_LOG_DIR.basename($outfile).'-errors.txt', date('Y-m-d H:i:s').': '.$err, FILE_APPEND);
|
||||
} else {
|
||||
file_put_contents(QR_LOG_DIR.'errors.txt', date('Y-m-d H:i:s').': '.$err, FILE_APPEND);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
public static function dumpMask($frame)
|
||||
{
|
||||
$width = count($frame);
|
||||
for($y=0;$y<$width;$y++) {
|
||||
for($x=0;$x<$width;$x++) {
|
||||
echo ord($frame[$y][$x]).',';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
public static function markTime($markerId)
|
||||
{
|
||||
list($usec, $sec) = explode(" ", microtime());
|
||||
$time = ((float)$usec + (float)$sec);
|
||||
|
||||
if (!isset($GLOBALS['qr_time_bench']))
|
||||
$GLOBALS['qr_time_bench'] = array();
|
||||
|
||||
$GLOBALS['qr_time_bench'][$markerId] = $time;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
public static function timeBenchmark()
|
||||
{
|
||||
self::markTime('finish');
|
||||
|
||||
$lastTime = 0;
|
||||
$startTime = 0;
|
||||
$p = 0;
|
||||
|
||||
echo '<table cellpadding="3" cellspacing="1">
|
||||
<thead><tr style="border-bottom:1px solid silver"><td colspan="2" style="text-align:center">BENCHMARK</td></tr></thead>
|
||||
<tbody>';
|
||||
|
||||
foreach($GLOBALS['qr_time_bench'] as $markerId=>$thisTime) {
|
||||
if ($p > 0) {
|
||||
echo '<tr><th style="text-align:right">till '.$markerId.': </th><td>'.number_format($thisTime-$lastTime, 6).'s</td></tr>';
|
||||
} else {
|
||||
$startTime = $thisTime;
|
||||
}
|
||||
|
||||
$p++;
|
||||
$lastTime = $thisTime;
|
||||
}
|
||||
|
||||
echo '</tbody><tfoot>
|
||||
<tr style="border-top:2px solid black"><th style="text-align:right">TOTAL: </th><td>'.number_format($lastTime-$startTime, 6).'s</td></tr>
|
||||
</tfoot>
|
||||
</table>';
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
//##########################################################################
|
||||
|
||||
QRtools::markTime('start');
|
||||
|
|
@ -1,2 +1,2 @@
|
|||
php ./merge.php
|
||||
php ./merge.php
|
||||
pause
|
|
@ -1,70 +1,70 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* PHP QR Code encoder
|
||||
*
|
||||
* Tool for merging all library files into one, simpler to incorporate.
|
||||
*
|
||||
* MAKE SURE THAT RESULTING PHPQRCode.php (and its dir) ARE WRITABLE!
|
||||
*
|
||||
* PHP QR Code is distributed under LGPL 3
|
||||
* Copyright (C) 2010 Dominik Dzienia <deltalab at poczta dot fm>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 3 of the License, or any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
$QR_BASEDIR = dirname(__FILE__).DIRECTORY_SEPARATOR.'..'.DIRECTORY_SEPARATOR;
|
||||
$QR_TOOLSDIR = dirname(__FILE__).DIRECTORY_SEPARATOR;
|
||||
|
||||
$outputFile = $QR_BASEDIR.'phpqrcode.php';
|
||||
|
||||
// Required libs
|
||||
|
||||
$fileList = array(
|
||||
$QR_BASEDIR.'qrconst.php',
|
||||
$QR_TOOLSDIR.'merged_config.php',
|
||||
$QR_BASEDIR.'qrtools.php',
|
||||
$QR_BASEDIR.'qrspec.php',
|
||||
$QR_BASEDIR.'qrimage.php',
|
||||
$QR_BASEDIR.'qrinput.php',
|
||||
$QR_BASEDIR.'qrbitstream.php',
|
||||
$QR_BASEDIR.'qrsplit.php',
|
||||
$QR_BASEDIR.'qrrscode.php',
|
||||
$QR_BASEDIR.'qrmask.php',
|
||||
$QR_BASEDIR.'qrencode.php'
|
||||
);
|
||||
|
||||
$headerFile = $QR_TOOLSDIR.'merged_header.php';
|
||||
$versionFile = $QR_BASEDIR.'VERSION';
|
||||
|
||||
$outputCode = '';
|
||||
|
||||
foreach($fileList as $fileName) {
|
||||
$outputCode .= "\n\n".'//---- '.basename($fileName).' -----------------------------'."\n\n";
|
||||
$anotherCode = file_get_contents($fileName);
|
||||
$anotherCode = preg_replace ('/^<\?php/', '', $anotherCode);
|
||||
$anotherCode = preg_replace ('/\?>\*$/', '', $anotherCode);
|
||||
$outputCode .= "\n\n".$anotherCode."\n\n";
|
||||
}
|
||||
|
||||
$versionDataEx = explode("\n", file_get_contents($versionFile));
|
||||
|
||||
$outputContents = file_get_contents($headerFile);
|
||||
$outputContents .= "\n\n/*\n * Version: ".trim($versionDataEx[0])."\n * Build: ".trim($versionDataEx[1])."\n */\n\n";
|
||||
$outputContents .= $outputCode;
|
||||
|
||||
file_put_contents($outputFile, $outputContents);
|
||||
|
||||
<?php
|
||||
|
||||
/*
|
||||
* PHP QR Code encoder
|
||||
*
|
||||
* Tool for merging all library files into one, simpler to incorporate.
|
||||
*
|
||||
* MAKE SURE THAT RESULTING PHPQRCode.php (and its dir) ARE WRITABLE!
|
||||
*
|
||||
* PHP QR Code is distributed under LGPL 3
|
||||
* Copyright (C) 2010 Dominik Dzienia <deltalab at poczta dot fm>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 3 of the License, or any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
$QR_BASEDIR = dirname(__FILE__).DIRECTORY_SEPARATOR.'..'.DIRECTORY_SEPARATOR;
|
||||
$QR_TOOLSDIR = dirname(__FILE__).DIRECTORY_SEPARATOR;
|
||||
|
||||
$outputFile = $QR_BASEDIR.'phpqrcode.php';
|
||||
|
||||
// Required libs
|
||||
|
||||
$fileList = array(
|
||||
$QR_BASEDIR.'qrconst.php',
|
||||
$QR_TOOLSDIR.'merged_config.php',
|
||||
$QR_BASEDIR.'qrtools.php',
|
||||
$QR_BASEDIR.'qrspec.php',
|
||||
$QR_BASEDIR.'qrimage.php',
|
||||
$QR_BASEDIR.'qrinput.php',
|
||||
$QR_BASEDIR.'qrbitstream.php',
|
||||
$QR_BASEDIR.'qrsplit.php',
|
||||
$QR_BASEDIR.'qrrscode.php',
|
||||
$QR_BASEDIR.'qrmask.php',
|
||||
$QR_BASEDIR.'qrencode.php'
|
||||
);
|
||||
|
||||
$headerFile = $QR_TOOLSDIR.'merged_header.php';
|
||||
$versionFile = $QR_BASEDIR.'VERSION';
|
||||
|
||||
$outputCode = '';
|
||||
|
||||
foreach($fileList as $fileName) {
|
||||
$outputCode .= "\n\n".'//---- '.basename($fileName).' -----------------------------'."\n\n";
|
||||
$anotherCode = file_get_contents($fileName);
|
||||
$anotherCode = preg_replace ('/^<\?php/', '', $anotherCode);
|
||||
$anotherCode = preg_replace ('/\?>\*$/', '', $anotherCode);
|
||||
$outputCode .= "\n\n".$anotherCode."\n\n";
|
||||
}
|
||||
|
||||
$versionDataEx = explode("\n", file_get_contents($versionFile));
|
||||
|
||||
$outputContents = file_get_contents($headerFile);
|
||||
$outputContents .= "\n\n/*\n * Version: ".trim($versionDataEx[0])."\n * Build: ".trim($versionDataEx[1])."\n */\n\n";
|
||||
$outputContents .= $outputCode;
|
||||
|
||||
file_put_contents($outputFile, $outputContents);
|
||||
|
||||
|
|
@ -1,2 +1,2 @@
|
|||
#!/bin/sh
|
||||
#!/bin/sh
|
||||
php ./merge.php
|
|
@ -1,17 +1,17 @@
|
|||
<?php
|
||||
/*
|
||||
* PHP QR Code encoder
|
||||
*
|
||||
* Config file, tuned-up for merged verion
|
||||
*/
|
||||
|
||||
define('QR_CACHEABLE', false); // use cache - more disk reads but less CPU power, masks and format templates are stored there
|
||||
define('QR_CACHE_DIR', false); // used when QR_CACHEABLE === true
|
||||
define('QR_LOG_DIR', false); // default error logs dir
|
||||
|
||||
define('QR_FIND_BEST_MASK', true); // if true, estimates best mask (spec. default, but extremally slow; set to false to significant performance boost but (propably) worst quality code
|
||||
define('QR_FIND_FROM_RANDOM', 2); // if false, checks all masks available, otherwise value tells count of masks need to be checked, mask id are got randomly
|
||||
define('QR_DEFAULT_MASK', 2); // when QR_FIND_BEST_MASK === false
|
||||
|
||||
define('QR_PNG_MAXIMUM_SIZE', 1024); // maximum allowed png image width (in pixels), tune to make sure GD and PHP can handle such big images
|
||||
<?php
|
||||
/*
|
||||
* PHP QR Code encoder
|
||||
*
|
||||
* Config file, tuned-up for merged verion
|
||||
*/
|
||||
|
||||
define('QR_CACHEABLE', false); // use cache - more disk reads but less CPU power, masks and format templates are stored there
|
||||
define('QR_CACHE_DIR', false); // used when QR_CACHEABLE === true
|
||||
define('QR_LOG_DIR', false); // default error logs dir
|
||||
|
||||
define('QR_FIND_BEST_MASK', true); // if true, estimates best mask (spec. default, but extremally slow; set to false to significant performance boost but (propably) worst quality code
|
||||
define('QR_FIND_FROM_RANDOM', 2); // if false, checks all masks available, otherwise value tells count of masks need to be checked, mask id are got randomly
|
||||
define('QR_DEFAULT_MASK', 2); // when QR_FIND_BEST_MASK === false
|
||||
|
||||
define('QR_PNG_MAXIMUM_SIZE', 1024); // maximum allowed png image width (in pixels), tune to make sure GD and PHP can handle such big images
|
||||
|
|
@ -1,36 +1,36 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* PHP QR Code encoder
|
||||
*
|
||||
* This file contains MERGED version of PHP QR Code library.
|
||||
* It was auto-generated from full version for your convenience.
|
||||
*
|
||||
* This merged version was configured to not requre any external files,
|
||||
* with disabled cache, error loging and weker but faster mask matching.
|
||||
* If you need tune it up please use non-merged version.
|
||||
*
|
||||
* For full version, documentation, examples of use please visit:
|
||||
*
|
||||
* http://phpqrcode.sourceforge.net/
|
||||
* https://sourceforge.net/projects/phpqrcode/
|
||||
*
|
||||
* PHP QR Code is distributed under LGPL 3
|
||||
* Copyright (C) 2010 Dominik Dzienia <deltalab at poczta dot fm>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 3 of the License, or any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
<?php
|
||||
|
||||
/*
|
||||
* PHP QR Code encoder
|
||||
*
|
||||
* This file contains MERGED version of PHP QR Code library.
|
||||
* It was auto-generated from full version for your convenience.
|
||||
*
|
||||
* This merged version was configured to not requre any external files,
|
||||
* with disabled cache, error loging and weker but faster mask matching.
|
||||
* If you need tune it up please use non-merged version.
|
||||
*
|
||||
* For full version, documentation, examples of use please visit:
|
||||
*
|
||||
* http://phpqrcode.sourceforge.net/
|
||||
* https://sourceforge.net/projects/phpqrcode/
|
||||
*
|
||||
* PHP QR Code is distributed under LGPL 3
|
||||
* Copyright (C) 2010 Dominik Dzienia <deltalab at poczta dot fm>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 3 of the License, or any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
|