diff --git a/boot.php b/boot.php
index b169efd7e..eb91b26ba 100644
--- a/boot.php
+++ b/boot.php
@@ -38,7 +38,7 @@ define ( 'FRIENDICA_PLATFORM', 'Friendica');
define ( 'FRIENDICA_CODENAME', 'Asparagus');
define ( 'FRIENDICA_VERSION', '3.5.1-dev' );
define ( 'DFRN_PROTOCOL_VERSION', '2.23' );
-define ( 'DB_UPDATE_VERSION', 1207 );
+define ( 'DB_UPDATE_VERSION', 1208 );
/**
* @brief Constant with a HTML line break.
@@ -785,60 +785,100 @@ class App {
return($this->scheme);
}
+ /**
+ * @brief Retrieves the Friendica instance base URL
+ *
+ * This function assembles the base URL from multiple parts:
+ * - Protocol is determined either by the request or a combination of
+ * system.ssl_policy and the $ssl parameter.
+ * - Host name is determined either by system.hostname or inferred from request
+ * - Path is inferred from SCRIPT_NAME
+ *
+ * Caches the result (depending on $ssl value) for performance.
+ *
+ * Note: $ssl parameter value doesn't directly correlate with the resulting protocol
+ *
+ * @param bool $ssl Whether to append http or https under SSL_POLICY_SELFSIGN
+ * @return string Friendica server base URL
+ */
function get_baseurl($ssl = false) {
// Is the function called statically?
- if (!is_object($this))
- return(self::$a->get_baseurl($ssl));
+ if (!is_object($this)) {
+ return self::$a->get_baseurl($ssl);
+ }
+
+ // Arbitrary values, the resulting url protocol can be different
+ $cache_index = $ssl ? 'https' : 'http';
+
+ // Cached value found, nothing to process
+ if (isset($this->baseurl[$cache_index])) {
+ return $this->baseurl[$cache_index];
+ }
$scheme = $this->scheme;
- if((x($this->config,'system')) && (x($this->config['system'],'ssl_policy'))) {
- if(intval($this->config['system']['ssl_policy']) === intval(SSL_POLICY_FULL))
+ if ((x($this->config, 'system')) && (x($this->config['system'], 'ssl_policy'))) {
+ if (intval($this->config['system']['ssl_policy']) === SSL_POLICY_FULL) {
$scheme = 'https';
+ }
// Basically, we have $ssl = true on any links which can only be seen by a logged in user
// (and also the login link). Anything seen by an outsider will have it turned off.
- if($this->config['system']['ssl_policy'] == SSL_POLICY_SELFSIGN) {
- if($ssl)
+ if ($this->config['system']['ssl_policy'] == SSL_POLICY_SELFSIGN) {
+ if ($ssl) {
$scheme = 'https';
- else
+ } else {
$scheme = 'http';
+ }
}
}
- if (get_config('config','hostname') != "")
- $this->hostname = get_config('config','hostname');
+ if (get_config('config', 'hostname') != '') {
+ $this->hostname = get_config('config', 'hostname');
+ }
- $this->baseurl = $scheme . "://" . $this->hostname . ((isset($this->path) && strlen($this->path)) ? '/' . $this->path : '' );
- return $this->baseurl;
+ $this->baseurl[$cache_index] = $scheme . "://" . $this->hostname . ((isset($this->path) && strlen($this->path)) ? '/' . $this->path : '' );
+
+ return $this->baseurl[$cache_index];
}
+ /**
+ * @brief Initializes the baseurl components
+ *
+ * Clears the baseurl cache to prevent inconstistencies
+ *
+ * @param string $url
+ */
function set_baseurl($url) {
$parsed = @parse_url($url);
- $this->baseurl = $url;
+ $this->baseurl = [];
if($parsed) {
$this->scheme = $parsed['scheme'];
$hostname = $parsed['host'];
- if(x($parsed,'port'))
+ if (x($parsed, 'port')) {
$hostname .= ':' . $parsed['port'];
- if(x($parsed,'path'))
- $this->path = trim($parsed['path'],'\\/');
+ }
+ if (x($parsed, 'path')) {
+ $this->path = trim($parsed['path'], '\\/');
+ }
- if (file_exists(".htpreconfig.php"))
+ if (file_exists(".htpreconfig.php")) {
@include(".htpreconfig.php");
+ }
- if (get_config('config','hostname') != "")
- $this->hostname = get_config('config','hostname');
+ if (get_config('config', 'hostname') != '') {
+ $this->hostname = get_config('config', 'hostname');
+ }
- if (!isset($this->hostname) OR ($this->hostname == ""))
+ if (!isset($this->hostname) OR ($this->hostname == '')) {
$this->hostname = $hostname;
+ }
}
-
}
function get_hostname() {
diff --git a/database.sql b/database.sql
index f12746e7e..c5fd49ba0 100644
--- a/database.sql
+++ b/database.sql
@@ -655,6 +655,8 @@ CREATE TABLE IF NOT EXISTS `notify` (
`seen` tinyint(1) NOT NULL DEFAULT 0,
`verb` varchar(255) NOT NULL DEFAULT '',
`otype` varchar(16) NOT NULL DEFAULT '',
+ `name_cache` tinytext,
+ `msg_name` mediumtext,
PRIMARY KEY(`id`),
INDEX `uid` (`uid`)
) DEFAULT CHARSET=utf8mb4;
diff --git a/doc/BBCode.md b/doc/BBCode.md
index d22f7afa5..595c2da86 100644
--- a/doc/BBCode.md
+++ b/doc/BBCode.md
@@ -1,208 +1,610 @@
Friendica BBCode tags reference
========================
-* [Home](help)
+* [Creating posts](help/Text_editor)
-Inline
------
+## Inline
+
-
[u]underlined[/u]
: underlined
+
+
+ BBCode |
+ Result |
+
+
+ [b]bold[/b] |
+ bold |
+
+
+ [i]italic[/i] |
+ italic |
+
+
+ [u]underlined[/u] |
+ underlined |
+
+
+ [s]strike[/s] |
+ strike |
+
+
+ [o]overline[/o] |
+ overline |
+
+
+ [color=red]red[/color] |
+ red |
+
+
+ [url=http://www.friendica.com]Friendica[/url] |
+ Friendica |
+
+
+ [img]http://friendica.com/sites/default/files/friendika-32.png[/img] |
+ |
+
+
+ [img=64x32]http://friendica.com/sites/default/files/friendika-32.png[/img]
+ Note: provided height is simply discarded. |
+ |
+
+
+ [size=xx-small]small text[/size] |
+ small text |
+
+
+ [size=xx-large]big text[/size] |
+ big text |
+
+
+ [size=20]exact size[/size] (size can be any number, in pixel) |
+ exact size |
+
+
+ [font=serif]Serif font[/font] |
+ Serif font |
+
+
-[s]strike[/s]
: strike
+### Links
-[color=red]red[/color]
: red
+
+
+ BBCode |
+ Result |
+
+
+ [url]http://friendica.com[/url] |
+ http://friendica.com |
+
+
+ [url=http://friendica.com]Friendica[/url] |
+ Friendica |
+
+
+ [bookmark]http://friendica.com[/bookmark]
+#^[url]http://friendica.com[/url] |
+ |
+
+
+ [bookmark=http://friendica.com]Bookmark[/bookmark]
+#^[url=http://friendica.com]Bookmark[/url]
+#[url=http://friendica.com]^[/url][url=http://friendica.com]Bookmark[/url] |
+ |
+
+
+ [url=/posts/f16d77b0630f0134740c0cc47a0ea02a]Diaspora post with GUID[/url] |
+ Diaspora post with GUID |
+
+
+ #Friendica |
+ #Friendica |
+
+
+ @Mention |
+ @Mention |
+
+
+ acct:account@friendica.host.com (WebFinger) |
+ acct:account@friendica.host.com |
+
+
+ [mail]user@mail.example.com[/mail] |
+ user@mail.example.com |
+
+
+ [mail=user@mail.example.com]Send an email to User[/mail] |
+ Send an email to User |
+
+
-[url=http://www.friendica.com]Friendica[/url]
: Friendica
+## Blocks
-[img]http://friendica.com/sites/default/files/friendika-32.png[/img]
:
+
+
+ BBCode |
+ Result |
+
+
+ [p]A paragraph of text[/p] |
+ A paragraph of text |
+
+
+ Inline [code]code[/code] in a paragraph |
+ Inline code in a paragraph |
+
+
+ [code]Multi line code[/code] |
+ Multi
+line
+code |
+
+
+ [code=php]function text_highlight($s,$lang)[/code] |
+ - function text_highlight($s,$lang)
|
+
+
+ [quote]quote[/quote] |
+ quote |
+
+
+ [quote=Author]Author? Me? No, no, no...[/quote] |
+ Author wrote:Author? Me? No, no, no... |
+
+
+ [center]Centered text[/center] |
+ Centered text |
+
+
+ You should not read any further if you want to be surprised.[spoiler]There is a happy end.[/spoiler] |
+
+
+ You should not read any further if you want to be surprised.
+ Click to open/close
+ There is a happy end.
+
+
+ |
+
+
+ [spoiler=Author]Spoiler quote[/spoiler] |
+
+
+ Author wrote:
+ Click to open/close
+ Spoiler quote
+
+
+ |
+
+
+ [hr] (horizontal line) |
+
|
+
+
-[size=xx-small]small text[/size]
: small text
+### Titles
-[size=xx-large]big text[/size]
: big text
+
+
+ BBCode |
+ Result |
+
+
+ [h1]Title 1[/h1] |
+ Title 1 |
+
+
+ [h2]Title 2[/h2] |
+ Title 2 |
+
+
+ [h3]Title 3[/h3] |
+ Title 3 |
+
+
+ [h4]Title 4[/h4] |
+ Title 4 |
+
+
+ [h5]Title 5[/h5] |
+ Title 5 |
+
+
+ [h6]Title 6[/h6] |
+ Title 6 |
+
+
-[size=20]exact size[/size] (size can be any number, in pixel)
: exact size
+### Tables
+
+
+ BBCode |
+ Result |
+
+
+ [table]
+ [tr]
+ [th]Header 1[/th]
+ [th]Header 2[/th]
+ [th]Header 2[/th]
+ [/tr]
+ [tr]
+ [td]Cell 1[/td]
+ [td]Cell 2[/td]
+ [td]Cell 3[/td]
+ [/tr]
+ [tr]
+ [td]Cell 4[/td]
+ [td]Cell 5[/td]
+ [td]Cell 6[/td]
+ [/tr]
+[/table] |
+
+
+
+
+ Header 1 |
+ Header 2 |
+ Header 3 |
+
+
+ Cell 1 |
+ Cell 2 |
+ Cell 3 |
+
+
+ Cell 4 |
+ Cell 5 |
+ Cell 6 |
+
+
+
+ |
+
+
+ [table border=0] |
+
+
+
+
+ Header 1 |
+ Header 2 |
+ Header 3 |
+
+
+ Cell 1 |
+ Cell 2 |
+ Cell 3 |
+
+
+ Cell 4 |
+ Cell 5 |
+ Cell 6 |
+
+
+
+ |
+
+
+ [table border=1] |
+
+
+
+
+ Header 1 |
+ Header 2 |
+ Header 3 |
+
+
+ Cell 1 |
+ Cell 2 |
+ Cell 3 |
+
+
+ Cell 4 |
+ Cell 5 |
+ Cell 6 |
+
+
+
+ |
+
+
+### Lists
+
+
+ BBCode |
+ Result |
+
+
+ [ul]
+ [li] First list element
+ [li] Second list element
+[/ul]
+[list]
+ [*] First list element
+ [*] Second list element
+[/list] |
+
+
+ - First list element
+ - Second list element
+
+ |
+
+
+ [ol]
+ [*] First list element
+ [*] Second list element
+[/ol]
+[list=1]
+ [*] First list element
+ [*] Second list element
+[/list] |
+
+
+ - First list element
+ - Second list element
+
+ |
+
+
+ [list=]
+ [*] First list element
+ [*] Second list element
+[/list] |
+
+
+ - First list element
+ - Second list element
+
+ |
+
+
+ [list=i]
+ [*] First list element
+ [*] Second list element
+[/list] |
+
+
+ - First list element
+ - Second list element
+
+ |
+
+
+ [list=I]
+ [*] First list element
+ [*] Second list element
+[/list] |
+
+
+ - First list element
+ - Second list element
+
+ |
+
+
+ [list=a]
+ [*] First list element
+ [*] Second list element
+[/list] |
+
+
+ - First list element
+ - Second list element
+
+ |
+
+
+ [list=A]
+ [*] First list element
+ [*] Second list element
+[/list] |
+
+
+ - First list element
+ - Second list element
+
+ |
+
+
-
-
-
-Block
------
-
-[code]code[/code]
-
-code
-
-
-
-[code=php]function text_highlight($s,$lang)[/code]
-
-- function text_highlight($s,$lang)
-
-
-
-[quote]quote[/quote]
-
-quote
-
-
-
-[quote=Author]Author? Me? No, no, no...[/quote]
-
-Author wrote:Author? Me? No, no, no...
-
-
-
-[center]centered text[/center]
-
-centered text
-
-
-
-You should not read any further if you want to be surprised.[spoiler]There is a happy end.[/spoiler]
-
-You should not read any further if you want to be surprised.
*click to open/close*
-
-(The text between thhe opening and the closing of the spoiler tag will be visible once the link is clicked. So *"There is a happy end."* wont be visible until the spoiler is uncovered.)
-
-
-
-**Table**
-[table border=1]
- [tr]
- [th]Tables now[/th]
- [/tr]
- [tr]
- [td]Have headers[/td]
- [/tr]
-[/table]
-
-
-
-
-
-**List**
-
-[list]
- [*] First list element
- [*] Second list element
-[/list]
-
-- First list element
-
-- Second list element
-
-
-[list] is equivalent to [ul] (unordered list).
-
-[ol] can be used instead of [list] to show an ordered list:
-
-[ol]
- [*] First list element
- [*] Second list element
-[/ol]
-- First list element
- Second list element
-
-For more options on ordered lists, you can define the style of numeration on [list] argument:
-[list=1]
: decimal
-
-[list=i]
: lover case roman
-
-[list=I]
: upper case roman
-
-[list=a]
: lover case alphabetic
-
-[list=A]
: upper case alphabetic
-
-
-
-
-Embed
-------
+## Embed
You can embed video, audio and more in a message.
-[video]url[/video]
-[audio]url[/audio]
+
+
+ BBCode |
+ Result |
+
+
+ [video]url[/video] |
+ Where *url* can be an url to youtube, vimeo, soundcloud, or other sites wich supports oembed or opengraph specifications. |
+
+
+ [video]Video file url[/video]
+[audio]Audio file url[/audio] |
+ Full URL to an ogg/ogv/oga/ogm/webm/mp4/mp3 file. An HTML5 player will be used to show it. |
+
+
+ [youtube]Youtube URL[/youtube] |
+ Youtube video OEmbed display. May not embed an actual player. |
+
+
+ [youtube]Youtube video ID[/youtube] |
+ Youtube player iframe embed. |
+
+
+ [vimeo]Vimeo URL[/vimeo] |
+ Vimeo video OEmbed display. May not embed an actual player. |
+
+
+ [vimeo]Vimeo video ID[/vimeo] |
+ Vimeo player iframe embed. |
+
+
+ [iframe]URL[/iframe] |
+ General embed, iframe size is limited by the theme size for video players. |
+
+
+ [url]*url*[/url] |
+ If *url* supports oembed or opengraph specifications the embedded object will be shown (eg, documents from scribd).
+Page title with a link to *url* will be shown. |
+
+
-Where *url* can be an url to youtube, vimeo, soundcloud, or other sites wich supports oembed or opengraph specifications.
-*url* can be also full url to an ogg file. HTML5 tag will be used to show it.
+## Map
-[url]*url*[/url]
+This require "openstreetmap" addon version 1.3 or newer. If the addon isn't activated,
+the raw coordinates are shown instead.
-If *url* supports oembed or opengraph specifications the embedded object will be shown (eg, documents from scribd).
-Page title with a link to *url* will be shown.
+
+
+ BBCode |
+ Result |
+
+
+ [map]address[/map] |
+ Embeds a map centered on this address. |
+
+
+ [map=lat,long] |
+ Embeds a map centered on those coordinates. |
+
+
+ [map] |
+ Embeds a map centered on the post's location. |
+
+
-Map
----
+## Abstract for longer posts
-[map]address[/map]
-[map=lat,long]
+If you want to spread your post to several third party networks you can have the problem that these networks have a length limitation like on Twitter.
-You can embed maps from coordinates or addresses.
-This require "openstreetmap" addon version 1.3 or newer.
-
------------------------------------------------------------
-
-Abstract for longer posts
--------------------------
-
-If you want to spread your post to several third party networks you can have the problem that these networks have (for example) a length limitation.
-(Like on Twitter)
-
-Friendica is using a semi intelligent mechanism to generate a fitting abstract.
-But it can be interesting to define an own abstract that will only be displayed on the external network.
-This is done with the [abstract]-element.
-Example:
-
-[abstract]Totally interesting! A must-see! Please click the link![/abstract]
-I want to tell you a really boring story that you really never wanted
-to hear.
-
-Twitter would display the text "Totally interesting! A must-see! Please click the link!".
-On Friendica you would only see the text after "I want to tell you a really ..."
+Friendica is using a semi intelligent mechanism to generate a fitting abstract.
+But it can be interesting to define a custom abstract that will only be displayed on the external network.
+This is done with the [abstract]-element.
+
+
+ BBCode |
+ Result |
+
+
+ [abstract]Totally interesting! A must-see! Please click the link![/abstract]
+I want to tell you a really boring story that you really never wanted to hear. |
+ Twitter would display the text Totally interesting! A must-see! Please click the link!
+On Friendica you would only see the text after I want to tell you a really ... |
+
+
It is even possible to define abstracts for separate networks:
-
-[abstract]Hi friends Here are my newest pictures![abstract]
-[abstract=twit]Hi my dear Twitter followers. Do you want to see my new
-pictures?[abstract]
-[abstract=apdn]Helly my dear followers on ADN. I made sone new pictures
-that I wanted to share with you.[abstract]
-Today I was in the woods and took some real cool pictures ...
-
-
-For Twitter and App.net the system will use the defined abstracts.
-For other networks (e.g. when you are using the "statusnet" connector that is used to post to GNU Social) the general abstract element will be used.
+
+
+ BBCode |
+ Result |
+
+
+
+[abstract]Hi friends Here are my newest pictures![/abstract]
+[abstract=twit]Hi my dear Twitter followers. Do you want to see my new
+pictures?[/abstract]
+[abstract=apdn]Helly my dear followers on ADN. I made sone new pictures
+that I wanted to share with you.[/abstract]
+Today I was in the woods and took some real cool pictures ... |
+ For Twitter and App.net the system will use the defined abstracts.
+For other networks (e.g. when you are using the "statusnet" connector that is used to post to GNU Social) the general abstract element will be used. |
+
+
If you use (for example) the "buffer" connector to post to Facebook or Google+ you can use this element to define an abstract for a longer blogpost that you don't want to post completely to these networks.
-Networks like Facebook or Google+ aren't length limited.
-For this reason the [abstract] element isn't used.
+Networks like Facebook or Google+ aren't length limited.
+For this reason the [abstract] element isn't used.
Instead you have to name the explicit network:
-
-[abstract]These days I had a strange encounter ...[abstract]
-[abstract=goog]Helly my dear Google+ followers. You have to read my
-newest blog post![abstract]
-[abstract=face]Hello my Facebook friends. These days happened something
-really cool.[abstract]
-While taking pictures in the woods I had a really strange encounter ...
+
+
+ BBCode |
+ Result |
+
+
+
+[abstract]These days I had a strange encounter...[/abstract]
+[abstract=goog]Helly my dear Google+ followers. You have to read my newest blog post![/abstract]
+[abstract=face]Hello my Facebook friends. These days happened something really cool.[/abstract]
+While taking pictures in the woods I had a really strange encounter... |
+ Google and Facebook will show the respective abstracts while the other networks will show the default one.
+ Meanwhile, Friendica won't show any of the abstracts. |
+
+
-The [abstract] element isn't working with the native OStatus connection or with connectors where we post the HTML.
-(Like Tumblr, Wordpress or Pump.io)
+The [abstract] element isn't working with the native OStatus connection or with connectors where we post the HTML like Tumblr, Wordpress or Pump.io.
-Special
--------
+## Special
-If you need to put literal bbcode in a message, [noparse], [nobb] or [pre] are used to escape bbcode:
-
-[noparse][b]bold[/b][/noparse]
: [b]bold[/b]
+
+
+ BBCode |
+ Result |
+
+
+ If you need to put literal bbcode in a message, [noparse], [nobb] or [pre] are used to escape bbcode:
+
+ - [noparse][b]bold[/b][/noparse]
+ - [nobb][b]bold[/b][/nobb]
+ - [pre][b]bold[/b][/pre]
+
+ |
+ [b]bold[/b] |
+
+
+ [nosmile] is used to disable smilies on a post by post basis
+
+ [nosmile] ;-) :-O
+ |
+ ;-) :-O |
+
+
+ Custom inline styles
+
+[style=text-shadow: 0 0 4px #CC0000;]You can change all the CSS properties of this block.[/style] |
+ You can change all the CSS properties of this block. |
+
+
+ Custom class block
+
+[class=custom]If the class exists, this block will have the custom class style applied.[/class] |
+ <span class="custom">If the class exists, this block will have the custom class style applied.</span> |
+
+
diff --git a/doc/database/db_notify.md b/doc/database/db_notify.md
index 5ef2aa7eb..b2bae6471 100644
--- a/doc/database/db_notify.md
+++ b/doc/database/db_notify.md
@@ -1,22 +1,24 @@
Table notify
============
-| Field | Description | Type | Null | Key | Default | Extra |
-| ------ | --------------------------------- | ------------ | ---- | --- | ------------------- | --------------- |
-| id | sequential ID | int(11) | NO | PRI | NULL | auto_increment |
-| hash | | varchar(64) | NO | | | |
-| type | | int(11) | NO | | 0 | |
-| name | | varchar(255) | NO | | | |
-| url | | varchar(255) | NO | | | |
-| photo | | varchar(255) | NO | | | |
-| date | | datetime | NO | | 0000-00-00 00:00:00 | |
-| msg | | mediumtext | NO | | NULL | |
-| uid | user.id of the owner of this data | int(11) | NO | MUL | 0 | |
-| link | | varchar(255) | NO | | | |
-| parent | | int(11) | NO | | 0 | |
-| seen | | tinyint(1) | NO | | 0 | |
-| verb | | varchar(255) | NO | | | |
-| otype | | varchar(16) | NO | | | |
-| iid | item.id | int(11) | NO | | 0 | |
+| Field | Description | Type | Null | Key | Default | Extra |
+| ---------- | --------------------------------- | ------------ | ---- | --- | ------------------- | --------------- |
+| id | sequential ID | int(11) | NO | PRI | NULL | auto_increment |
+| hash | | varchar(64) | NO | | | |
+| type | | int(11) | NO | | 0 | |
+| name | | varchar(255) | NO | | | |
+| url | | varchar(255) | NO | | | |
+| photo | | varchar(255) | NO | | | |
+| date | | datetime | NO | | 0000-00-00 00:00:00 | |
+| msg | | mediumtext | YES | | NULL | |
+| uid | user.id of the owner of this data | int(11) | NO | MUL | 0 | |
+| link | | varchar(255) | NO | | | |
+| iid | item.id | int(11) | NO | | 0 | |
+| parent | | int(11) | NO | | 0 | |
+| seen | | tinyint(1) | NO | | 0 | |
+| verb | | varchar(255) | NO | | | |
+| otype | | varchar(16) | NO | | | |
+| name_cache | Cached bbcode parsing of name | tinytext | YES | | NULL | |
+| msg_cache | Cached bbcode parsing of msg | mediumtext | YES | | NULL | |
Return to [database documentation](help/database)
diff --git a/include/Photo.php b/include/Photo.php
index e734fed89..6a7cc3e52 100644
--- a/include/Photo.php
+++ b/include/Photo.php
@@ -1,133 +1,141 @@
'jpg',
- 'image/png' => 'png',
- 'image/gif' => 'gif'
- );
- } else {
- $t = array();
- $t['image/jpeg'] ='jpg';
- if (imagetypes() & IMG_PNG) $t['image/png'] = 'png';
+ /**
+ * @brief supported mimetypes and corresponding file extensions
+ */
+ static function supportedTypes() {
+ if (class_exists('Imagick')) {
+
+ // Imagick::queryFormats won't help us a lot there...
+ // At least, not yet, other parts of friendica uses this array
+ $t = array(
+ 'image/jpeg' => 'jpg',
+ 'image/png' => 'png',
+ 'image/gif' => 'gif'
+ );
+ } else {
+ $t = array();
+ $t['image/jpeg'] ='jpg';
+ if (imagetypes() & IMG_PNG) {
+ $t['image/png'] = 'png';
+ }
+ }
+
+ return $t;
}
- return $t;
- }
+ public function __construct($data, $type=null) {
+ $this->imagick = class_exists('Imagick');
+ $this->types = $this->supportedTypes();
+ if (!array_key_exists($type, $this->types)){
+ $type='image/jpeg';
+ }
+ $this->type = $type;
- public function __construct($data, $type=null) {
- $this->imagick = class_exists('Imagick');
- $this->types = $this->supportedTypes();
- if (!array_key_exists($type,$this->types)){
- $type='image/jpeg';
- }
- $this->type = $type;
-
- if($this->is_imagick() && $this->load_data($data)) {
+ if ($this->is_imagick() && $this->load_data($data)) {
return true;
} else {
// Failed to load with Imagick, fallback
$this->imagick = false;
}
return $this->load_data($data);
- }
-
- public function __destruct() {
- if($this->image) {
- if($this->is_imagick()) {
- $this->image->clear();
- $this->image->destroy();
- return;
- }
- imagedestroy($this->image);
}
- }
- public function is_imagick() {
- return $this->imagick;
- }
-
- /**
- * Maps Mime types to Imagick formats
- */
- public function get_FormatsMap() {
- $m = array(
- 'image/jpeg' => 'JPG',
- 'image/png' => 'PNG',
- 'image/gif' => 'GIF'
- );
- return $m;
- }
-
- private function load_data($data) {
- if($this->is_imagick()) {
- $this->image = new Imagick();
- try {
- $this->image->readImageBlob($data);
+ public function __destruct() {
+ if ($this->image) {
+ if ($this->is_imagick()) {
+ $this->image->clear();
+ $this->image->destroy();
+ return;
}
- catch (Exception $e) {
+ imagedestroy($this->image);
+ }
+ }
+
+ public function is_imagick() {
+ return $this->imagick;
+ }
+
+ /**
+ * @brief Maps Mime types to Imagick formats
+ * @return arr With with image formats (mime type as key)
+ */
+ public function get_FormatsMap() {
+ $m = array(
+ 'image/jpeg' => 'JPG',
+ 'image/png' => 'PNG',
+ 'image/gif' => 'GIF'
+ );
+ return $m;
+ }
+
+ private function load_data($data) {
+ if ($this->is_imagick()) {
+ $this->image = new Imagick();
+ try {
+ $this->image->readImageBlob($data);
+ } catch (Exception $e) {
// Imagick couldn't use the data
return false;
}
- /**
- * Setup the image to the format it will be saved to
- */
- $map = $this->get_FormatsMap();
- $format = $map[$type];
- $this->image->setFormat($format);
+ /*
+ * Setup the image to the format it will be saved to
+ */
+ $map = $this->get_FormatsMap();
+ $format = $map[$type];
+ $this->image->setFormat($format);
- // Always coalesce, if it is not a multi-frame image it won't hurt anyway
- $this->image = $this->image->coalesceImages();
+ // Always coalesce, if it is not a multi-frame image it won't hurt anyway
+ $this->image = $this->image->coalesceImages();
- /**
- * setup the compression here, so we'll do it only once
- */
- switch($this->getType()){
- case "image/png":
- $quality = get_config('system','png_quality');
- if((! $quality) || ($quality > 9))
- $quality = PNG_QUALITY;
- /**
- * From http://www.imagemagick.org/script/command-line-options.php#quality:
- *
- * 'For the MNG and PNG image formats, the quality value sets
- * the zlib compression level (quality / 10) and filter-type (quality % 10).
- * The default PNG "quality" is 75, which means compression level 7 with adaptive PNG filtering,
- * unless the image has a color map, in which case it means compression level 7 with no PNG filtering'
- */
- $quality = $quality * 10;
- $this->image->setCompressionQuality($quality);
- break;
- case "image/jpeg":
- $quality = get_config('system','jpeg_quality');
- if((! $quality) || ($quality > 100))
- $quality = JPEG_QUALITY;
- $this->image->setCompressionQuality($quality);
- }
+ /*
+ * setup the compression here, so we'll do it only once
+ */
+ switch($this->getType()){
+ case "image/png":
+ $quality = get_config('system', 'png_quality');
+ if ((! $quality) || ($quality > 9)) {
+ $quality = PNG_QUALITY;
+ }
+ /*
+ * From http://www.imagemagick.org/script/command-line-options.php#quality:
+ *
+ * 'For the MNG and PNG image formats, the quality value sets
+ * the zlib compression level (quality / 10) and filter-type (quality % 10).
+ * The default PNG "quality" is 75, which means compression level 7 with adaptive PNG filtering,
+ * unless the image has a color map, in which case it means compression level 7 with no PNG filtering'
+ */
+ $quality = $quality * 10;
+ $this->image->setCompressionQuality($quality);
+ break;
+ case "image/jpeg":
+ $quality = get_config('system', 'jpeg_quality');
+ if ((! $quality) || ($quality > 100)) {
+ $quality = JPEG_QUALITY;
+ }
+ $this->image->setCompressionQuality($quality);
+ }
// The 'width' and 'height' properties are only used by non-Imagick routines.
$this->width = $this->image->getImageWidth();
@@ -139,7 +147,7 @@ class Photo {
$this->valid = false;
$this->image = @imagecreatefromstring($data);
- if($this->image !== FALSE) {
+ if ($this->image !== false) {
$this->width = imagesx($this->image);
$this->height = imagesy($this->image);
$this->valid = true;
@@ -148,123 +156,125 @@ class Photo {
return true;
}
-
+
return false;
}
- public function is_valid() {
- if($this->is_imagick())
- return ($this->image !== FALSE);
- return $this->valid;
- }
-
- public function getWidth() {
- if(!$this->is_valid())
- return FALSE;
-
- if($this->is_imagick())
- return $this->image->getImageWidth();
- return $this->width;
- }
-
- public function getHeight() {
- if(!$this->is_valid())
- return FALSE;
-
- if($this->is_imagick())
- return $this->image->getImageHeight();
- return $this->height;
- }
-
- public function getImage() {
- if(!$this->is_valid())
- return FALSE;
-
- if($this->is_imagick()) {
- /* Clean it */
- $this->image = $this->image->deconstructImages();
- return $this->image;
+ public function is_valid() {
+ if ($this->is_imagick()) {
+ return ($this->image !== false);
+ }
+ return $this->valid;
}
- return $this->image;
- }
- public function getType() {
- if(!$this->is_valid())
- return FALSE;
+ public function getWidth() {
+ if (!$this->is_valid()) {
+ return false;
+ }
- return $this->type;
- }
+ if ($this->is_imagick()) {
+ return $this->image->getImageWidth();
+ }
+ return $this->width;
+ }
- public function getExt() {
- if(!$this->is_valid())
- return FALSE;
+ public function getHeight() {
+ if (!$this->is_valid()) {
+ return false;
+ }
- return $this->types[$this->getType()];
- }
+ if ($this->is_imagick()) {
+ return $this->image->getImageHeight();
+ }
+ return $this->height;
+ }
- public function scaleImage($max) {
- if(!$this->is_valid())
- return FALSE;
+ public function getImage() {
+ if (!$this->is_valid()) {
+ return false;
+ }
- $width = $this->getWidth();
- $height = $this->getHeight();
+ if ($this->is_imagick()) {
+ /* Clean it */
+ $this->image = $this->image->deconstructImages();
+ return $this->image;
+ }
+ return $this->image;
+ }
- $dest_width = $dest_height = 0;
+ public function getType() {
+ if (!$this->is_valid()) {
+ return false;
+ }
- if((! $width)|| (! $height))
- return FALSE;
+ return $this->type;
+ }
- if($width > $max && $height > $max) {
+ public function getExt() {
+ if (!$this->is_valid()) {
+ return false;
+ }
+
+ return $this->types[$this->getType()];
+ }
+
+ public function scaleImage($max) {
+ if (!$this->is_valid()) {
+ return false;
+ }
+
+ $width = $this->getWidth();
+ $height = $this->getHeight();
+
+ $dest_width = $dest_height = 0;
+
+ if ((! $width)|| (! $height)) {
+ return false;
+ }
+
+ if ($width > $max && $height > $max) {
// very tall image (greater than 16:9)
// constrain the width - let the height float.
- if((($height * 9) / 16) > $width) {
+ if ((($height * 9) / 16) > $width) {
$dest_width = $max;
- $dest_height = intval(( $height * $max ) / $width);
+ $dest_height = intval(($height * $max) / $width);
+ } elseif ($width > $height) {
+ // else constrain both dimensions
+ $dest_width = $max;
+ $dest_height = intval(($height * $max) / $width);
+ } else {
+ $dest_width = intval(($width * $max) / $height);
+ $dest_height = $max;
}
-
- // else constrain both dimensions
-
- elseif($width > $height) {
- $dest_width = $max;
- $dest_height = intval(( $height * $max ) / $width);
- }
- else {
- $dest_width = intval(( $width * $max ) / $height);
- $dest_height = $max;
- }
- }
- else {
- if( $width > $max ) {
- $dest_width = $max;
- $dest_height = intval(( $height * $max ) / $width);
- }
- else {
- if( $height > $max ) {
+ } else {
+ if ($width > $max) {
+ $dest_width = $max;
+ $dest_height = intval(($height * $max) / $width);
+ } else {
+ if ($height > $max) {
// very tall image (greater than 16:9)
// but width is OK - don't do anything
- if((($height * 9) / 16) > $width) {
+ if ((($height * 9) / 16) > $width) {
$dest_width = $width;
- $dest_height = $height;
- }
- else {
- $dest_width = intval(( $width * $max ) / $height);
- $dest_height = $max;
+ $dest_height = $height;
+ } else {
+ $dest_width = intval(($width * $max) / $height);
+ $dest_height = $max;
}
+ } else {
+ $dest_width = $width;
+ $dest_height = $height;
+ }
+ }
}
- else {
- $dest_width = $width;
- $dest_height = $height;
- }
- }
- }
- if($this->is_imagick()) {
- /**
+ if ($this->is_imagick()) {
+ /*
* If it is not animated, there will be only one iteration here,
* so don't bother checking
*/
@@ -283,234 +293,253 @@ class Photo {
$this->height = $this->image->getImageHeight();
return;
- }
-
-
- $dest = imagecreatetruecolor( $dest_width, $dest_height );
- imagealphablending($dest, false);
- imagesavealpha($dest, true);
- if ($this->type=='image/png') imagefill($dest, 0, 0, imagecolorallocatealpha($dest, 0, 0, 0, 127)); // fill with alpha
- imagecopyresampled($dest, $this->image, 0, 0, 0, 0, $dest_width, $dest_height, $width, $height);
- if($this->image)
- imagedestroy($this->image);
- $this->image = $dest;
- $this->width = imagesx($this->image);
- $this->height = imagesy($this->image);
- }
-
- public function rotate($degrees) {
- if(!$this->is_valid())
- return FALSE;
-
- if($this->is_imagick()) {
- $this->image->setFirstIterator();
- do {
- $this->image->rotateImage(new ImagickPixel(), -$degrees); // ImageMagick rotates in the opposite direction of imagerotate()
- } while ($this->image->nextImage());
- return;
- }
-
- $this->image = imagerotate($this->image,$degrees,0);
- $this->width = imagesx($this->image);
- $this->height = imagesy($this->image);
- }
-
- public function flip($horiz = true, $vert = false) {
- if(!$this->is_valid())
- return FALSE;
-
- if($this->is_imagick()) {
- $this->image->setFirstIterator();
- do {
- if($horiz) $this->image->flipImage();
- if($vert) $this->image->flopImage();
- } while ($this->image->nextImage());
- return;
- }
-
- $w = imagesx($this->image);
- $h = imagesy($this->image);
- $flipped = imagecreate($w, $h);
- if($horiz) {
- for ($x = 0; $x < $w; $x++) {
- imagecopy($flipped, $this->image, $x, 0, $w - $x - 1, 0, 1, $h);
- }
- }
- if($vert) {
- for ($y = 0; $y < $h; $y++) {
- imagecopy($flipped, $this->image, 0, $y, 0, $h - $y - 1, $w, 1);
- }
- }
- $this->image = $flipped;
- }
-
- public function orient($filename) {
- if ($this->is_imagick()) {
- // based off comment on http://php.net/manual/en/imagick.getimageorientation.php
- $orientation = $this->image->getImageOrientation();
- switch ($orientation) {
- case imagick::ORIENTATION_BOTTOMRIGHT:
- $this->image->rotateimage("#000", 180);
- break;
- case imagick::ORIENTATION_RIGHTTOP:
- $this->image->rotateimage("#000", 90);
- break;
- case imagick::ORIENTATION_LEFTBOTTOM:
- $this->image->rotateimage("#000", -90);
- break;
}
- $this->image->setImageOrientation(imagick::ORIENTATION_TOPLEFT);
- return TRUE;
- }
- // based off comment on http://php.net/manual/en/function.imagerotate.php
- if(!$this->is_valid())
- return FALSE;
-
- if( (! function_exists('exif_read_data')) || ($this->getType() !== 'image/jpeg') )
- return;
-
- $exif = @exif_read_data($filename,null,true);
- if(! $exif)
- return;
-
- $ort = $exif['IFD0']['Orientation'];
-
- switch($ort)
- {
- case 1: // nothing
- break;
-
- case 2: // horizontal flip
- $this->flip();
- break;
-
- case 3: // 180 rotate left
- $this->rotate(180);
- break;
-
- case 4: // vertical flip
- $this->flip(false, true);
- break;
-
- case 5: // vertical flip + 90 rotate right
- $this->flip(false, true);
- $this->rotate(-90);
- break;
-
- case 6: // 90 rotate right
- $this->rotate(-90);
- break;
-
- case 7: // horizontal flip + 90 rotate right
- $this->flip();
- $this->rotate(-90);
- break;
-
- case 8: // 90 rotate left
- $this->rotate(90);
- break;
- }
-
- // logger('exif: ' . print_r($exif,true));
- return $exif;
-
- }
-
-
-
- public function scaleImageUp($min) {
- if(!$this->is_valid())
- return FALSE;
-
-
- $width = $this->getWidth();
- $height = $this->getHeight();
-
- $dest_width = $dest_height = 0;
-
- if((! $width)|| (! $height))
- return FALSE;
-
- if($width < $min && $height < $min) {
- if($width > $height) {
- $dest_width = $min;
- $dest_height = intval(( $height * $min ) / $width);
- }
- else {
- $dest_width = intval(( $width * $min ) / $height);
- $dest_height = $min;
- }
- }
- else {
- if( $width < $min ) {
- $dest_width = $min;
- $dest_height = intval(( $height * $min ) / $width);
- }
- else {
- if( $height < $min ) {
- $dest_width = intval(( $width * $min ) / $height);
- $dest_height = $min;
+ $dest = imagecreatetruecolor($dest_width, $dest_height);
+ imagealphablending($dest, false);
+ imagesavealpha($dest, true);
+ if ($this->type=='image/png') {
+ imagefill($dest, 0, 0, imagecolorallocatealpha($dest, 0, 0, 0, 127)); // fill with alpha
}
- else {
- $dest_width = $width;
- $dest_height = $height;
+ imagecopyresampled($dest, $this->image, 0, 0, 0, 0, $dest_width, $dest_height, $width, $height);
+ if ($this->image) {
+ imagedestroy($this->image);
}
- }
+ $this->image = $dest;
+ $this->width = imagesx($this->image);
+ $this->height = imagesy($this->image);
}
- if($this->is_imagick())
- return $this->scaleImage($dest_width,$dest_height);
+ public function rotate($degrees) {
+ if (!$this->is_valid()) {
+ return false;
+ }
- $dest = imagecreatetruecolor( $dest_width, $dest_height );
- imagealphablending($dest, false);
- imagesavealpha($dest, true);
- if ($this->type=='image/png') imagefill($dest, 0, 0, imagecolorallocatealpha($dest, 0, 0, 0, 127)); // fill with alpha
- imagecopyresampled($dest, $this->image, 0, 0, 0, 0, $dest_width, $dest_height, $width, $height);
- if($this->image)
- imagedestroy($this->image);
- $this->image = $dest;
- $this->width = imagesx($this->image);
- $this->height = imagesy($this->image);
- }
+ if ($this->is_imagick()) {
+ $this->image->setFirstIterator();
+ do {
+ $this->image->rotateImage(new ImagickPixel(), -$degrees); // ImageMagick rotates in the opposite direction of imagerotate()
+ } while ($this->image->nextImage());
+ return;
+ }
-
-
- public function scaleImageSquare($dim) {
- if(!$this->is_valid())
- return FALSE;
-
- if($this->is_imagick()) {
- $this->image->setFirstIterator();
- do {
- $this->image->scaleImage($dim, $dim);
- } while ($this->image->nextImage());
- return;
+ $this->image = imagerotate($this->image,$degrees,0);
+ $this->width = imagesx($this->image);
+ $this->height = imagesy($this->image);
}
- $dest = imagecreatetruecolor( $dim, $dim );
- imagealphablending($dest, false);
- imagesavealpha($dest, true);
- if ($this->type=='image/png') imagefill($dest, 0, 0, imagecolorallocatealpha($dest, 0, 0, 0, 127)); // fill with alpha
- imagecopyresampled($dest, $this->image, 0, 0, 0, 0, $dim, $dim, $this->width, $this->height);
- if($this->image)
- imagedestroy($this->image);
- $this->image = $dest;
- $this->width = imagesx($this->image);
- $this->height = imagesy($this->image);
- }
+ public function flip($horiz = true, $vert = false) {
+ if (!$this->is_valid()) {
+ return false;
+ }
+
+ if ($this->is_imagick()) {
+ $this->image->setFirstIterator();
+ do {
+ if ($horiz) {
+ $this->image->flipImage();
+ }
+ if ($vert) {
+ $this->image->flopImage();
+ }
+ } while ($this->image->nextImage());
+ return;
+ }
+
+ $w = imagesx($this->image);
+ $h = imagesy($this->image);
+ $flipped = imagecreate($w, $h);
+ if ($horiz) {
+ for ($x = 0; $x < $w; $x++) {
+ imagecopy($flipped, $this->image, $x, 0, $w - $x - 1, 0, 1, $h);
+ }
+ }
+ if ($vert) {
+ for ($y = 0; $y < $h; $y++) {
+ imagecopy($flipped, $this->image, 0, $y, 0, $h - $y - 1, $w, 1);
+ }
+ }
+ $this->image = $flipped;
+ }
+
+ public function orient($filename) {
+ if ($this->is_imagick()) {
+ // based off comment on http://php.net/manual/en/imagick.getimageorientation.php
+ $orientation = $this->image->getImageOrientation();
+ switch ($orientation) {
+ case imagick::ORIENTATION_BOTTOMRIGHT:
+ $this->image->rotateimage("#000", 180);
+ break;
+ case imagick::ORIENTATION_RIGHTTOP:
+ $this->image->rotateimage("#000", 90);
+ break;
+ case imagick::ORIENTATION_LEFTBOTTOM:
+ $this->image->rotateimage("#000", -90);
+ break;
+ }
+
+ $this->image->setImageOrientation(imagick::ORIENTATION_TOPLEFT);
+ return true;
+ }
+ // based off comment on http://php.net/manual/en/function.imagerotate.php
+
+ if (!$this->is_valid()) {
+ return false;
+ }
+
+ if ((!function_exists('exif_read_data')) || ($this->getType() !== 'image/jpeg')) {
+ return;
+ }
+
+ $exif = @exif_read_data($filename,null,true);
+ if (!$exif) {
+ return;
+ }
+
+ $ort = $exif['IFD0']['Orientation'];
+
+ switch($ort)
+ {
+ case 1: // nothing
+ break;
+
+ case 2: // horizontal flip
+ $this->flip();
+ break;
+
+ case 3: // 180 rotate left
+ $this->rotate(180);
+ break;
+
+ case 4: // vertical flip
+ $this->flip(false, true);
+ break;
+
+ case 5: // vertical flip + 90 rotate right
+ $this->flip(false, true);
+ $this->rotate(-90);
+ break;
+
+ case 6: // 90 rotate right
+ $this->rotate(-90);
+ break;
+
+ case 7: // horizontal flip + 90 rotate right
+ $this->flip();
+ $this->rotate(-90);
+ break;
+
+ case 8: // 90 rotate left
+ $this->rotate(90);
+ break;
+ }
+
+ // logger('exif: ' . print_r($exif,true));
+ return $exif;
+
+ }
- public function cropImage($max,$x,$y,$w,$h) {
- if(!$this->is_valid())
- return FALSE;
- if($this->is_imagick()) {
+ public function scaleImageUp($min) {
+ if (!$this->is_valid()) {
+ return false;
+ }
+
+
+ $width = $this->getWidth();
+ $height = $this->getHeight();
+
+ $dest_width = $dest_height = 0;
+
+ if ((!$width)|| (!$height)) {
+ return false;
+ }
+
+ if ($width < $min && $height < $min) {
+ if ($width > $height) {
+ $dest_width = $min;
+ $dest_height = intval(($height * $min) / $width);
+ } else {
+ $dest_width = intval(($width * $min) / $height);
+ $dest_height = $min;
+ }
+ } else {
+ if ($width < $min) {
+ $dest_width = $min;
+ $dest_height = intval(($height * $min) / $width);
+ } else {
+ if ($height < $min) {
+ $dest_width = intval(($width * $min) / $height);
+ $dest_height = $min;
+ } else {
+ $dest_width = $width;
+ $dest_height = $height;
+ }
+ }
+ }
+
+ if ($this->is_imagick()) {
+ return $this->scaleImage($dest_width, $dest_height);
+ }
+
+ $dest = imagecreatetruecolor($dest_width, $dest_height);
+ imagealphablending($dest, false);
+ imagesavealpha($dest, true);
+ if ($this->type=='image/png') {
+ imagefill($dest, 0, 0, imagecolorallocatealpha($dest, 0, 0, 0, 127)); // fill with alpha
+ }
+ imagecopyresampled($dest, $this->image, 0, 0, 0, 0, $dest_width, $dest_height, $width, $height);
+ if ($this->image) {
+ imagedestroy($this->image);
+ }
+ $this->image = $dest;
+ $this->width = imagesx($this->image);
+ $this->height = imagesy($this->image);
+ }
+
+
+
+ public function scaleImageSquare($dim) {
+ if (!$this->is_valid()) {
+ return false;
+ }
+
+ if ($this->is_imagick()) {
+ $this->image->setFirstIterator();
+ do {
+ $this->image->scaleImage($dim, $dim);
+ } while ($this->image->nextImage());
+ return;
+ }
+
+ $dest = imagecreatetruecolor($dim, $dim);
+ imagealphablending($dest, false);
+ imagesavealpha($dest, true);
+ if ($this->type=='image/png') {
+ imagefill($dest, 0, 0, imagecolorallocatealpha($dest, 0, 0, 0, 127)); // fill with alpha
+ }
+ imagecopyresampled($dest, $this->image, 0, 0, 0, 0, $dim, $dim, $this->width, $this->height);
+ if ($this->image) {
+ imagedestroy($this->image);
+ }
+ $this->image = $dest;
+ $this->width = imagesx($this->image);
+ $this->height = imagesy($this->image);
+ }
+
+
+ public function cropImage($max, $x, $y, $w, $h) {
+ if (!$this->is_valid()) {
+ return false;
+ }
+
+ if ($this->is_imagick()) {
$this->image->setFirstIterator();
do {
$this->image->cropImage($w, $h, $x, $y);
- /**
+ /*
* We need to remove the canva,
* or the image is not resized to the crop:
* http://php.net/manual/en/imagick.cropimage.php#97232
@@ -520,165 +549,172 @@ class Photo {
return $this->scaleImage($max);
}
- $dest = imagecreatetruecolor( $max, $max );
- imagealphablending($dest, false);
- imagesavealpha($dest, true);
- if ($this->type=='image/png') imagefill($dest, 0, 0, imagecolorallocatealpha($dest, 0, 0, 0, 127)); // fill with alpha
- imagecopyresampled($dest, $this->image, 0, 0, $x, $y, $max, $max, $w, $h);
- if($this->image)
- imagedestroy($this->image);
- $this->image = $dest;
- $this->width = imagesx($this->image);
- $this->height = imagesy($this->image);
- }
-
- public function saveImage($path) {
- if(!$this->is_valid())
- return FALSE;
-
- $string = $this->imageString();
-
- $a = get_app();
-
- $stamp1 = microtime(true);
- file_put_contents($path, $string);
- $a->save_timestamp($stamp1, "file");
- }
-
- public function imageString() {
- if(!$this->is_valid())
- return FALSE;
-
- if($this->is_imagick()) {
- /* Clean it */
- $this->image = $this->image->deconstructImages();
- $string = $this->image->getImagesBlob();
- return $string;
+ $dest = imagecreatetruecolor($max, $max);
+ imagealphablending($dest, false);
+ imagesavealpha($dest, true);
+ if ($this->type=='image/png') {
+ imagefill($dest, 0, 0, imagecolorallocatealpha($dest, 0, 0, 0, 127)); // fill with alpha
+ }
+ imagecopyresampled($dest, $this->image, 0, 0, $x, $y, $max, $max, $w, $h);
+ if ($this->image) {
+ imagedestroy($this->image);
+ }
+ $this->image = $dest;
+ $this->width = imagesx($this->image);
+ $this->height = imagesy($this->image);
}
- $quality = FALSE;
+ public function saveImage($path) {
+ if (!$this->is_valid()) {
+ return false;
+ }
- ob_start();
+ $string = $this->imageString();
- // Enable interlacing
- imageinterlace($this->image, true);
+ $a = get_app();
- switch($this->getType()){
- case "image/png":
- $quality = get_config('system','png_quality');
- if((! $quality) || ($quality > 9))
- $quality = PNG_QUALITY;
- imagepng($this->image,NULL, $quality);
- break;
- case "image/jpeg":
- $quality = get_config('system','jpeg_quality');
- if((! $quality) || ($quality > 100))
- $quality = JPEG_QUALITY;
- imagejpeg($this->image,NULL,$quality);
+ $stamp1 = microtime(true);
+ file_put_contents($path, $string);
+ $a->save_timestamp($stamp1, "file");
}
- $string = ob_get_contents();
- ob_end_clean();
- return $string;
- }
+ public function imageString() {
+ if (!$this->is_valid()) {
+ return false;
+ }
+
+ if ($this->is_imagick()) {
+ /* Clean it */
+ $this->image = $this->image->deconstructImages();
+ $string = $this->image->getImagesBlob();
+ return $string;
+ }
+
+ $quality = false;
+
+ ob_start();
+
+ // Enable interlacing
+ imageinterlace($this->image, true);
+
+ switch($this->getType()){
+ case "image/png":
+ $quality = get_config('system', 'png_quality');
+ if ((!$quality) || ($quality > 9)) {
+ $quality = PNG_QUALITY;
+ }
+ imagepng($this->image, null, $quality);
+ break;
+ case "image/jpeg":
+ $quality = get_config('system', 'jpeg_quality');
+ if ((!$quality) || ($quality > 100)) {
+ $quality = JPEG_QUALITY;
+ }
+ imagejpeg($this->image, null, $quality);
+ }
+ $string = ob_get_contents();
+ ob_end_clean();
+
+ return $string;
+ }
- public function store($uid, $cid, $rid, $filename, $album, $scale, $profile = 0, $allow_cid = '', $allow_gid = '', $deny_cid = '', $deny_gid = '') {
+ public function store($uid, $cid, $rid, $filename, $album, $scale, $profile = 0, $allow_cid = '', $allow_gid = '', $deny_cid = '', $deny_gid = '') {
- $r = q("select `guid` from photo where `resource-id` = '%s' and `guid` != '' limit 1",
- dbesc($rid)
- );
- if(count($r))
- $guid = $r[0]['guid'];
- else
- $guid = get_guid();
+ $r = q("SELECT `guid` FROM `photo` WHERE `resource-id` = '%s' AND `guid` != '' LIMIT 1",
+ dbesc($rid)
+ );
+ if (dbm::is_result($r)) {
+ $guid = $r[0]['guid'];
+ } else {
+ $guid = get_guid();
+ }
- $x = q("select id from photo where `resource-id` = '%s' and uid = %d and `contact-id` = %d and `scale` = %d limit 1",
- dbesc($rid),
- intval($uid),
- intval($cid),
- intval($scale)
- );
- if(count($x)) {
- $r = q("UPDATE `photo`
- set `uid` = %d,
- `contact-id` = %d,
- `guid` = '%s',
- `resource-id` = '%s',
- `created` = '%s',
- `edited` = '%s',
- `filename` = '%s',
- `type` = '%s',
- `album` = '%s',
- `height` = %d,
- `width` = %d,
+ $x = q("SELECT `id` FROM `photo` WHERE `resource-id` = '%s' AND `uid` = %d AND `contact-id` = %d AND `scale` = %d LIMIT 1",
+ dbesc($rid),
+ intval($uid),
+ intval($cid),
+ intval($scale)
+ );
+ if (dbm::is_result($x)) {
+ $r = q("UPDATE `photo`
+ SET `uid` = %d,
+ `contact-id` = %d,
+ `guid` = '%s',
+ `resource-id` = '%s',
+ `created` = '%s',
+ `edited` = '%s',
+ `filename` = '%s',
+ `type` = '%s',
+ `album` = '%s',
+ `height` = %d,
+ `width` = %d,
`datasize` = %d,
- `data` = '%s',
- `scale` = %d,
- `profile` = %d,
- `allow_cid` = '%s',
- `allow_gid` = '%s',
- `deny_cid` = '%s',
- `deny_gid` = '%s'
- where id = %d",
+ `data` = '%s',
+ `scale` = %d,
+ `profile` = %d,
+ `allow_cid` = '%s',
+ `allow_gid` = '%s',
+ `deny_cid` = '%s',
+ `deny_gid` = '%s'
+ WHERE `id` = %d",
- intval($uid),
- intval($cid),
- dbesc($guid),
- dbesc($rid),
- dbesc(datetime_convert()),
- dbesc(datetime_convert()),
- dbesc(basename($filename)),
- dbesc($this->getType()),
- dbesc($album),
- intval($this->getHeight()),
- intval($this->getWidth()),
+ intval($uid),
+ intval($cid),
+ dbesc($guid),
+ dbesc($rid),
+ dbesc(datetime_convert()),
+ dbesc(datetime_convert()),
+ dbesc(basename($filename)),
+ dbesc($this->getType()),
+ dbesc($album),
+ intval($this->getHeight()),
+ intval($this->getWidth()),
dbesc(strlen($this->imageString())),
- dbesc($this->imageString()),
- intval($scale),
- intval($profile),
- dbesc($allow_cid),
- dbesc($allow_gid),
- dbesc($deny_cid),
- dbesc($deny_gid),
- intval($x[0]['id'])
- );
- }
- else {
- $r = q("INSERT INTO `photo`
- ( `uid`, `contact-id`, `guid`, `resource-id`, `created`, `edited`, `filename`, type, `album`, `height`, `width`, `datasize`, `data`, `scale`, `profile`, `allow_cid`, `allow_gid`, `deny_cid`, `deny_gid` )
- VALUES ( %d, %d, '%s', '%s', '%s', '%s', '%s', '%s', '%s', %d, %d, %d, '%s', %d, %d, '%s', '%s', '%s', '%s' )",
- intval($uid),
- intval($cid),
- dbesc($guid),
- dbesc($rid),
- dbesc(datetime_convert()),
- dbesc(datetime_convert()),
- dbesc(basename($filename)),
- dbesc($this->getType()),
- dbesc($album),
- intval($this->getHeight()),
- intval($this->getWidth()),
+ dbesc($this->imageString()),
+ intval($scale),
+ intval($profile),
+ dbesc($allow_cid),
+ dbesc($allow_gid),
+ dbesc($deny_cid),
+ dbesc($deny_gid),
+ intval($x[0]['id'])
+ );
+ } else {
+ $r = q("INSERT INTO `photo`
+ (`uid`, `contact-id`, `guid`, `resource-id`, `created`, `edited`, `filename`, type, `album`, `height`, `width`, `datasize`, `data`, `scale`, `profile`, `allow_cid`, `allow_gid`, `deny_cid`, `deny_gid`)
+ VALUES (%d, %d, '%s', '%s', '%s', '%s', '%s', '%s', '%s', %d, %d, %d, '%s', %d, %d, '%s', '%s', '%s', '%s')",
+ intval($uid),
+ intval($cid),
+ dbesc($guid),
+ dbesc($rid),
+ dbesc(datetime_convert()),
+ dbesc(datetime_convert()),
+ dbesc(basename($filename)),
+ dbesc($this->getType()),
+ dbesc($album),
+ intval($this->getHeight()),
+ intval($this->getWidth()),
dbesc(strlen($this->imageString())),
- dbesc($this->imageString()),
- intval($scale),
- intval($profile),
- dbesc($allow_cid),
- dbesc($allow_gid),
- dbesc($deny_cid),
- dbesc($deny_gid)
- );
- }
+ dbesc($this->imageString()),
+ intval($scale),
+ intval($profile),
+ dbesc($allow_cid),
+ dbesc($allow_gid),
+ dbesc($deny_cid),
+ dbesc($deny_gid)
+ );
+ }
- // Update the cached values
- if ($album != 'Contact Photos') {
- photo_albums($uid, true);
- }
+ // Update the cached values
+ if ($album != 'Contact Photos') {
+ photo_albums($uid, true);
+ }
- return $r;
- }
-}}
+ return $r;
+ }
+}
/**
@@ -688,41 +724,43 @@ class Photo {
* @arg $fromcurl boolean Check Content-Type header from curl request
*/
function guess_image_type($filename, $fromcurl=false) {
- logger('Photo: guess_image_type: '.$filename . ($fromcurl?' from curl headers':''), LOGGER_DEBUG);
- $type = null;
- if ($fromcurl) {
- $a = get_app();
- $headers=array();
- $h = explode("\n",$a->get_curl_headers());
- foreach ($h as $l) {
- list($k,$v) = array_map("trim", explode(":", trim($l), 2));
- $headers[$k] = $v;
+ logger('Photo: guess_image_type: '.$filename . ($fromcurl?' from curl headers':''), LOGGER_DEBUG);
+ $type = null;
+ if ($fromcurl) {
+ $a = get_app();
+ $headers=array();
+ $h = explode("\n",$a->get_curl_headers());
+ foreach ($h as $l) {
+ list($k,$v) = array_map("trim", explode(":", trim($l), 2));
+ $headers[$k] = $v;
+ }
+ if (array_key_exists('Content-Type', $headers))
+ $type = $headers['Content-Type'];
}
- if (array_key_exists('Content-Type', $headers))
- $type = $headers['Content-Type'];
- }
- if (is_null($type)){
- // Guessing from extension? Isn't that... dangerous?
- if(class_exists('Imagick') && file_exists($filename) && is_readable($filename)) {
- /**
- * Well, this not much better,
- * but at least it comes from the data inside the image,
- * we won't be tricked by a manipulated extension
- */
- $image = new Imagick($filename);
- $type = $image->getImageMimeType();
- $image->setInterlaceScheme(Imagick::INTERLACE_PLANE);
- } else {
- $ext = pathinfo($filename, PATHINFO_EXTENSION);
- $types = Photo::supportedTypes();
- $type = "image/jpeg";
- foreach ($types as $m=>$e){
- if ($ext==$e) $type = $m;
- }
+ if (is_null($type)){
+ // Guessing from extension? Isn't that... dangerous?
+ if (class_exists('Imagick') && file_exists($filename) && is_readable($filename)) {
+ /**
+ * Well, this not much better,
+ * but at least it comes from the data inside the image,
+ * we won't be tricked by a manipulated extension
+ */
+ $image = new Imagick($filename);
+ $type = $image->getImageMimeType();
+ $image->setInterlaceScheme(Imagick::INTERLACE_PLANE);
+ } else {
+ $ext = pathinfo($filename, PATHINFO_EXTENSION);
+ $types = Photo::supportedTypes();
+ $type = "image/jpeg";
+ foreach ($types as $m => $e){
+ if ($ext == $e) {
+ $type = $m;
+ }
+ }
+ }
}
- }
- logger('Photo: guess_image_type: type='.$type, LOGGER_DEBUG);
- return $type;
+ logger('Photo: guess_image_type: type='.$type, LOGGER_DEBUG);
+ return $type;
}
@@ -736,16 +774,17 @@ function guess_image_type($filename, $fromcurl=false) {
*
* @return array Returns array of the different avatar sizes
*/
-function update_contact_avatar($avatar,$uid,$cid, $force = false) {
+function update_contact_avatar($avatar, $uid, $cid, $force = false) {
$r = q("SELECT `avatar`, `photo`, `thumb`, `micro` FROM `contact` WHERE `id` = %d LIMIT 1", intval($cid));
- if (!$r)
+ if (!dbm::is_result($r)) {
return false;
- else
+ } else {
$data = array($r[0]["photo"], $r[0]["thumb"], $r[0]["micro"]);
+ }
if (($r[0]["avatar"] != $avatar) OR $force) {
- $photos = import_profile_photo($avatar,$uid,$cid, true);
+ $photos = import_profile_photo($avatar, $uid, $cid, true);
if ($photos) {
q("UPDATE `contact` SET `avatar` = '%s', `photo` = '%s', `thumb` = '%s', `micro` = '%s', `avatar-date` = '%s' WHERE `id` = %d",
@@ -758,63 +797,67 @@ function update_contact_avatar($avatar,$uid,$cid, $force = false) {
return $data;
}
-function import_profile_photo($photo,$uid,$cid, $quit_on_error = false) {
+function import_profile_photo($photo, $uid, $cid, $quit_on_error = false) {
$a = get_app();
- $r = q("select `resource-id` from photo where `uid` = %d and `contact-id` = %d and `scale` = 4 and `album` = 'Contact Photos' limit 1",
+ $r = q("SELECT `resource-id` FROM `photo` WHERE `uid` = %d AND `contact-id` = %d AND `scale` = 4 AND `album` = 'Contact Photos' LIMIT 1",
intval($uid),
intval($cid)
);
- if(count($r) && strlen($r[0]['resource-id'])) {
+ if (dbm::is_result($r) && strlen($r[0]['resource-id'])) {
$hash = $r[0]['resource-id'];
} else {
$hash = photo_new_resource();
- }
+ }
$photo_failure = false;
$filename = basename($photo);
- $img_str = fetch_url($photo,true);
+ $img_str = fetch_url($photo, true);
- if ($quit_on_error AND ($img_str == ""))
+ if ($quit_on_error AND ($img_str == "")) {
return false;
+ }
- $type = guess_image_type($photo,true);
+ $type = guess_image_type($photo, true);
$img = new Photo($img_str, $type);
- if($img->is_valid()) {
+ if ($img->is_valid()) {
$img->scaleImageSquare(175);
- $r = $img->store($uid, $cid, $hash, $filename, 'Contact Photos', 4 );
+ $r = $img->store($uid, $cid, $hash, $filename, 'Contact Photos', 4);
- if($r === false)
+ if ($r === false)
$photo_failure = true;
$img->scaleImage(80);
- $r = $img->store($uid, $cid, $hash, $filename, 'Contact Photos', 5 );
+ $r = $img->store($uid, $cid, $hash, $filename, 'Contact Photos', 5);
- if($r === false)
+ if ($r === false)
$photo_failure = true;
$img->scaleImage(48);
- $r = $img->store($uid, $cid, $hash, $filename, 'Contact Photos', 6 );
+ $r = $img->store($uid, $cid, $hash, $filename, 'Contact Photos', 6);
- if($r === false)
+ if ($r === false) {
$photo_failure = true;
+ }
$photo = $a->get_baseurl() . '/photo/' . $hash . '-4.' . $img->getExt();
$thumb = $a->get_baseurl() . '/photo/' . $hash . '-5.' . $img->getExt();
$micro = $a->get_baseurl() . '/photo/' . $hash . '-6.' . $img->getExt();
- } else
+ } else {
$photo_failure = true;
+ }
- if($photo_failure AND $quit_on_error)
+ if ($photo_failure AND $quit_on_error) {
return false;
+ }
- if($photo_failure) {
+ if ($photo_failure) {
$photo = $a->get_baseurl() . '/images/person-175.jpg';
$thumb = $a->get_baseurl() . '/images/person-80.jpg';
$micro = $a->get_baseurl() . '/images/person-48.jpg';
@@ -829,17 +872,13 @@ function get_photo_info($url) {
$data = Cache::get($url);
- // Unserialise to be able to check in the next step if the cached data is alright.
- if (!is_null($data))
- $data = unserialize($data);
-
if (is_null($data) OR !$data) {
$img_str = fetch_url($url, true, $redirects, 4);
$filesize = strlen($img_str);
- if (function_exists("getimagesizefromstring"))
+ if (function_exists("getimagesizefromstring")) {
$data = getimagesizefromstring($img_str);
- else {
+ } else {
$tempfile = tempnam(get_temppath(), "cache");
$a = get_app();
@@ -851,10 +890,11 @@ function get_photo_info($url) {
unlink($tempfile);
}
- if ($data)
+ if ($data) {
$data["size"] = $filesize;
+ }
- Cache::set($url, serialize($data));
+ Cache::set($url, $data);
}
return $data;
@@ -864,40 +904,41 @@ function scale_image($width, $height, $max) {
$dest_width = $dest_height = 0;
- if((!$width) || (!$height))
- return FALSE;
+ if ((!$width) || (!$height)) {
+ return false;
+ }
- if($width > $max && $height > $max) {
+ if ($width > $max && $height > $max) {
// very tall image (greater than 16:9)
// constrain the width - let the height float.
- if((($height * 9) / 16) > $width) {
+ if ((($height * 9) / 16) > $width) {
$dest_width = $max;
- $dest_height = intval(( $height * $max ) / $width);
- } elseif($width > $height) {
+ $dest_height = intval(($height * $max) / $width);
+ } elseif ($width > $height) {
// else constrain both dimensions
$dest_width = $max;
- $dest_height = intval(( $height * $max ) / $width);
- } else {
- $dest_width = intval(( $width * $max ) / $height);
+ $dest_height = intval(($height * $max) / $width);
+ } else {
+ $dest_width = intval(($width * $max) / $height);
$dest_height = $max;
}
} else {
- if( $width > $max ) {
+ if ($width > $max) {
$dest_width = $max;
- $dest_height = intval(( $height * $max ) / $width);
- } else {
- if( $height > $max ) {
+ $dest_height = intval(($height * $max) / $width);
+ } else {
+ if ($height > $max) {
// very tall image (greater than 16:9)
// but width is OK - don't do anything
- if((($height * 9) / 16) > $width) {
+ if ((($height * 9) / 16) > $width) {
$dest_width = $width;
$dest_height = $height;
} else {
- $dest_width = intval(( $width * $max ) / $height);
+ $dest_width = intval(($width * $max) / $height);
$dest_height = $max;
}
} else {
@@ -911,10 +952,10 @@ function scale_image($width, $height, $max) {
function store_photo($a, $uid, $imagedata = "", $url = "") {
$r = q("SELECT `user`.`nickname`, `user`.`page-flags`, `contact`.`id` FROM `user` INNER JOIN `contact` on `user`.`uid` = `contact`.`uid`
- WHERE `user`.`uid` = %d AND `user`.`blocked` = 0 and `contact`.`self` = 1 LIMIT 1",
+ WHERE `user`.`uid` = %d AND `user`.`blocked` = 0 AND `contact`.`self` = 1 LIMIT 1",
intval($uid));
- if(!count($r)) {
+ if (!dbm::is_result($r)) {
logger("Can't detect user data for uid ".$uid, LOGGER_DEBUG);
return(array());
}
@@ -936,24 +977,24 @@ function store_photo($a, $uid, $imagedata = "", $url = "") {
$a->save_timestamp($stamp1, "file");
}
- $maximagesize = get_config('system','maximagesize');
+ $maximagesize = get_config('system', 'maximagesize');
- if(($maximagesize) && (strlen($imagedata) > $maximagesize)) {
+ if (($maximagesize) && (strlen($imagedata) > $maximagesize)) {
logger("Image exceeds size limit of ".$maximagesize, LOGGER_DEBUG);
return(array());
- }
+ }
/*
- $r = q("select sum(octet_length(data)) as total from photo where uid = %d and scale = 0 and album != 'Contact Photos' ",
- intval($uid)
- );
+ $r = q("select sum(octet_length(data)) as total from photo where uid = %d and scale = 0 and album != 'Contact Photos' ",
+ intval($uid)
+ );
- $limit = service_class_fetch($uid,'photo_upload_limit');
+ $limit = service_class_fetch($uid,'photo_upload_limit');
- if(($limit !== false) && (($r[0]['total'] + strlen($imagedata)) > $limit)) {
+ if (($limit !== false) && (($r[0]['total'] + strlen($imagedata)) > $limit)) {
logger("Image exceeds personal limit of uid ".$uid, LOGGER_DEBUG);
return(array());
- }
+ }
*/
$tempfile = tempnam(get_temppath(), "cache");
@@ -972,7 +1013,7 @@ function store_photo($a, $uid, $imagedata = "", $url = "") {
$ph = new Photo($imagedata, $data["mime"]);
- if(!$ph->is_valid()) {
+ if (!$ph->is_valid()) {
unlink($tempfile);
logger("Picture is no valid picture", LOGGER_DEBUG);
return(array());
@@ -981,11 +1022,13 @@ function store_photo($a, $uid, $imagedata = "", $url = "") {
$ph->orient($tempfile);
unlink($tempfile);
- $max_length = get_config('system','max_image_length');
- if(! $max_length)
+ $max_length = get_config('system', 'max_image_length');
+ if (! $max_length) {
$max_length = MAX_IMAGE_LENGTH;
- if($max_length > 0)
+ }
+ if ($max_length > 0) {
$ph->scaleImage($max_length);
+ }
$width = $ph->getWidth();
$height = $ph->getHeight();
@@ -997,11 +1040,11 @@ function store_photo($a, $uid, $imagedata = "", $url = "") {
// Pictures are always public by now
//$defperm = '<'.$default_cid.'>';
$defperm = "";
- $visitor = 0;
+ $visitor = 0;
$r = $ph->store($uid, $visitor, $hash, $tempfile, t('Wall Photos'), 0, 0, $defperm);
- if(!$r) {
+ if (!$r) {
logger("Picture couldn't be stored", LOGGER_DEBUG);
return(array());
}
@@ -1009,43 +1052,49 @@ function store_photo($a, $uid, $imagedata = "", $url = "") {
$image = array("page" => $a->get_baseurl().'/photos/'.$page_owner_nick.'/image/'.$hash,
"full" => $a->get_baseurl()."/photo/{$hash}-0.".$ph->getExt());
- if($width > 800 || $height > 800)
+ if ($width > 800 || $height > 800) {
$image["large"] = $a->get_baseurl()."/photo/{$hash}-0.".$ph->getExt();
+ }
- if($width > 640 || $height > 640) {
+ if ($width > 640 || $height > 640) {
$ph->scaleImage(640);
$r = $ph->store($uid, $visitor, $hash, $tempfile, t('Wall Photos'), 1, 0, $defperm);
- if($r)
+ if ($r) {
$image["medium"] = $a->get_baseurl()."/photo/{$hash}-1.".$ph->getExt();
+ }
}
- if($width > 320 || $height > 320) {
+ if ($width > 320 || $height > 320) {
$ph->scaleImage(320);
$r = $ph->store($uid, $visitor, $hash, $tempfile, t('Wall Photos'), 2, 0, $defperm);
- if($r)
+ if ($r) {
$image["small"] = $a->get_baseurl()."/photo/{$hash}-2.".$ph->getExt();
+ }
}
- if($width > 160 AND $height > 160) {
+ if ($width > 160 AND $height > 160) {
$x = 0;
$y = 0;
$min = $ph->getWidth();
- if ($min > 160)
+ if ($min > 160) {
$x = ($min - 160) / 2;
+ }
if ($ph->getHeight() < $min) {
$min = $ph->getHeight();
- if ($min > 160)
+ if ($min > 160) {
$y = ($min - 160) / 2;
+ }
}
$min = 160;
$ph->cropImage(160, $x, $y, $min, $min);
$r = $ph->store($uid, $visitor, $hash, $tempfile, t('Wall Photos'), 3, 0, $defperm);
- if($r)
+ if ($r) {
$image["thumb"] = $a->get_baseurl()."/photo/{$hash}-3.".$ph->getExt();
+ }
}
// Set the full image as preview image. This will be overwritten, if the picture is larger than 640.
@@ -1059,39 +1108,9 @@ function store_photo($a, $uid, $imagedata = "", $url = "") {
//if (isset($image["small"]))
// $image["preview"] = $image["small"];
- if (isset($image["medium"]))
+ if (isset($image["medium"])) {
$image["preview"] = $image["medium"];
+ }
return($image);
}
-
-/**
- * @brief Fetch the photo albums that are available for a viewer
- *
- * The query in this function is cost intensive, so it is cached.
- *
- * @param int $uid User id of the photos
- * @param bool $update Update the cache
- *
- * @return array Returns array of the photo albums
- */
-function photo_albums($uid, $update = false) {
- $sql_extra = permissions_sql($uid);
-
- $key = "photo_albums:".$uid.":".local_user().":".remote_user();
- $albums = Cache::get($key);
- if (is_null($albums) OR $update) {
- /// @todo This query needs to be renewed. It is really slow
- // At this time we just store the data in the cache
- $albums = qu("SELECT COUNT(DISTINCT `resource-id`) AS `total`, `album`
- FROM `photo` USE INDEX (`uid_album_created`)
- WHERE `uid` = %d AND `album` != '%s' AND `album` != '%s' $sql_extra
- GROUP BY `album` ORDER BY `created` DESC",
- intval($uid),
- dbesc('Contact Photos'),
- dbesc(t('Contact Photos'))
- );
- Cache::set($key, $albums, CACHE_DAY);
- }
- return $albums;
-}
diff --git a/include/Probe.php b/include/Probe.php
index d266a384e..aa9f7d21d 100644
--- a/include/Probe.php
+++ b/include/Probe.php
@@ -217,7 +217,6 @@ class Probe {
if ($cache) {
$result = Cache::get("probe_url:".$network.":".$uri);
if (!is_null($result)) {
- $result = unserialize($result);
return $result;
}
}
@@ -257,7 +256,7 @@ class Probe {
// Only store into the cache if the value seems to be valid
if (!in_array($data['network'], array(NETWORK_PHANTOM, NETWORK_MAIL))) {
- Cache::set("probe_url:".$network.":".$uri,serialize($data), CACHE_DAY);
+ Cache::set("probe_url:".$network.":".$uri, $data, CACHE_DAY);
/// @todo temporary fix - we need a real contact update function that updates only changing fields
/// The biggest problem is the avatar picture that could have a reduced image size.
diff --git a/include/bbcode.php b/include/bbcode.php
index ed2325364..ebafc353a 100644
--- a/include/bbcode.php
+++ b/include/bbcode.php
@@ -146,7 +146,7 @@ function cleancss($input) {
if (($char >= "a") and ($char <= "z"))
$cleaned .= $char;
- if (!(strpos(" #;:0123456789-_", $char) === false))
+ if (!(strpos(" #;:0123456789-_.%", $char) === false))
$cleaned .= $char;
}
@@ -892,8 +892,7 @@ function bbcode($Text,$preserve_nl = false, $tryoembed = true, $simplehtml = fal
// we may need to restrict this further if it picks up too many strays
// link acct:user@host to a webfinger profile redirector
- $Text = preg_replace('/acct:(.*?)@(.*?)([ ,])/', 'acct:' . "$1@$2$3" . '',$Text);
+ $Text = preg_replace('/acct:([^@]+)@((?!\-)(?:[a-zA-Z\d\-]{0,62}[a-zA-Z\d]\.){1,126}(?!\d+)[a-zA-Z\d]{1,63})/', 'acct:$1@$2',$Text);
// Perform MAIL Search
$Text = preg_replace("/\[mail\]([$MAILSearchString]*)\[\/mail\]/", '$1', $Text);
diff --git a/include/cache.php b/include/cache.php
index 45938dddf..b8016ac45 100644
--- a/include/cache.php
+++ b/include/cache.php
@@ -99,8 +99,8 @@ class Cache {
dbesc($key)
);
- if (count($r)) {
- return $r[0]['v'];
+ if (dbm::is_result($r)) {
+ return unserialize($r[0]['v']);
}
return null;
@@ -108,7 +108,9 @@ class Cache {
/**
* @brief Put data in the cache according to the key
- *
+ *
+ * The input $value can have multiple formats.
+ *
* @param string $key The key to the cached data
* @param mixed $valie The value that is about to be stored
* @param integer $duration The cache lifespan
@@ -126,7 +128,7 @@ class Cache {
/// @todo store the cache data in the same way like the config data
q("REPLACE INTO `cache` (`k`,`v`,`expire_mode`,`updated`) VALUES ('%s','%s',%d,'%s')",
dbesc($key),
- dbesc($value),
+ dbesc(serialize($value)),
intval($duration),
dbesc(datetime_convert()));
}
diff --git a/include/cron.php b/include/cron.php
index 925bb5eab..fea5b3961 100644
--- a/include/cron.php
+++ b/include/cron.php
@@ -11,6 +11,7 @@ if (!file_exists("boot.php") AND (sizeof($_SERVER["argv"]) != 0)) {
}
require_once("boot.php");
+require_once("include/photos.php");
function cron_run(&$argv, &$argc){
@@ -155,8 +156,9 @@ function cron_run(&$argv, &$argc){
*/
function cron_update_photo_albums() {
$r = q("SELECT `uid` FROM `user` WHERE NOT `account_expired` AND NOT `account_removed`");
- if (!dbm::is_result($r))
+ if (!dbm::is_result($r)) {
return;
+ }
foreach ($r AS $user) {
photo_albums($user['uid'], true);
diff --git a/include/datetime.php b/include/datetime.php
index ea98f01fe..16b134e90 100644
--- a/include/datetime.php
+++ b/include/datetime.php
@@ -325,15 +325,15 @@ function datetimesel($format, $min, $max, $default, $label, $id = 'datetimepicke
* Results relative to current timezone.
* Limited to range of timestamps.
*
- * @param string $posted_date
+ * @param string $posted_date MySQL-formatted date string (YYYY-MM-DD HH:MM:SS)
* @param string $format (optional) Parsed with sprintf()
* %1$d %2$s ago, e.g. 22 hours ago, 1 minute ago
- *
+ *
* @return string with relative date
*/
-function relative_date($posted_date,$format = null) {
+function relative_date($posted_date, $format = null) {
- $localtime = datetime_convert('UTC',date_default_timezone_get(),$posted_date);
+ $localtime = $posted_date . ' UTC';
$abs = strtotime($localtime);
@@ -347,13 +347,6 @@ function relative_date($posted_date,$format = null) {
return t('less than a second ago');
}
- /*
- $time_append = '';
- if ($etime >= 86400) {
- $time_append = ' ('.$localtime.')';
- }
- */
-
$a = array( 12 * 30 * 24 * 60 * 60 => array( t('year'), t('years')),
30 * 24 * 60 * 60 => array( t('month'), t('months')),
7 * 24 * 60 * 60 => array( t('week'), t('weeks')),
@@ -368,10 +361,11 @@ function relative_date($posted_date,$format = null) {
if ($d >= 1) {
$r = round($d);
// translators - e.g. 22 hours ago, 1 minute ago
- if(! $format)
+ if (!$format) {
$format = t('%1$d %2$s ago');
+ }
- return sprintf( $format,$r, (($r == 1) ? $str[0] : $str[1]));
+ return sprintf($format, $r, (($r == 1) ? $str[0] : $str[1]));
}
}
}
diff --git a/include/dbstructure.php b/include/dbstructure.php
index 134789177..bd4a07eb5 100644
--- a/include/dbstructure.php
+++ b/include/dbstructure.php
@@ -1039,6 +1039,8 @@ function db_definition($charset) {
"seen" => array("type" => "tinyint(1)", "not null" => "1", "default" => "0"),
"verb" => array("type" => "varchar(255)", "not null" => "1", "default" => ""),
"otype" => array("type" => "varchar(16)", "not null" => "1", "default" => ""),
+ "name_cache" => array("type" => "tinytext"),
+ "msg_cache" => array("type" => "mediumtext")
),
"indexes" => array(
"PRIMARY" => array("id"),
diff --git a/include/enotify.php b/include/enotify.php
index 4973bedc2..5b2bea297 100644
--- a/include/enotify.php
+++ b/include/enotify.php
@@ -418,6 +418,7 @@ function notification($params) {
$datarray = array();
$datarray['hash'] = $hash;
$datarray['name'] = $params['source_name'];
+ $datarray['name_cache'] = strip_tags(bbcode($params['source_name']));
$datarray['url'] = $params['source_link'];
$datarray['photo'] = $params['source_photo'];
$datarray['date'] = datetime_convert();
@@ -439,8 +440,8 @@ function notification($params) {
// create notification entry in DB
- $r = q("INSERT INTO `notify` (`hash`, `name`, `url`, `photo`, `date`, `uid`, `link`, `iid`, `parent`, `type`, `verb`, `otype`)
- values('%s', '%s', '%s', '%s', '%s', %d, '%s', %d, %d, %d, '%s', '%s')",
+ $r = q("INSERT INTO `notify` (`hash`, `name`, `url`, `photo`, `date`, `uid`, `link`, `iid`, `parent`, `type`, `verb`, `otype`, `name_cache`)
+ values('%s', '%s', '%s', '%s', '%s', %d, '%s', %d, %d, %d, '%s', '%s', '%s')",
dbesc($datarray['hash']),
dbesc($datarray['name']),
dbesc($datarray['url']),
@@ -452,7 +453,8 @@ function notification($params) {
intval($datarray['parent']),
intval($datarray['type']),
dbesc($datarray['verb']),
- dbesc($datarray['otype'])
+ dbesc($datarray['otype']),
+ dbesc($datarray["name_cache"])
);
$r = q("SELECT `id` FROM `notify` WHERE `hash` = '%s' AND `uid` = %d LIMIT 1",
@@ -494,8 +496,10 @@ function notification($params) {
$itemlink = $a->get_baseurl().'/notify/view/'.$notify_id;
$msg = replace_macros($epreamble, array('$itemlink' => $itemlink));
- $r = q("UPDATE `notify` SET `msg` = '%s' WHERE `id` = %d AND `uid` = %d",
+ $msg_cache = format_notification_message($datarray['name_cache'], strip_tags(bbcode($msg)));
+ $r = q("UPDATE `notify` SET `msg` = '%s', `msg_cache` = '%s' WHERE `id` = %d AND `uid` = %d",
dbesc($msg),
+ dbesc($msg_cache),
intval($notify_id),
intval($params['uid'])
);
@@ -778,4 +782,27 @@ function check_item_notification($itemid, $uid, $defaulttype = "") {
if (isset($params["type"]))
notification($params);
}
-?>
+
+/**
+ * @brief Formats a notification message with the notification author
+ *
+ * Replace the name with {0} but ensure to make that only once. The {0} is used
+ * later and prints the name in bold.
+ *
+ * @param string $name
+ * @param string $message
+ * @return string Formatted message
+ */
+function format_notification_message($name, $message) {
+ if ($name != '') {
+ $pos = strpos($message, $name);
+ } else {
+ $pos = false;
+ }
+
+ if ($pos !== false) {
+ $message = substr_replace($message, '{0}', $pos, strlen($name));
+ }
+
+ return $message;
+}
diff --git a/include/gprobe.php b/include/gprobe.php
index 91b9b16e3..42a8ef713 100644
--- a/include/gprobe.php
+++ b/include/gprobe.php
@@ -12,11 +12,11 @@ function gprobe_run(&$argv, &$argc){
}
if(is_null($db)) {
- @include(".htconfig.php");
- require_once("include/dba.php");
- $db = new dba($db_host, $db_user, $db_pass, $db_data);
- unset($db_host, $db_user, $db_pass, $db_data);
- };
+ @include(".htconfig.php");
+ require_once("include/dba.php");
+ $db = new dba($db_host, $db_user, $db_pass, $db_data);
+ unset($db_host, $db_user, $db_pass, $db_data);
+ };
require_once('include/session.php');
require_once('include/datetime.php');
@@ -39,14 +39,13 @@ function gprobe_run(&$argv, &$argc){
logger("gprobe start for ".normalise_link($url), LOGGER_DEBUG);
- if (!count($r)) {
+ if (!dbm::is_result($r)) {
// Is it a DDoS attempt?
$urlparts = parse_url($url);
$result = Cache::get("gprobe:".$urlparts["host"]);
if (!is_null($result)) {
- $result = unserialize($result);
if (in_array($result["network"], array(NETWORK_FEED, NETWORK_PHANTOM))) {
logger("DDoS attempt detected for ".$urlparts["host"]." by ".$_SERVER["REMOTE_ADDR"].". server data: ".print_r($_SERVER, true), LOGGER_DEBUG);
return;
@@ -56,7 +55,7 @@ function gprobe_run(&$argv, &$argc){
$arr = probe_url($url);
if (is_null($result))
- Cache::set("gprobe:".$urlparts["host"],serialize($arr));
+ Cache::set("gprobe:".$urlparts["host"], $arr);
if (!in_array($arr["network"], array(NETWORK_FEED, NETWORK_PHANTOM)))
update_gcontact($arr);
@@ -65,7 +64,7 @@ function gprobe_run(&$argv, &$argc){
dbesc(normalise_link($url))
);
}
- if(count($r)) {
+ if(dbm::is_result($r)) {
// Check for accessibility and do a poco discovery
if (poco_last_updated($r[0]['url'], true) AND ($r[0]["network"] == NETWORK_DFRN))
poco_load(0,0,$r[0]['id'], str_replace('/profile/','/poco/',$r[0]['url']));
@@ -76,6 +75,6 @@ function gprobe_run(&$argv, &$argc){
}
if (array_search(__file__,get_included_files())===0){
- gprobe_run($_SERVER["argv"],$_SERVER["argc"]);
- killme();
+ gprobe_run($_SERVER["argv"],$_SERVER["argc"]);
+ killme();
}
diff --git a/include/oembed.php b/include/oembed.php
index 898d900f4..be6c298e8 100755
--- a/include/oembed.php
+++ b/include/oembed.php
@@ -6,7 +6,15 @@ function oembed_replacecb($matches){
return $s;
}
-
+/**
+ * @brief Get data from an URL to embed its content.
+ *
+ * @param string $embedurl The URL from which the data should be fetched.
+ * @param bool $no_rich_type If set to true rich type content won't be fetched.
+ *
+ * @return bool|object Returns object with embed content or false if no embedable
+ * content exists
+ */
function oembed_fetch_url($embedurl, $no_rich_type = false){
$embedurl = trim($embedurl, "'");
$embedurl = trim($embedurl, '"');
@@ -16,11 +24,11 @@ function oembed_fetch_url($embedurl, $no_rich_type = false){
$r = q("SELECT * FROM `oembed` WHERE `url` = '%s'",
dbesc(normalise_link($embedurl)));
- if ($r)
+ if (dbm::is_result($r)) {
$txt = $r[0]["content"];
- else
+ } else {
$txt = Cache::get($a->videowidth . $embedurl);
-
+ }
// These media files should now be caught in bbcode.php
// left here as a fallback in case this is called from another source
@@ -28,27 +36,27 @@ function oembed_fetch_url($embedurl, $no_rich_type = false){
$ext = pathinfo(strtolower($embedurl),PATHINFO_EXTENSION);
- if(is_null($txt)){
+ if (is_null($txt)) {
$txt = "";
if (!in_array($ext, $noexts)){
// try oembed autodiscovery
$redirects = 0;
- $html_text = fetch_url($embedurl, false, $redirects, 15, "text/*"); /**/
- if($html_text){
+ $html_text = fetch_url($embedurl, false, $redirects, 15, "text/*");
+ if ($html_text) {
$dom = @DOMDocument::loadHTML($html_text);
- if ($dom){
+ if ($dom) {
$xpath = new DOMXPath($dom);
$attr = "oembed";
$xattr = oe_build_xpath("class","oembed");
$entries = $xpath->query("//link[@type='application/json+oembed']");
- foreach($entries as $e){
+ foreach ($entries as $e) {
$href = $e->getAttributeNode("href")->nodeValue;
$txt = fetch_url($href . '&maxwidth=' . $a->videowidth);
break;
}
$entries = $xpath->query("//link[@type='text/json+oembed']");
- foreach($entries as $e){
+ foreach ($entries as $e) {
$href = $e->getAttributeNode("href")->nodeValue;
$txt = fetch_url($href . '&maxwidth=' . $a->videowidth);
break;
@@ -57,7 +65,7 @@ function oembed_fetch_url($embedurl, $no_rich_type = false){
}
}
- if ($txt==false || $txt==""){
+ if ($txt==false || $txt=="") {
$embedly = get_config("system", "embedly");
if ($embedly != "") {
// try embedly service
@@ -70,30 +78,33 @@ function oembed_fetch_url($embedurl, $no_rich_type = false){
$txt=trim($txt);
- if ($txt[0]!="{")
+ if ($txt[0]!="{") {
$txt='{"type":"error"}';
- else { //save in cache
+ } else { //save in cache
$j = json_decode($txt);
- if ($j->type != "error")
+ if ($j->type != "error") {
q("INSERT INTO `oembed` (`url`, `content`, `created`) VALUES ('%s', '%s', '%s')
ON DUPLICATE KEY UPDATE `content` = '%s', `created` = '%s'",
dbesc(normalise_link($embedurl)),
dbesc($txt), dbesc(datetime_convert()),
dbesc($txt), dbesc(datetime_convert()));
+ }
- Cache::set($a->videowidth.$embedurl,$txt, CACHE_DAY);
+ Cache::set($a->videowidth.$embedurl, $txt, CACHE_DAY);
}
}
$j = json_decode($txt);
- if (!is_object($j))
+ if (!is_object($j)) {
return false;
+ }
// Always embed the SSL version
- if (isset($j->html))
+ if (isset($j->html)) {
$j->html = str_replace(array("http://www.youtube.com/", "http://player.vimeo.com/"),
array("https://www.youtube.com/", "https://player.vimeo.com/"), $j->html);
+ }
$j->embedurl = $embedurl;
@@ -109,16 +120,18 @@ function oembed_fetch_url($embedurl, $no_rich_type = false){
//$j->height = $data["images"][0]["height"];
}
- if (isset($data["title"]))
- $j->title = $data["title"];
+ if (isset($data["title"])) {
+ $j->title = $data["title"];
+ }
- if (isset($data["text"]))
- $j->description = $data["text"];
+ if (isset($data["text"])) {
+ $j->description = $data["text"];
+ }
if (is_array($data["images"])) {
- $j->thumbnail_url = $data["images"][0]["src"];
- $j->thumbnail_width = $data["images"][0]["width"];
- $j->thumbnail_height = $data["images"][0]["height"];
+ $j->thumbnail_url = $data["images"][0]["src"];
+ $j->thumbnail_width = $data["images"][0]["width"];
+ $j->thumbnail_height = $data["images"][0]["height"];
}
}
diff --git a/include/photos.php b/include/photos.php
index 93a565b51..2beb23ffa 100644
--- a/include/photos.php
+++ b/include/photos.php
@@ -25,3 +25,34 @@ function gps2Num($coordPart) {
return floatval($parts[0]) / floatval($parts[1]);
}
+
+/**
+ * @brief Fetch the photo albums that are available for a viewer
+ *
+ * The query in this function is cost intensive, so it is cached.
+ *
+ * @param int $uid User id of the photos
+ * @param bool $update Update the cache
+ *
+ * @return array Returns array of the photo albums
+ */
+function photo_albums($uid, $update = false) {
+ $sql_extra = permissions_sql($uid);
+
+ $key = "photo_albums:".$uid.":".local_user().":".remote_user();
+ $albums = Cache::get($key);
+ if (is_null($albums) OR $update) {
+ /// @todo This query needs to be renewed. It is really slow
+ // At this time we just store the data in the cache
+ $albums = qu("SELECT COUNT(DISTINCT `resource-id`) AS `total`, `album`
+ FROM `photo` USE INDEX (`uid_album_created`)
+ WHERE `uid` = %d AND `album` != '%s' AND `album` != '%s' $sql_extra
+ GROUP BY `album` ORDER BY `created` DESC",
+ intval($uid),
+ dbesc('Contact Photos'),
+ dbesc(t('Contact Photos'))
+ );
+ Cache::set($key, $albums, CACHE_DAY);
+ }
+ return $albums;
+}
diff --git a/include/session.php b/include/session.php
index c69a40231..763b05f48 100644
--- a/include/session.php
+++ b/include/session.php
@@ -40,6 +40,19 @@ function ref_session_read($id) {
return '';
}
+/**
+ * @brief Standard PHP session write callback
+ *
+ * This callback updates the DB-stored session data and/or the expiration depending
+ * on the case. Uses the $session_expire global for existing session, 5 minutes
+ * for newly created session.
+ *
+ * @global bool $session_exists Whether a session with the given id already exists
+ * @global int $session_expire Session expiration delay in seconds
+ * @param string $id Session ID with format: [a-z0-9]{26}
+ * @param string $data Serialized session data
+ * @return boolean Returns false if parameters are missing, true otherwise
+ */
function ref_session_write($id, $data) {
global $session_exists, $session_expire;
@@ -66,10 +79,11 @@ function ref_session_write($id, $data) {
SET `expire` = '%s'
WHERE `expire` != '%s' AND `sid` = '%s'",
dbesc($expire), dbesc($expire), dbesc($id));
- } else
+ } else {
$r = q("INSERT INTO `session`
SET `sid` = '%s', `expire` = '%s', `data` = '%s'",
dbesc($id), dbesc($default_expire), dbesc($data));
+ }
return true;
}
diff --git a/include/text.php b/include/text.php
index 5c9202c58..83eab1927 100644
--- a/include/text.php
+++ b/include/text.php
@@ -769,71 +769,75 @@ function activity_match($haystack,$needle) {
}}
-if(! function_exists('get_tags')) {
/**
- * Pull out all #hashtags and @person tags from $s;
+ * @brief Pull out all #hashtags and @person tags from $string.
+ *
* We also get @person@domain.com - which would make
* the regex quite complicated as tags can also
* end a sentence. So we'll run through our results
* and strip the period from any tags which end with one.
* Returns array of tags found, or empty array.
*
- * @param string $s
- * @return array
+ * @param string $string Post content
+ * @return array List of tag and person names
*/
-function get_tags($s) {
+function get_tags($string) {
$ret = array();
// Convert hashtag links to hashtags
- $s = preg_replace("/#\[url\=([^\[\]]*)\](.*?)\[\/url\]/ism", "#$2", $s);
+ $string = preg_replace('/#\[url\=([^\[\]]*)\](.*?)\[\/url\]/ism', '#$2', $string);
// ignore anything in a code block
- $s = preg_replace('/\[code\](.*?)\[\/code\]/sm','',$s);
+ $string = preg_replace('/\[code\](.*?)\[\/code\]/sm', '', $string);
// Force line feeds at bbtags
- $s = str_replace(array("[", "]"), array("\n[", "]\n"), $s);
+ $string = str_replace(array('[', ']'), array("\n[", "]\n"), $string);
// ignore anything in a bbtag
- $s = preg_replace('/\[(.*?)\]/sm','',$s);
+ $string = preg_replace('/\[(.*?)\]/sm', '', $string);
// Match full names against @tags including the space between first and last
// We will look these up afterward to see if they are full names or not recognisable.
- if(preg_match_all('/(@[^ \x0D\x0A,:?]+ [^ \x0D\x0A@,:?]+)([ \x0D\x0A@,:?]|$)/',$s,$match)) {
- foreach($match[1] as $mtch) {
- if(strstr($mtch,"]")) {
+ if (preg_match_all('/(@[^ \x0D\x0A,:?]+ [^ \x0D\x0A@,:?]+)([ \x0D\x0A@,:?]|$)/', $string, $matches)) {
+ foreach ($matches[1] as $match) {
+ if (strstr($match, ']')) {
// we might be inside a bbcode color tag - leave it alone
continue;
}
- if(substr($mtch,-1,1) === '.')
- $ret[] = substr($mtch,0,-1);
- else
- $ret[] = $mtch;
+ if (substr($match, -1, 1) === '.') {
+ $ret[] = substr($match, 0, -1);
+ } else {
+ $ret[] = $match;
+ }
}
}
// Otherwise pull out single word tags. These can be @nickname, @first_last
// and #hash tags.
- if(preg_match_all('/([!#@][^ \x0D\x0A,;:?]+)([ \x0D\x0A,;:?]|$)/',$s,$match)) {
- foreach($match[1] as $mtch) {
- if(strstr($mtch,"]")) {
+ if (preg_match_all('/([!#@][^\^ \x0D\x0A,;:?]+)([ \x0D\x0A,;:?]|$)/', $string, $matches)) {
+ foreach($matches[1] as $match) {
+ if (strstr($match, ']')) {
// we might be inside a bbcode color tag - leave it alone
continue;
}
- if(substr($mtch,-1,1) === '.')
- $mtch = substr($mtch,0,-1);
+ if (substr($match, -1, 1) === '.') {
+ $match = substr($match,0,-1);
+ }
// ignore strictly numeric tags like #1
- if((strpos($mtch,'#') === 0) && ctype_digit(substr($mtch,1)))
+ if ((strpos($match, '#') === 0) && ctype_digit(substr($match, 1))) {
continue;
+ }
// try not to catch url fragments
- if(strpos($s,$mtch) && preg_match('/[a-zA-z0-9\/]/',substr($s,strpos($s,$mtch)-1,1)))
+ if (strpos($string, $match) && preg_match('/[a-zA-z0-9\/]/', substr($string, strpos($string, $match) - 1, 1))) {
continue;
- $ret[] = $mtch;
+ }
+ $ret[] = $match;
}
}
return $ret;
-}}
+}
//
diff --git a/mod/photos.php b/mod/photos.php
index edaba5a90..1730a9b60 100644
--- a/mod/photos.php
+++ b/mod/photos.php
@@ -21,8 +21,6 @@ function photos_init(&$a) {
nav_set_selected('home');
- $o = '';
-
if ($a->argc > 1) {
$nick = $a->argv[1];
$user = qu("SELECT * FROM `user` WHERE `nickname` = '%s' AND `blocked` = 0 LIMIT 1",
diff --git a/mod/ping.php b/mod/ping.php
index 8c28e7474..0ed7eb3fe 100644
--- a/mod/ping.php
+++ b/mod/ping.php
@@ -344,6 +344,12 @@ function ping_init(&$a) {
killme();
}
+/**
+ * @brief Retrieves the notifications array for the given user ID
+ *
+ * @param int $uid User id
+ * @return array Associative array of notifications
+ */
function ping_get_notifications($uid) {
$result = array();
@@ -372,46 +378,47 @@ function ping_get_notifications($uid) {
$seensql = "";
$order = "DESC";
$offset = 0;
- } elseif (!$r)
+ } elseif (!$r) {
$quit = true;
- else
+ } else {
$offset += 50;
-
+ }
foreach ($r AS $notification) {
- if (is_null($notification["visible"]))
+ if (is_null($notification["visible"])) {
$notification["visible"] = true;
+ }
- if (is_null($notification["spam"]))
+ if (is_null($notification["spam"])) {
$notification["spam"] = 0;
+ }
- if (is_null($notification["deleted"]))
+ if (is_null($notification["deleted"])) {
$notification["deleted"] = 0;
+ }
- $notification["message"] = strip_tags(bbcode($notification["msg"]));
- $notification["name"] = strip_tags(bbcode($notification["name"]));
+ if ($notification["msg_cache"]) {
+ $notification["name"] = $notification["name_cache"];
+ $notification["message"] = $notification["msg_cache"];
+ } else {
+ $notification["name"] = strip_tags(bbcode($notification["name"]));
+ $notification["message"] = format_notification_message($notification["name"], strip_tags(bbcode($notification["msg"])));
- // Replace the name with {0} but ensure to make that only once
- // The {0} is used later and prints the name in bold.
+ q("UPDATE `notify` SET `name_cache` = '%s', `msg_cache` = '%s' WHERE `id` = %d",
+ dbesc($notification["name"]),
+ dbesc($notification["message"]),
+ intval($notification["id"])
+ );
+ }
- if ($notification['name'] != "")
- $pos = strpos($notification["message"],$notification['name']);
- else
- $pos = false;
-
- if ($pos !== false)
- $notification["message"] = substr_replace($notification["message"],"{0}",$pos,strlen($notification["name"]));
-
- $notification['href'] = $a->get_baseurl() . '/notify/view/' . $notification['id'];
+ $notification["href"] = $a->get_baseurl() . "/notify/view/" . $notification["id"];
if ($notification["visible"] AND !$notification["spam"] AND
!$notification["deleted"] AND !is_array($result[$notification["parent"]])) {
$result[$notification["parent"]] = $notification;
}
}
-
} while ((count($result) < 50) AND !$quit);
-
return($result);
}
diff --git a/update.php b/update.php
index 5eab9c220..fa03ddd1a 100644
--- a/update.php
+++ b/update.php
@@ -1,6 +1,6 @@
@@ -57,7 +57,9 @@ as the value of $top_child_total (this is done at the end of this file)
+ {{if $item.star}}
{{$item.star.starred}}
+ {{/if}}
{{if $item.lock}}
{{/if}}
@@ -73,7 +75,7 @@ as the value of $top_child_total (this is done at the end of this file)
{{/if}}