Merge remote-tracking branch 'upstream/develop' into update-self
This commit is contained in:
commit
a0451e1c62
159 changed files with 7123 additions and 4877 deletions
116
src/App.php
116
src/App.php
|
@ -148,6 +148,8 @@ class App
|
|||
$this->performance['start'] = microtime(true);
|
||||
$this->performance['database'] = 0;
|
||||
$this->performance['database_write'] = 0;
|
||||
$this->performance['cache'] = 0;
|
||||
$this->performance['cache_write'] = 0;
|
||||
$this->performance['network'] = 0;
|
||||
$this->performance['file'] = 0;
|
||||
$this->performance['rendering'] = 0;
|
||||
|
@ -157,6 +159,8 @@ class App
|
|||
|
||||
$this->callstack['database'] = [];
|
||||
$this->callstack['database_write'] = [];
|
||||
$this->callstack['cache'] = [];
|
||||
$this->callstack['cache_write'] = [];
|
||||
$this->callstack['network'] = [];
|
||||
$this->callstack['file'] = [];
|
||||
$this->callstack['rendering'] = [];
|
||||
|
@ -940,4 +944,116 @@ class App
|
|||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $cat Config category
|
||||
* @param string $k Config key
|
||||
* @param mixed $default Default value if it isn't set
|
||||
*/
|
||||
public function getConfigValue($cat, $k, $default = null)
|
||||
{
|
||||
$return = $default;
|
||||
|
||||
if ($cat === 'config') {
|
||||
if (isset($this->config[$k])) {
|
||||
$return = $this->config[$k];
|
||||
}
|
||||
} else {
|
||||
if (isset($this->config[$cat][$k])) {
|
||||
$return = $this->config[$cat][$k];
|
||||
}
|
||||
}
|
||||
|
||||
return $return;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets a value in the config cache. Accepts raw output from the config table
|
||||
*
|
||||
* @param string $cat Config category
|
||||
* @param string $k Config key
|
||||
* @param mixed $v Value to set
|
||||
*/
|
||||
public function setConfigValue($cat, $k, $v)
|
||||
{
|
||||
// Only arrays are serialized in database, so we have to unserialize sparingly
|
||||
$value = is_string($v) && preg_match("|^a:[0-9]+:{.*}$|s", $v) ? unserialize($v) : $v;
|
||||
|
||||
if ($cat === 'config') {
|
||||
$this->config[$k] = $value;
|
||||
} else {
|
||||
$this->config[$cat][$k] = $value;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Deletes a value from the config cache
|
||||
*
|
||||
* @param string $cat Config category
|
||||
* @param string $k Config key
|
||||
*/
|
||||
public function deleteConfigValue($cat, $k)
|
||||
{
|
||||
if ($cat === 'config') {
|
||||
if (isset($this->config[$k])) {
|
||||
unset($this->config[$k]);
|
||||
}
|
||||
} else {
|
||||
if (isset($this->config[$cat][$k])) {
|
||||
unset($this->config[$cat][$k]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Retrieves a value from the user config cache
|
||||
*
|
||||
* @param int $uid User Id
|
||||
* @param string $cat Config category
|
||||
* @param string $k Config key
|
||||
* @param mixed $default Default value if key isn't set
|
||||
*/
|
||||
public function getPConfigValue($uid, $cat, $k, $default = null)
|
||||
{
|
||||
$return = $default;
|
||||
|
||||
if (isset($this->config[$uid][$cat][$k])) {
|
||||
$return = $this->config[$uid][$cat][$k];
|
||||
}
|
||||
|
||||
return $return;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets a value in the user config cache
|
||||
*
|
||||
* Accepts raw output from the pconfig table
|
||||
*
|
||||
* @param int $uid User Id
|
||||
* @param string $cat Config category
|
||||
* @param string $k Config key
|
||||
* @param mixed $v Value to set
|
||||
*/
|
||||
public function setPConfigValue($uid, $cat, $k, $v)
|
||||
{
|
||||
// Only arrays are serialized in database, so we have to unserialize sparingly
|
||||
$value = is_string($v) && preg_match("|^a:[0-9]+:{.*}$|s", $v) ? unserialize($v) : $v;
|
||||
|
||||
$this->config[$uid][$cat][$k] = $value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Deletes a value from the user config cache
|
||||
*
|
||||
* @param int $uid User Id
|
||||
* @param string $cat Config category
|
||||
* @param string $k Config key
|
||||
*/
|
||||
public function deletePConfigValue($uid, $cat, $k)
|
||||
{
|
||||
if (isset($this->config[$uid][$cat][$k])) {
|
||||
unset($this->config[$uid][$cat][$k]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,34 +1,36 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file src/Content/Text/BBCode.php
|
||||
*/
|
||||
|
||||
namespace Friendica\Content\Text;
|
||||
|
||||
use DOMDocument;
|
||||
use DomXPath;
|
||||
use DOMXPath;
|
||||
use Exception;
|
||||
use Friendica\BaseObject;
|
||||
use Friendica\Content\OEmbed;
|
||||
use Friendica\Content\Smilies;
|
||||
use Friendica\Content\Text\Plaintext;
|
||||
use Friendica\Core\Addon;
|
||||
use Friendica\Core\Cache;
|
||||
use Friendica\Core\Config;
|
||||
use Friendica\Core\L10n;
|
||||
use Friendica\Core\Protocol;
|
||||
use Friendica\Core\PConfig;
|
||||
use Friendica\Core\Protocol;
|
||||
use Friendica\Core\System;
|
||||
use Friendica\Model\Contact;
|
||||
use Friendica\Model\Event;
|
||||
use Friendica\Network\Probe;
|
||||
use Friendica\Object\Image;
|
||||
use Friendica\Util\Map;
|
||||
use Friendica\Util\Network;
|
||||
use Friendica\Util\ParseUrl;
|
||||
use League\HTMLToMarkdown\HtmlConverter;
|
||||
|
||||
require_once "include/event.php";
|
||||
require_once "include/html2plain.php";
|
||||
require_once "include/html2bbcode.php";
|
||||
require_once "mod/proxy.php";
|
||||
|
||||
class BBCode
|
||||
class BBCode extends BaseObject
|
||||
{
|
||||
/**
|
||||
* @brief Fetches attachment data that were generated the old way
|
||||
|
@ -174,7 +176,7 @@ class BBCode
|
|||
}
|
||||
|
||||
if ($title != "") {
|
||||
$title = BBCode::convert(html_entity_decode($title, ENT_QUOTES, 'UTF-8'), false, true);
|
||||
$title = self::convert(html_entity_decode($title, ENT_QUOTES, 'UTF-8'), false, true);
|
||||
$title = html_entity_decode($title, ENT_QUOTES, 'UTF-8');
|
||||
$title = str_replace(["[", "]"], ["[", "]"], $title);
|
||||
$data["title"] = $title;
|
||||
|
@ -409,8 +411,8 @@ class BBCode
|
|||
}
|
||||
}
|
||||
|
||||
$html = BBCode::convert($post["text"].$post["after"], false, $htmlmode);
|
||||
$msg = html2plain($html, 0, true);
|
||||
$html = self::convert($post["text"].$post["after"], false, $htmlmode);
|
||||
$msg = HTML::toPlaintext($html, 0, true);
|
||||
$msg = trim(html_entity_decode($msg, ENT_QUOTES, 'UTF-8'));
|
||||
|
||||
$link = "";
|
||||
|
@ -707,7 +709,7 @@ class BBCode
|
|||
|
||||
if ($data["description"] != "" && $data["description"] != $data["title"]) {
|
||||
// Sanitize the HTML by converting it to BBCode
|
||||
$bbcode = html2bbcode($data["description"]);
|
||||
$bbcode = HTML::toBBCode($data["description"]);
|
||||
$return .= sprintf('<blockquote>%s</blockquote>', trim(self::convert($bbcode)));
|
||||
}
|
||||
if ($data["type"] == "link") {
|
||||
|
@ -762,27 +764,6 @@ class BBCode
|
|||
return $text . "\n" . $data["after"];
|
||||
}
|
||||
|
||||
private static function cleanCss($input)
|
||||
{
|
||||
$cleaned = "";
|
||||
|
||||
$input = strtolower($input);
|
||||
|
||||
for ($i = 0; $i < strlen($input); $i++) {
|
||||
$char = substr($input, $i, 1);
|
||||
|
||||
if (($char >= "a") && ($char <= "z")) {
|
||||
$cleaned .= $char;
|
||||
}
|
||||
|
||||
if (!(strpos(" #;:0123456789-_.%", $char) === false)) {
|
||||
$cleaned .= $char;
|
||||
}
|
||||
}
|
||||
|
||||
return $cleaned;
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts [url] BBCodes in a format that looks fine on Mastodon. (callback function)
|
||||
*
|
||||
|
@ -1197,7 +1178,7 @@ class BBCode
|
|||
$text = Cache::get($match[1]);
|
||||
|
||||
if (is_null($text)) {
|
||||
$a = get_app();
|
||||
$a = self::getApp();
|
||||
|
||||
$stamp1 = microtime(true);
|
||||
|
||||
|
@ -1220,7 +1201,7 @@ class BBCode
|
|||
|
||||
$doc = new DOMDocument();
|
||||
@$doc->loadHTML($body);
|
||||
$xpath = new DomXPath($doc);
|
||||
$xpath = new DOMXPath($doc);
|
||||
$list = $xpath->query("//meta[@name]");
|
||||
foreach ($list as $node) {
|
||||
$attr = [];
|
||||
|
@ -1256,7 +1237,7 @@ class BBCode
|
|||
$text = Cache::get($match[1]);
|
||||
|
||||
if (is_null($text)) {
|
||||
$a = get_app();
|
||||
$a = self::getApp();
|
||||
|
||||
$stamp1 = microtime(true);
|
||||
|
||||
|
@ -1280,7 +1261,7 @@ class BBCode
|
|||
|
||||
$doc = new DOMDocument();
|
||||
@$doc->loadHTML($body);
|
||||
$xpath = new DomXPath($doc);
|
||||
$xpath = new DOMXPath($doc);
|
||||
$list = $xpath->query("//meta[@name]");
|
||||
foreach ($list as $node) {
|
||||
$attr = [];
|
||||
|
@ -1343,7 +1324,7 @@ class BBCode
|
|||
*/
|
||||
public static function convert($text, $try_oembed = true, $simple_html = false, $for_plaintext = false)
|
||||
{
|
||||
$a = get_app();
|
||||
$a = self::getApp();
|
||||
|
||||
/*
|
||||
* preg_match_callback function to replace potential Oembed tags with Oembed content
|
||||
|
@ -1392,7 +1373,7 @@ class BBCode
|
|||
// After we're finished processing the bbcode we'll
|
||||
// replace all of the event code with a reformatted version.
|
||||
|
||||
$ev = bbtoevent($text);
|
||||
$ev = Event::fromBBCode($text);
|
||||
|
||||
// Replace any html brackets with HTML Entities to prevent executing HTML or script
|
||||
// Don't use strip_tags here because it breaks [url] search by replacing & with amp
|
||||
|
@ -1616,7 +1597,7 @@ class BBCode
|
|||
$text = preg_replace_callback(
|
||||
"(\[style=(.*?)\](.*?)\[\/style\])ism",
|
||||
function ($match) {
|
||||
return "<span style=\"" . self::cleanCss($match[1]) . ";\">" . $match[2] . "</span>";
|
||||
return "<span style=\"" . HTML::sanitizeCSS($match[1]) . ";\">" . $match[2] . "</span>";
|
||||
},
|
||||
$text
|
||||
);
|
||||
|
@ -1625,7 +1606,7 @@ class BBCode
|
|||
$text = preg_replace_callback(
|
||||
"(\[class=(.*?)\](.*?)\[\/class\])ism",
|
||||
function ($match) {
|
||||
return "<span class=\"" . self::cleanCss($match[1]) . "\">" . $match[2] . "</span>";
|
||||
return "<span class=\"" . HTML::sanitizeCSS($match[1]) . "\">" . $match[2] . "</span>";
|
||||
},
|
||||
$text
|
||||
);
|
||||
|
@ -1830,7 +1811,7 @@ class BBCode
|
|||
// start which is always required). Allow desc with a missing summary for compatibility.
|
||||
|
||||
if ((x($ev, 'desc') || x($ev, 'summary')) && x($ev, 'start')) {
|
||||
$sub = format_event_html($ev, $simple_html);
|
||||
$sub = Event::getHTML($ev, $simple_html);
|
||||
|
||||
$text = preg_replace("/\[event\-summary\](.*?)\[\/event\-summary\]/ism", '', $text);
|
||||
$text = preg_replace("/\[event\-description\](.*?)\[\/event\-description\]/ism", '', $text);
|
||||
|
@ -1969,4 +1950,148 @@ class BBCode
|
|||
|
||||
return $abstract;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Callback function to replace a Friendica style mention in a mention for Diaspora
|
||||
*
|
||||
* @param array $match Matching values for the callback
|
||||
* @return string Replaced mention
|
||||
*/
|
||||
private static function bbCodeMention2DiasporaCallback($match)
|
||||
{
|
||||
$contact = Contact::getDetailsByURL($match[3]);
|
||||
|
||||
if (empty($contact['addr'])) {
|
||||
$contact = Probe::uri($match[3]);
|
||||
}
|
||||
|
||||
if (empty($contact['addr'])) {
|
||||
return $match[0];
|
||||
}
|
||||
|
||||
$mention = '@{' . $match[2] . '; ' . $contact['addr'] . '}';
|
||||
return $mention;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Converts a BBCode text into Markdown
|
||||
*
|
||||
* This function converts a BBCode item body to be sent to Markdown-enabled
|
||||
* systems like Diaspora and Libertree
|
||||
*
|
||||
* @param string $text
|
||||
* @param bool $for_diaspora Diaspora requires more changes than Libertree
|
||||
* @return string
|
||||
*/
|
||||
public static function toMarkdown($text, $for_diaspora = true)
|
||||
{
|
||||
$a = self::getApp();
|
||||
|
||||
$original_text = $text;
|
||||
|
||||
// Since Diaspora is creating a summary for links, this function removes them before posting
|
||||
if ($for_diaspora) {
|
||||
$text = self::removeShareInformation($text);
|
||||
}
|
||||
|
||||
/**
|
||||
* Transform #tags, strip off the [url] and replace spaces with underscore
|
||||
*/
|
||||
$url_search_string = "^\[\]";
|
||||
$text = preg_replace_callback("/#\[url\=([$url_search_string]*)\](.*?)\[\/url\]/i",
|
||||
function ($matches) {
|
||||
return '#' . str_replace(' ', '_', $matches[2]);
|
||||
},
|
||||
$text
|
||||
);
|
||||
|
||||
// Converting images with size parameters to simple images. Markdown doesn't know it.
|
||||
$text = preg_replace("/\[img\=([0-9]*)x([0-9]*)\](.*?)\[\/img\]/ism", '[img]$3[/img]', $text);
|
||||
|
||||
// Extracting multi-line code blocks before the whitespace processing/code highlighter in self::convert()
|
||||
$codeblocks = [];
|
||||
|
||||
$text = preg_replace_callback("#\[code(?:=([^\]]*))?\](.*?)\[\/code\]#is",
|
||||
function ($matches) use (&$codeblocks) {
|
||||
$return = $matches[0];
|
||||
if (strpos($matches[2], "\n") !== false) {
|
||||
$return = '#codeblock-' . count($codeblocks) . '#';
|
||||
|
||||
$prefix = '````' . $matches[1] . PHP_EOL;
|
||||
$codeblocks[] = $prefix . trim($matches[2]) . PHP_EOL . '````';
|
||||
}
|
||||
return $return;
|
||||
},
|
||||
$text
|
||||
);
|
||||
|
||||
// Convert it to HTML - don't try oembed
|
||||
if ($for_diaspora) {
|
||||
$text = self::convert($text, false, 3);
|
||||
|
||||
// Add all tags that maybe were removed
|
||||
if (preg_match_all("/#\[url\=([$url_search_string]*)\](.*?)\[\/url\]/ism", $original_text, $tags)) {
|
||||
$tagline = "";
|
||||
foreach ($tags[2] as $tag) {
|
||||
$tag = html_entity_decode($tag, ENT_QUOTES, 'UTF-8');
|
||||
if (!strpos(html_entity_decode($text, ENT_QUOTES, 'UTF-8'), '#' . $tag)) {
|
||||
$tagline .= '#' . $tag . ' ';
|
||||
}
|
||||
}
|
||||
$text = $text . " " . $tagline;
|
||||
}
|
||||
} else {
|
||||
$text = self::convert($text, false, 4);
|
||||
}
|
||||
|
||||
// mask some special HTML chars from conversation to markdown
|
||||
$text = str_replace(['<', '>', '&'], ['&_lt_;', '&_gt_;', '&_amp_;'], $text);
|
||||
|
||||
// If a link is followed by a quote then there should be a newline before it
|
||||
// Maybe we should make this newline at every time before a quote.
|
||||
$text = str_replace(["</a><blockquote>"], ["</a><br><blockquote>"], $text);
|
||||
|
||||
$stamp1 = microtime(true);
|
||||
|
||||
// Now convert HTML to Markdown
|
||||
$converter = new HtmlConverter();
|
||||
$text = $converter->convert($text);
|
||||
|
||||
// unmask the special chars back to HTML
|
||||
$text = str_replace(['&\_lt\_;', '&\_gt\_;', '&\_amp\_;'], ['<', '>', '&'], $text);
|
||||
|
||||
$a->save_timestamp($stamp1, "parser");
|
||||
|
||||
// Libertree has a problem with escaped hashtags.
|
||||
$text = str_replace(['\#'], ['#'], $text);
|
||||
|
||||
// Remove any leading or trailing whitespace, as this will mess up
|
||||
// the Diaspora signature verification and cause the item to disappear
|
||||
$text = trim($text);
|
||||
|
||||
if ($for_diaspora) {
|
||||
$url_search_string = "^\[\]";
|
||||
$text = preg_replace_callback(
|
||||
"/([@]\[(.*?)\])\(([$url_search_string]*?)\)/ism",
|
||||
['self', 'bbCodeMention2DiasporaCallback'],
|
||||
$text
|
||||
);
|
||||
}
|
||||
|
||||
// Restore code blocks
|
||||
$text = preg_replace_callback('/#codeblock-([0-9]+)#/iU',
|
||||
function ($matches) use ($codeblocks) {
|
||||
$return = '';
|
||||
if (isset($codeblocks[intval($matches[1])])) {
|
||||
$return = $codeblocks[$matches[1]];
|
||||
}
|
||||
return $return;
|
||||
},
|
||||
$text
|
||||
);
|
||||
|
||||
Addon::callHooks('bb2diaspora', $text);
|
||||
|
||||
return $text;
|
||||
}
|
||||
}
|
||||
|
|
674
src/Content/Text/HTML.php
Normal file
674
src/Content/Text/HTML.php
Normal file
|
@ -0,0 +1,674 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file src/Content/Text/HTML.php
|
||||
*/
|
||||
|
||||
namespace Friendica\Content\Text;
|
||||
|
||||
use DOMDocument;
|
||||
use DOMXPath;
|
||||
use Friendica\Core\Addon;
|
||||
use Friendica\Util\Network;
|
||||
use Friendica\Util\XML;
|
||||
|
||||
class HTML
|
||||
{
|
||||
public static function sanitizeCSS($input)
|
||||
{
|
||||
$cleaned = "";
|
||||
|
||||
$input = strtolower($input);
|
||||
|
||||
for ($i = 0; $i < strlen($input); $i++) {
|
||||
$char = substr($input, $i, 1);
|
||||
|
||||
if (($char >= "a") && ($char <= "z")) {
|
||||
$cleaned .= $char;
|
||||
}
|
||||
|
||||
if (!(strpos(" #;:0123456789-_.%", $char) === false)) {
|
||||
$cleaned .= $char;
|
||||
}
|
||||
}
|
||||
|
||||
return $cleaned;
|
||||
}
|
||||
|
||||
private static function tagToBBCode(DOMDocument $doc, $tag, $attributes, $startbb, $endbb)
|
||||
{
|
||||
do {
|
||||
$done = self::tagToBBCodeSub($doc, $tag, $attributes, $startbb, $endbb);
|
||||
} while ($done);
|
||||
}
|
||||
|
||||
private static function tagToBBCodeSub(DOMDocument $doc, $tag, $attributes, $startbb, $endbb)
|
||||
{
|
||||
$savestart = str_replace('$', '\x01', $startbb);
|
||||
$replace = false;
|
||||
|
||||
$xpath = new DOMXPath($doc);
|
||||
|
||||
$list = $xpath->query("//" . $tag);
|
||||
foreach ($list as $node) {
|
||||
$attr = [];
|
||||
if ($node->attributes->length) {
|
||||
foreach ($node->attributes as $attribute) {
|
||||
$attr[$attribute->name] = $attribute->value;
|
||||
}
|
||||
}
|
||||
|
||||
$replace = true;
|
||||
|
||||
$startbb = $savestart;
|
||||
|
||||
$i = 0;
|
||||
|
||||
foreach ($attributes as $attribute => $value) {
|
||||
$startbb = str_replace('\x01' . ++$i, '$1', $startbb);
|
||||
if (strpos('*' . $startbb, '$1') > 0) {
|
||||
if ($replace && (@$attr[$attribute] != '')) {
|
||||
$startbb = preg_replace($value, $startbb, $attr[$attribute], -1, $count);
|
||||
|
||||
// If nothing could be changed
|
||||
if ($count == 0) {
|
||||
$replace = false;
|
||||
}
|
||||
} else {
|
||||
$replace = false;
|
||||
}
|
||||
} else {
|
||||
if (@$attr[$attribute] != $value) {
|
||||
$replace = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ($replace) {
|
||||
$StartCode = $doc->createTextNode($startbb);
|
||||
$EndCode = $doc->createTextNode($endbb);
|
||||
|
||||
$node->parentNode->insertBefore($StartCode, $node);
|
||||
|
||||
if ($node->hasChildNodes()) {
|
||||
foreach ($node->childNodes as $child) {
|
||||
$newNode = $child->cloneNode(true);
|
||||
$node->parentNode->insertBefore($newNode, $node);
|
||||
}
|
||||
}
|
||||
|
||||
$node->parentNode->insertBefore($EndCode, $node);
|
||||
$node->parentNode->removeChild($node);
|
||||
}
|
||||
}
|
||||
|
||||
return $replace;
|
||||
}
|
||||
|
||||
/**
|
||||
* Made by: ike@piratenpartei.de
|
||||
* Originally made for the syncom project: http://wiki.piratenpartei.de/Syncom
|
||||
* https://github.com/annando/Syncom
|
||||
*
|
||||
* @brief Converter for HTML to BBCode
|
||||
* @param string $message
|
||||
* @param string $basepath
|
||||
* @return string
|
||||
*/
|
||||
public static function toBBCode($message, $basepath = '')
|
||||
{
|
||||
$message = str_replace("\r", "", $message);
|
||||
|
||||
// Removing code blocks before the whitespace removal processing below
|
||||
$codeblocks = [];
|
||||
$message = preg_replace_callback(
|
||||
'#<pre><code(?: class="([^"]*)")?>(.*)</code></pre>#iUs',
|
||||
function ($matches) use (&$codeblocks) {
|
||||
$return = '[codeblock-' . count($codeblocks) . ']';
|
||||
|
||||
$prefix = '[code]';
|
||||
if ($matches[1] != '') {
|
||||
$prefix = '[code=' . $matches[1] . ']';
|
||||
}
|
||||
|
||||
$codeblocks[] = $prefix . trim($matches[2]) . '[/code]';
|
||||
return $return;
|
||||
},
|
||||
$message
|
||||
);
|
||||
|
||||
$message = str_replace(
|
||||
[
|
||||
"<li><p>",
|
||||
"</p></li>",
|
||||
], [
|
||||
"<li>",
|
||||
"</li>",
|
||||
], $message
|
||||
);
|
||||
|
||||
// remove namespaces
|
||||
$message = preg_replace('=<(\w+):(.+?)>=', '<removeme>', $message);
|
||||
$message = preg_replace('=</(\w+):(.+?)>=', '</removeme>', $message);
|
||||
|
||||
$doc = new DOMDocument();
|
||||
$doc->preserveWhiteSpace = false;
|
||||
|
||||
$message = mb_convert_encoding($message, 'HTML-ENTITIES', "UTF-8");
|
||||
|
||||
@$doc->loadHTML($message);
|
||||
|
||||
XML::deleteNode($doc, 'style');
|
||||
XML::deleteNode($doc, 'head');
|
||||
XML::deleteNode($doc, 'title');
|
||||
XML::deleteNode($doc, 'meta');
|
||||
XML::deleteNode($doc, 'xml');
|
||||
XML::deleteNode($doc, 'removeme');
|
||||
|
||||
$xpath = new DomXPath($doc);
|
||||
$list = $xpath->query("//pre");
|
||||
foreach ($list as $node) {
|
||||
$node->nodeValue = str_replace("\n", "\r", $node->nodeValue);
|
||||
}
|
||||
|
||||
$message = $doc->saveHTML();
|
||||
$message = str_replace(["\n<", ">\n", "\r", "\n", "\xC3\x82\xC2\xA0"], ["<", ">", "<br />", " ", ""], $message);
|
||||
$message = preg_replace('= [\s]*=i', " ", $message);
|
||||
@$doc->loadHTML($message);
|
||||
|
||||
self::tagToBBCode($doc, 'html', [], "", "");
|
||||
self::tagToBBCode($doc, 'body', [], "", "");
|
||||
|
||||
// Outlook-Quote - Variant 1
|
||||
self::tagToBBCode($doc, 'p', ['class' => 'MsoNormal', 'style' => 'margin-left:35.4pt'], '[quote]', '[/quote]');
|
||||
|
||||
// Outlook-Quote - Variant 2
|
||||
self::tagToBBCode($doc, 'div', ['style' => 'border:none;border-left:solid blue 1.5pt;padding:0cm 0cm 0cm 4.0pt'],
|
||||
'[quote]', '[/quote]');
|
||||
|
||||
// MyBB-Stuff
|
||||
self::tagToBBCode($doc, 'span', ['style' => 'text-decoration: underline;'], '[u]', '[/u]');
|
||||
self::tagToBBCode($doc, 'span', ['style' => 'font-style: italic;'], '[i]', '[/i]');
|
||||
self::tagToBBCode($doc, 'span', ['style' => 'font-weight: bold;'], '[b]', '[/b]');
|
||||
|
||||
/* self::node2BBCode($doc, 'font', array('face'=>'/([\w ]+)/', 'size'=>'/(\d+)/', 'color'=>'/(.+)/'), '[font=$1][size=$2][color=$3]', '[/color][/size][/font]');
|
||||
self::node2BBCode($doc, 'font', array('size'=>'/(\d+)/', 'color'=>'/(.+)/'), '[size=$1][color=$2]', '[/color][/size]');
|
||||
self::node2BBCode($doc, 'font', array('face'=>'/([\w ]+)/', 'size'=>'/(.+)/'), '[font=$1][size=$2]', '[/size][/font]');
|
||||
self::node2BBCode($doc, 'font', array('face'=>'/([\w ]+)/', 'color'=>'/(.+)/'), '[font=$1][color=$3]', '[/color][/font]');
|
||||
self::node2BBCode($doc, 'font', array('face'=>'/([\w ]+)/'), '[font=$1]', '[/font]');
|
||||
self::node2BBCode($doc, 'font', array('size'=>'/(\d+)/'), '[size=$1]', '[/size]');
|
||||
self::node2BBCode($doc, 'font', array('color'=>'/(.+)/'), '[color=$1]', '[/color]');
|
||||
*/
|
||||
// Untested
|
||||
//self::node2BBCode($doc, 'span', array('style'=>'/.*font-size:\s*(.+?)[,;].*font-family:\s*(.+?)[,;].*color:\s*(.+?)[,;].*/'), '[size=$1][font=$2][color=$3]', '[/color][/font][/size]');
|
||||
//self::node2BBCode($doc, 'span', array('style'=>'/.*font-size:\s*(\d+)[,;].*/'), '[size=$1]', '[/size]');
|
||||
//self::node2BBCode($doc, 'span', array('style'=>'/.*font-size:\s*(.+?)[,;].*/'), '[size=$1]', '[/size]');
|
||||
|
||||
self::tagToBBCode($doc, 'span', ['style' => '/.*color:\s*(.+?)[,;].*/'], '[color="$1"]', '[/color]');
|
||||
|
||||
//self::node2BBCode($doc, 'span', array('style'=>'/.*font-family:\s*(.+?)[,;].*/'), '[font=$1]', '[/font]');
|
||||
//self::node2BBCode($doc, 'div', array('style'=>'/.*font-family:\s*(.+?)[,;].*font-size:\s*(\d+?)pt.*/'), '[font=$1][size=$2]', '[/size][/font]');
|
||||
//self::node2BBCode($doc, 'div', array('style'=>'/.*font-family:\s*(.+?)[,;].*font-size:\s*(\d+?)px.*/'), '[font=$1][size=$2]', '[/size][/font]');
|
||||
//self::node2BBCode($doc, 'div', array('style'=>'/.*font-family:\s*(.+?)[,;].*/'), '[font=$1]', '[/font]');
|
||||
// Importing the classes - interesting for importing of posts from third party networks that were exported from friendica
|
||||
// Test
|
||||
//self::node2BBCode($doc, 'span', array('class'=>'/([\w ]+)/'), '[class=$1]', '[/class]');
|
||||
self::tagToBBCode($doc, 'span', ['class' => 'type-link'], '[class=type-link]', '[/class]');
|
||||
self::tagToBBCode($doc, 'span', ['class' => 'type-video'], '[class=type-video]', '[/class]');
|
||||
|
||||
self::tagToBBCode($doc, 'strong', [], '[b]', '[/b]');
|
||||
self::tagToBBCode($doc, 'em', [], '[i]', '[/i]');
|
||||
self::tagToBBCode($doc, 'b', [], '[b]', '[/b]');
|
||||
self::tagToBBCode($doc, 'i', [], '[i]', '[/i]');
|
||||
self::tagToBBCode($doc, 'u', [], '[u]', '[/u]');
|
||||
|
||||
self::tagToBBCode($doc, 'big', [], "[size=large]", "[/size]");
|
||||
self::tagToBBCode($doc, 'small', [], "[size=small]", "[/size]");
|
||||
|
||||
self::tagToBBCode($doc, 'blockquote', [], '[quote]', '[/quote]');
|
||||
|
||||
self::tagToBBCode($doc, 'br', [], "\n", '');
|
||||
|
||||
self::tagToBBCode($doc, 'p', ['class' => 'MsoNormal'], "\n", "");
|
||||
self::tagToBBCode($doc, 'div', ['class' => 'MsoNormal'], "\r", "");
|
||||
|
||||
self::tagToBBCode($doc, 'span', [], "", "");
|
||||
|
||||
self::tagToBBCode($doc, 'span', [], "", "");
|
||||
self::tagToBBCode($doc, 'pre', [], "", "");
|
||||
|
||||
self::tagToBBCode($doc, 'div', [], "\r", "\r");
|
||||
self::tagToBBCode($doc, 'p', [], "\n", "\n");
|
||||
|
||||
self::tagToBBCode($doc, 'ul', [], "[list]", "[/list]");
|
||||
self::tagToBBCode($doc, 'ol', [], "[list=1]", "[/list]");
|
||||
self::tagToBBCode($doc, 'li', [], "[*]", "");
|
||||
|
||||
self::tagToBBCode($doc, 'hr', [], "[hr]", "");
|
||||
|
||||
self::tagToBBCode($doc, 'table', [], "", "");
|
||||
self::tagToBBCode($doc, 'tr', [], "\n", "");
|
||||
self::tagToBBCode($doc, 'td', [], "\t", "");
|
||||
//self::node2BBCode($doc, 'table', array(), "[table]", "[/table]");
|
||||
//self::node2BBCode($doc, 'th', array(), "[th]", "[/th]");
|
||||
//self::node2BBCode($doc, 'tr', array(), "[tr]", "[/tr]");
|
||||
//self::node2BBCode($doc, 'td', array(), "[td]", "[/td]");
|
||||
//self::node2BBCode($doc, 'h1', array(), "\n\n[size=xx-large][b]", "[/b][/size]\n");
|
||||
//self::node2BBCode($doc, 'h2', array(), "\n\n[size=x-large][b]", "[/b][/size]\n");
|
||||
//self::node2BBCode($doc, 'h3', array(), "\n\n[size=large][b]", "[/b][/size]\n");
|
||||
//self::node2BBCode($doc, 'h4', array(), "\n\n[size=medium][b]", "[/b][/size]\n");
|
||||
//self::node2BBCode($doc, 'h5', array(), "\n\n[size=small][b]", "[/b][/size]\n");
|
||||
//self::node2BBCode($doc, 'h6', array(), "\n\n[size=x-small][b]", "[/b][/size]\n");
|
||||
|
||||
self::tagToBBCode($doc, 'h1', [], "[h1]", "[/h1]");
|
||||
self::tagToBBCode($doc, 'h2', [], "[h2]", "[/h2]");
|
||||
self::tagToBBCode($doc, 'h3', [], "[h3]", "[/h3]");
|
||||
self::tagToBBCode($doc, 'h4', [], "[h4]", "[/h4]");
|
||||
self::tagToBBCode($doc, 'h5', [], "[h5]", "[/h5]");
|
||||
self::tagToBBCode($doc, 'h6', [], "[h6]", "[/h6]");
|
||||
|
||||
self::tagToBBCode($doc, 'a', ['href' => '/mailto:(.+)/'], '[mail=$1]', '[/mail]');
|
||||
self::tagToBBCode($doc, 'a', ['href' => '/(.+)/'], '[url=$1]', '[/url]');
|
||||
|
||||
self::tagToBBCode($doc, 'img', ['src' => '/(.+)/', 'width' => '/(\d+)/', 'height' => '/(\d+)/'], '[img=$2x$3]$1',
|
||||
'[/img]');
|
||||
self::tagToBBCode($doc, 'img', ['src' => '/(.+)/'], '[img]$1', '[/img]');
|
||||
|
||||
|
||||
self::tagToBBCode($doc, 'video', ['src' => '/(.+)/'], '[video]$1', '[/video]');
|
||||
self::tagToBBCode($doc, 'audio', ['src' => '/(.+)/'], '[audio]$1', '[/audio]');
|
||||
self::tagToBBCode($doc, 'iframe', ['src' => '/(.+)/'], '[iframe]$1', '[/iframe]');
|
||||
|
||||
self::tagToBBCode($doc, 'key', [], '[code]', '[/code]');
|
||||
self::tagToBBCode($doc, 'code', [], '[code]', '[/code]');
|
||||
|
||||
$message = $doc->saveHTML();
|
||||
|
||||
// I'm removing something really disturbing
|
||||
// Don't know exactly what it is
|
||||
$message = str_replace(chr(194) . chr(160), ' ', $message);
|
||||
|
||||
$message = str_replace(" ", " ", $message);
|
||||
|
||||
// removing multiple DIVs
|
||||
$message = preg_replace('=\r *\r=i', "\n", $message);
|
||||
$message = str_replace("\r", "\n", $message);
|
||||
|
||||
Addon::callHooks('html2bbcode', $message);
|
||||
|
||||
$message = strip_tags($message);
|
||||
|
||||
$message = html_entity_decode($message, ENT_QUOTES, 'UTF-8');
|
||||
|
||||
$message = str_replace(["<"], ["<"], $message);
|
||||
|
||||
// remove quotes if they don't make sense
|
||||
$message = preg_replace('=\[/quote\][\s]*\[quote\]=i', "\n", $message);
|
||||
|
||||
$message = preg_replace('=\[quote\]\s*=i', "[quote]", $message);
|
||||
$message = preg_replace('=\s*\[/quote\]=i', "[/quote]", $message);
|
||||
|
||||
do {
|
||||
$oldmessage = $message;
|
||||
$message = str_replace("\n \n", "\n\n", $message);
|
||||
} while ($oldmessage != $message);
|
||||
|
||||
do {
|
||||
$oldmessage = $message;
|
||||
$message = str_replace("\n\n\n", "\n\n", $message);
|
||||
} while ($oldmessage != $message);
|
||||
|
||||
do {
|
||||
$oldmessage = $message;
|
||||
$message = str_replace(
|
||||
[
|
||||
"[/size]\n\n",
|
||||
"\n[hr]",
|
||||
"[hr]\n",
|
||||
"\n[list",
|
||||
"[/list]\n",
|
||||
"\n[/",
|
||||
"[list]\n",
|
||||
"[list=1]\n",
|
||||
"\n[*]"],
|
||||
[
|
||||
"[/size]\n",
|
||||
"[hr]",
|
||||
"[hr]",
|
||||
"[list",
|
||||
"[/list]",
|
||||
"[/",
|
||||
"[list]",
|
||||
"[list=1]",
|
||||
"[*]"], $message
|
||||
);
|
||||
} while ($message != $oldmessage);
|
||||
|
||||
$message = str_replace(
|
||||
['[b][b]', '[/b][/b]', '[i][i]', '[/i][/i]'], ['[b]', '[/b]', '[i]', '[/i]'], $message
|
||||
);
|
||||
|
||||
// Handling Yahoo style of mails
|
||||
$message = str_replace('[hr][b]From:[/b]', '[quote][b]From:[/b]', $message);
|
||||
|
||||
// Restore code blocks
|
||||
$message = preg_replace_callback(
|
||||
'#\[codeblock-([0-9]+)\]#iU',
|
||||
function ($matches) use ($codeblocks) {
|
||||
$return = '';
|
||||
if (isset($codeblocks[intval($matches[1])])) {
|
||||
$return = $codeblocks[$matches[1]];
|
||||
}
|
||||
return $return;
|
||||
},
|
||||
$message
|
||||
);
|
||||
|
||||
$message = trim($message);
|
||||
|
||||
if ($basepath != '') {
|
||||
$message = self::qualifyURLs($message, $basepath);
|
||||
}
|
||||
|
||||
return $message;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Sub function to complete incomplete URL
|
||||
*
|
||||
* @param array $matches Result of preg_replace_callback
|
||||
* @param string $basepath Basepath that is used to complete the URL
|
||||
*
|
||||
* @return string The expanded URL
|
||||
*/
|
||||
private static function qualifyURLsSub($matches, $basepath)
|
||||
{
|
||||
$base = parse_url($basepath);
|
||||
unset($base['query']);
|
||||
unset($base['fragment']);
|
||||
|
||||
$link = $matches[0];
|
||||
$url = $matches[1];
|
||||
|
||||
$parts = array_merge($base, parse_url($url));
|
||||
$url2 = Network::unparseURL($parts);
|
||||
|
||||
return str_replace($url, $url2, $link);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Complete incomplete URLs in BBCode
|
||||
*
|
||||
* @param string $body Body with URLs
|
||||
* @param string $basepath Base path that is used to complete the URL
|
||||
*
|
||||
* @return string Body with expanded URLs
|
||||
*/
|
||||
private static function qualifyURLs($body, $basepath)
|
||||
{
|
||||
$URLSearchString = "^\[\]";
|
||||
|
||||
$matches = ["/\[url\=([$URLSearchString]*)\].*?\[\/url\]/ism",
|
||||
"/\[url\]([$URLSearchString]*)\[\/url\]/ism",
|
||||
"/\[img\=[0-9]*x[0-9]*\](.*?)\[\/img\]/ism",
|
||||
"/\[img\](.*?)\[\/img\]/ism",
|
||||
"/\[zmg\=[0-9]*x[0-9]*\](.*?)\[\/img\]/ism",
|
||||
"/\[zmg\](.*?)\[\/zmg\]/ism",
|
||||
"/\[video\](.*?)\[\/video\]/ism",
|
||||
"/\[audio\](.*?)\[\/audio\]/ism",
|
||||
];
|
||||
|
||||
foreach ($matches as $match) {
|
||||
$body = preg_replace_callback(
|
||||
$match, function ($match) use ($basepath) {
|
||||
return self::qualifyURLsSub($match, $basepath);
|
||||
},
|
||||
$body
|
||||
);
|
||||
}
|
||||
return $body;
|
||||
}
|
||||
|
||||
private static function breakLines($line, $level, $wraplength = 75)
|
||||
{
|
||||
if ($wraplength == 0) {
|
||||
$wraplength = 2000000;
|
||||
}
|
||||
|
||||
$wraplen = $wraplength - $level;
|
||||
|
||||
$newlines = [];
|
||||
|
||||
do {
|
||||
$oldline = $line;
|
||||
|
||||
$subline = substr($line, 0, $wraplen);
|
||||
|
||||
$pos = strrpos($subline, ' ');
|
||||
|
||||
if ($pos == 0) {
|
||||
$pos = strpos($line, ' ');
|
||||
}
|
||||
|
||||
if (($pos > 0) && strlen($line) > $wraplen) {
|
||||
$newline = trim(substr($line, 0, $pos));
|
||||
if ($level > 0) {
|
||||
$newline = str_repeat(">", $level) . ' ' . $newline;
|
||||
}
|
||||
|
||||
$newlines[] = $newline . " ";
|
||||
$line = substr($line, $pos + 1);
|
||||
}
|
||||
} while ((strlen($line) > $wraplen) && !($oldline == $line));
|
||||
|
||||
if ($level > 0) {
|
||||
$line = str_repeat(">", $level) . ' ' . $line;
|
||||
}
|
||||
|
||||
$newlines[] = $line;
|
||||
|
||||
return implode($newlines, "\n");
|
||||
}
|
||||
|
||||
private static function quoteLevel($message, $wraplength = 75)
|
||||
{
|
||||
$lines = explode("\n", $message);
|
||||
|
||||
$newlines = [];
|
||||
$level = 0;
|
||||
foreach ($lines as $line) {
|
||||
$line = trim($line);
|
||||
$startquote = false;
|
||||
while (strpos("*" . $line, '[quote]') > 0) {
|
||||
$level++;
|
||||
$pos = strpos($line, '[quote]');
|
||||
$line = substr($line, 0, $pos) . substr($line, $pos + 7);
|
||||
$startquote = true;
|
||||
}
|
||||
|
||||
$currlevel = $level;
|
||||
|
||||
while (strpos("*" . $line, '[/quote]') > 0) {
|
||||
$level--;
|
||||
if ($level < 0) {
|
||||
$level = 0;
|
||||
}
|
||||
|
||||
$pos = strpos($line, '[/quote]');
|
||||
$line = substr($line, 0, $pos) . substr($line, $pos + 8);
|
||||
}
|
||||
|
||||
if (!$startquote || ($line != '')) {
|
||||
$newlines[] = self::breakLines($line, $currlevel, $wraplength);
|
||||
}
|
||||
}
|
||||
|
||||
return implode($newlines, "\n");
|
||||
}
|
||||
|
||||
private static function collectURLs($message)
|
||||
{
|
||||
$pattern = '/<a.*?href="(.*?)".*?>(.*?)<\/a>/is';
|
||||
preg_match_all($pattern, $message, $result, PREG_SET_ORDER);
|
||||
|
||||
$urls = [];
|
||||
foreach ($result as $treffer) {
|
||||
$ignore = false;
|
||||
|
||||
// A list of some links that should be ignored
|
||||
$list = ["/user/", "/tag/", "/group/", "/profile/", "/search?search=", "/search?tag=", "mailto:", "/u/", "/node/",
|
||||
"//facebook.com/profile.php?id=", "//plus.google.com/", "//twitter.com/"];
|
||||
foreach ($list as $listitem) {
|
||||
if (strpos($treffer[1], $listitem) !== false) {
|
||||
$ignore = true;
|
||||
}
|
||||
}
|
||||
|
||||
if ((strpos($treffer[1], "//twitter.com/") !== false) && (strpos($treffer[1], "/status/") !== false)) {
|
||||
$ignore = false;
|
||||
}
|
||||
|
||||
if ((strpos($treffer[1], "//plus.google.com/") !== false) && (strpos($treffer[1], "/posts") !== false)) {
|
||||
$ignore = false;
|
||||
}
|
||||
|
||||
if ((strpos($treffer[1], "//plus.google.com/") !== false) && (strpos($treffer[1], "/photos") !== false)) {
|
||||
$ignore = false;
|
||||
}
|
||||
|
||||
if (!$ignore) {
|
||||
$urls[$treffer[1]] = $treffer[1];
|
||||
}
|
||||
}
|
||||
|
||||
return $urls;
|
||||
}
|
||||
|
||||
public static function toPlaintext($html, $wraplength = 75, $compact = false)
|
||||
{
|
||||
global $lang;
|
||||
|
||||
$message = str_replace("\r", "", $html);
|
||||
|
||||
$doc = new DOMDocument();
|
||||
$doc->preserveWhiteSpace = false;
|
||||
|
||||
$message = mb_convert_encoding($message, 'HTML-ENTITIES', "UTF-8");
|
||||
|
||||
@$doc->loadHTML($message);
|
||||
|
||||
$xpath = new DOMXPath($doc);
|
||||
$list = $xpath->query("//pre");
|
||||
foreach ($list as $node) {
|
||||
$node->nodeValue = str_replace("\n", "\r", $node->nodeValue);
|
||||
}
|
||||
|
||||
$message = $doc->saveHTML();
|
||||
$message = str_replace(["\n<", ">\n", "\r", "\n", "\xC3\x82\xC2\xA0"], ["<", ">", "<br>", " ", ""], $message);
|
||||
$message = preg_replace('= [\s]*=i', " ", $message);
|
||||
|
||||
// Collecting all links
|
||||
$urls = self::collectURLs($message);
|
||||
|
||||
@$doc->loadHTML($message);
|
||||
|
||||
self::tagToBBCode($doc, 'html', [], '', '');
|
||||
self::tagToBBCode($doc, 'body', [], '', '');
|
||||
|
||||
// MyBB-Auszeichnungen
|
||||
/*
|
||||
self::node2BBCode($doc, 'span', array('style'=>'text-decoration: underline;'), '_', '_');
|
||||
self::node2BBCode($doc, 'span', array('style'=>'font-style: italic;'), '/', '/');
|
||||
self::node2BBCode($doc, 'span', array('style'=>'font-weight: bold;'), '*', '*');
|
||||
|
||||
self::node2BBCode($doc, 'strong', array(), '*', '*');
|
||||
self::node2BBCode($doc, 'b', array(), '*', '*');
|
||||
self::node2BBCode($doc, 'i', array(), '/', '/');
|
||||
self::node2BBCode($doc, 'u', array(), '_', '_');
|
||||
*/
|
||||
|
||||
if ($compact) {
|
||||
self::tagToBBCode($doc, 'blockquote', [], "»", "«");
|
||||
} else {
|
||||
self::tagToBBCode($doc, 'blockquote', [], '[quote]', "[/quote]\n");
|
||||
}
|
||||
|
||||
self::tagToBBCode($doc, 'br', [], "\n", '');
|
||||
|
||||
self::tagToBBCode($doc, 'span', [], "", "");
|
||||
self::tagToBBCode($doc, 'pre', [], "", "");
|
||||
self::tagToBBCode($doc, 'div', [], "\r", "\r");
|
||||
self::tagToBBCode($doc, 'p', [], "\n", "\n");
|
||||
|
||||
//self::node2BBCode($doc, 'ul', array(), "\n[list]", "[/list]\n");
|
||||
//self::node2BBCode($doc, 'ol', array(), "\n[list=1]", "[/list]\n");
|
||||
self::tagToBBCode($doc, 'li', [], "\n* ", "\n");
|
||||
|
||||
self::tagToBBCode($doc, 'hr', [], "\n" . str_repeat("-", 70) . "\n", "");
|
||||
|
||||
self::tagToBBCode($doc, 'tr', [], "\n", "");
|
||||
self::tagToBBCode($doc, 'td', [], "\t", "");
|
||||
|
||||
self::tagToBBCode($doc, 'h1', [], "\n\n*", "*\n");
|
||||
self::tagToBBCode($doc, 'h2', [], "\n\n*", "*\n");
|
||||
self::tagToBBCode($doc, 'h3', [], "\n\n*", "*\n");
|
||||
self::tagToBBCode($doc, 'h4', [], "\n\n*", "*\n");
|
||||
self::tagToBBCode($doc, 'h5', [], "\n\n*", "*\n");
|
||||
self::tagToBBCode($doc, 'h6', [], "\n\n*", "*\n");
|
||||
|
||||
// Problem: there is no reliable way to detect if it is a link to a tag or profile
|
||||
//self::node2BBCode($doc, 'a', array('href'=>'/(.+)/'), ' $1 ', ' ', true);
|
||||
//self::node2BBCode($doc, 'a', array('href'=>'/(.+)/', 'rel'=>'oembed'), ' $1 ', '', true);
|
||||
//self::node2BBCode($doc, 'img', array('alt'=>'/(.+)/'), '$1', '');
|
||||
//self::node2BBCode($doc, 'img', array('title'=>'/(.+)/'), '$1', '');
|
||||
//self::node2BBCode($doc, 'img', array(), '', '');
|
||||
if (!$compact) {
|
||||
self::tagToBBCode($doc, 'img', ['src' => '/(.+)/'], ' [img]$1', '[/img] ');
|
||||
} else {
|
||||
self::tagToBBCode($doc, 'img', ['src' => '/(.+)/'], ' ', ' ');
|
||||
}
|
||||
|
||||
self::tagToBBCode($doc, 'iframe', ['src' => '/(.+)/'], ' $1 ', '');
|
||||
|
||||
$message = $doc->saveHTML();
|
||||
|
||||
if (!$compact) {
|
||||
$message = str_replace("[img]", "", $message);
|
||||
$message = str_replace("[/img]", "", $message);
|
||||
}
|
||||
|
||||
// was ersetze ich da?
|
||||
// Irgendein stoerrisches UTF-Zeug
|
||||
$message = str_replace(chr(194) . chr(160), ' ', $message);
|
||||
|
||||
$message = str_replace(" ", " ", $message);
|
||||
|
||||
// Aufeinanderfolgende DIVs
|
||||
$message = preg_replace('=\r *\r=i', "\n", $message);
|
||||
$message = str_replace("\r", "\n", $message);
|
||||
|
||||
$message = strip_tags($message);
|
||||
|
||||
$message = html_entity_decode($message, ENT_QUOTES, 'UTF-8');
|
||||
|
||||
if (!$compact && ($message != '')) {
|
||||
foreach ($urls as $id => $url) {
|
||||
if ($url != '' && strpos($message, $url) === false) {
|
||||
$message .= "\n" . $url . ' ';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$message = str_replace("\n«", "«\n", $message);
|
||||
$message = str_replace("»\n", "\n»", $message);
|
||||
|
||||
do {
|
||||
$oldmessage = $message;
|
||||
$message = str_replace("\n\n\n", "\n\n", $message);
|
||||
} while ($oldmessage != $message);
|
||||
|
||||
$message = self::quoteLevel(trim($message), $wraplength);
|
||||
|
||||
return trim($message);
|
||||
}
|
||||
}
|
|
@ -7,7 +7,9 @@
|
|||
namespace Friendica\Content\Text;
|
||||
|
||||
use Friendica\BaseObject;
|
||||
use Friendica\Model\Contact;
|
||||
use Michelf\MarkdownExtra;
|
||||
use Friendica\Content\Text\HTML;
|
||||
|
||||
/**
|
||||
* Friendica-specific usage of Markdown
|
||||
|
@ -36,4 +38,81 @@ class Markdown extends BaseObject
|
|||
|
||||
return $html;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Callback function to replace a Diaspora style mention in a mention for Friendica
|
||||
*
|
||||
* @param array $match Matching values for the callback
|
||||
* @return string Replaced mention
|
||||
*/
|
||||
private static function diasporaMention2BBCodeCallback($match)
|
||||
{
|
||||
if ($match[2] == '') {
|
||||
return;
|
||||
}
|
||||
|
||||
$data = Contact::getDetailsByAddr($match[2]);
|
||||
|
||||
$name = $match[1];
|
||||
|
||||
if ($name == '') {
|
||||
$name = $data['name'];
|
||||
}
|
||||
|
||||
return '@[url=' . $data['url'] . ']' . $name . '[/url]';
|
||||
}
|
||||
|
||||
/*
|
||||
* we don't want to support a bbcode specific markdown interpreter
|
||||
* and the markdown library we have is pretty good, but provides HTML output.
|
||||
* So we'll use that to convert to HTML, then convert the HTML back to bbcode,
|
||||
* and then clean up a few Diaspora specific constructs.
|
||||
*/
|
||||
public static function toBBCode($s)
|
||||
{
|
||||
$s = html_entity_decode($s, ENT_COMPAT, 'UTF-8');
|
||||
|
||||
// Handles single newlines
|
||||
$s = str_replace("\r\n", "\n", $s);
|
||||
$s = str_replace("\n", " \n", $s);
|
||||
$s = str_replace("\r", " \n", $s);
|
||||
|
||||
// Replace lonely stars in lines not starting with it with literal stars
|
||||
$s = preg_replace('/^([^\*]+)\*([^\*]*)$/im', '$1\*$2', $s);
|
||||
|
||||
// The parser cannot handle paragraphs correctly
|
||||
$s = str_replace(['</p>', '<p>', '<p dir="ltr">'], ['<br>', '<br>', '<br>'], $s);
|
||||
|
||||
// Escaping the hash tags
|
||||
$s = preg_replace('/\#([^\s\#])/', '#$1', $s);
|
||||
|
||||
$s = self::convert($s);
|
||||
|
||||
$regexp = "/@\{(?:([^\}]+?); )?([^\} ]+)\}/";
|
||||
$s = preg_replace_callback($regexp, ['self', 'diasporaMention2BBCodeCallback'], $s);
|
||||
|
||||
$s = str_replace('#', '#', $s);
|
||||
|
||||
$s = HTML::toBBCode($s);
|
||||
|
||||
// protect the recycle symbol from turning into a tag, but without unescaping angles and naked ampersands
|
||||
$s = str_replace('♲', html_entity_decode('♲', ENT_QUOTES, 'UTF-8'), $s);
|
||||
|
||||
// Convert everything that looks like a link to a link
|
||||
$s = preg_replace('/([^\]=]|^)(https?\:\/\/)([a-zA-Z0-9:\/\-?&;.=_~#%$!+,@]+(?<!,))/ism', '$1[url=$2$3]$2$3[/url]', $s);
|
||||
|
||||
//$s = preg_replace("/([^\]\=]|^)(https?\:\/\/)(vimeo|youtu|www\.youtube|soundcloud)([a-zA-Z0-9\:\/\-\?\&\;\.\=\_\~\#\%\$\!\+\,]+)/ism", '$1[url=$2$3$4]$2$3$4[/url]',$s);
|
||||
$s = BBCode::pregReplaceInTag('/\[url\=?(.*?)\]https?:\/\/www.youtube.com\/watch\?v\=(.*?)\[\/url\]/ism', '[youtube]$2[/youtube]', 'url', $s);
|
||||
$s = BBCode::pregReplaceInTag('/\[url\=https?:\/\/www.youtube.com\/watch\?v\=(.*?)\].*?\[\/url\]/ism' , '[youtube]$1[/youtube]', 'url', $s);
|
||||
$s = BBCode::pregReplaceInTag('/\[url\=?(.*?)\]https?:\/\/vimeo.com\/([0-9]+)(.*?)\[\/url\]/ism' , '[vimeo]$2[/vimeo]' , 'url', $s);
|
||||
$s = BBCode::pregReplaceInTag('/\[url\=https?:\/\/vimeo.com\/([0-9]+)\](.*?)\[\/url\]/ism' , '[vimeo]$1[/vimeo]' , 'url', $s);
|
||||
|
||||
// remove duplicate adjacent code tags
|
||||
$s = preg_replace('/(\[code\])+(.*?)(\[\/code\])+/ism', '[code]$2[/code]', $s);
|
||||
|
||||
// Don't show link to full picture (until it is fixed)
|
||||
$s = BBCode::scaleExternalImages($s, false);
|
||||
|
||||
return $s;
|
||||
}
|
||||
}
|
||||
|
|
69
src/Content/Widget/CalendarExport.php
Normal file
69
src/Content/Widget/CalendarExport.php
Normal file
|
@ -0,0 +1,69 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* @file src/Content/Widget/CalendarExport.php
|
||||
*/
|
||||
|
||||
namespace Friendica\Content\Widget;
|
||||
|
||||
use Friendica\Content\Feature;
|
||||
use Friendica\Core\L10n;
|
||||
|
||||
require_once 'boot.php';
|
||||
require_once 'include/text.php';
|
||||
|
||||
/**
|
||||
* TagCloud widget
|
||||
*
|
||||
* @author Rabuzarus
|
||||
*/
|
||||
class CalendarExport
|
||||
{
|
||||
/**
|
||||
* @brief Get the events widget.
|
||||
*
|
||||
* @return string Formated HTML of the calendar widget.
|
||||
*/
|
||||
public static function getHTML() {
|
||||
$a = get_app();
|
||||
|
||||
$owner_uid = $a->data['user']['uid'];
|
||||
|
||||
// The permission testing is a little bit tricky because we have to respect many cases.
|
||||
|
||||
// It's not the private events page (we don't get the $owner_uid for /events).
|
||||
if (!local_user() && !$owner_uid) {
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* If it's a kind of profile page (intval($owner_uid)) return if the user not logged in and
|
||||
* export feature isn't enabled.
|
||||
*/
|
||||
/*
|
||||
* Cal logged in user (test permission at foreign profile page).
|
||||
* If the $owner uid is available we know it is part of one of the profile pages (like /cal).
|
||||
* So we have to test if if it's the own profile page of the logged in user
|
||||
* or a foreign one. For foreign profile pages we need to check if the feature
|
||||
* for exporting the cal is enabled (otherwise the widget would appear for logged in users
|
||||
* on foreigen profile pages even if the widget is disabled).
|
||||
*/
|
||||
if (local_user() != $owner_uid && !Feature::isEnabled($owner_uid, "export_calendar")) {
|
||||
return;
|
||||
}
|
||||
|
||||
// $a->data is only available if the profile page is visited. If the visited page is not part
|
||||
// of the profile page it should be the personal /events page. So we can use $a->user.
|
||||
$user = defaults($a->data['user'], 'nickname', $a->user['nickname']);
|
||||
|
||||
$tpl = get_markup_template("events_aside.tpl");
|
||||
$return = replace_macros($tpl, [
|
||||
'$etitle' => L10n::t("Export"),
|
||||
'$export_ical' => L10n::t("Export calendar as ical"),
|
||||
'$export_csv' => L10n::t("Export calendar as csv"),
|
||||
'$user' => $user
|
||||
]);
|
||||
|
||||
return $return;
|
||||
}
|
||||
}
|
369
src/Core/ACL.php
Normal file
369
src/Core/ACL.php
Normal file
|
@ -0,0 +1,369 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file src/Core/Acl.php
|
||||
*/
|
||||
|
||||
namespace Friendica\Core;
|
||||
|
||||
use dba;
|
||||
use Friendica\BaseObject;
|
||||
use Friendica\Content\Feature;
|
||||
use Friendica\Database\DBM;
|
||||
use Friendica\Model\Contact;
|
||||
use Friendica\Model\GContact;
|
||||
use Friendica\Util\Network;
|
||||
use const CONTACT_IS_FRIEND;
|
||||
use const NETWORK_DFRN;
|
||||
use const NETWORK_DIASPORA;
|
||||
use const NETWORK_FACEBOOK;
|
||||
use const NETWORK_MAIL;
|
||||
use const NETWORK_OSTATUS;
|
||||
use const PHP_EOL;
|
||||
use function dbesc;
|
||||
use function defaults;
|
||||
use function get_markup_template;
|
||||
use function get_server;
|
||||
use function local_user;
|
||||
use function remote_user;
|
||||
use function replace_macros;
|
||||
|
||||
/**
|
||||
* Handle ACL management and display
|
||||
*
|
||||
* @author Hypolite Petovan <mrpetovan@gmail.com>
|
||||
*/
|
||||
class ACL extends BaseObject
|
||||
{
|
||||
/**
|
||||
* Returns a select input tag with all the contact of the local user
|
||||
*
|
||||
* @param string $selname Name attribute of the select input tag
|
||||
* @param string $selclass Class attribute of the select input tag
|
||||
* @param array $options Available options:
|
||||
* - size: length of the select box
|
||||
* - mutual_friends: Only used for the hook
|
||||
* - single: Only used for the hook
|
||||
* - exclude: Only used for the hook
|
||||
* @param array $preselected Contact ID that should be already selected
|
||||
* @return string
|
||||
*/
|
||||
public static function getSuggestContactSelectHTML($selname, $selclass, array $options = [], array $preselected = [])
|
||||
{
|
||||
$a = self::getApp();
|
||||
|
||||
$networks = null;
|
||||
|
||||
$size = defaults($options, 'size', 4);
|
||||
$mutual = !empty($options['mutual_friends']);
|
||||
$single = !empty($options['single']) && empty($options['multiple']);
|
||||
$exclude = defaults($options, 'exclude', false);
|
||||
|
||||
switch (defaults($options, 'networks', Protocol::PHANTOM)) {
|
||||
case 'DFRN_ONLY':
|
||||
$networks = [NETWORK_DFRN];
|
||||
break;
|
||||
case 'PRIVATE':
|
||||
if (!empty($a->user['prvnets'])) {
|
||||
$networks = [NETWORK_DFRN, NETWORK_MAIL, NETWORK_DIASPORA];
|
||||
} else {
|
||||
$networks = [NETWORK_DFRN, NETWORK_FACEBOOK, NETWORK_MAIL, NETWORK_DIASPORA];
|
||||
}
|
||||
break;
|
||||
case 'TWO_WAY':
|
||||
if (!empty($a->user['prvnets'])) {
|
||||
$networks = [NETWORK_DFRN, NETWORK_MAIL, NETWORK_DIASPORA];
|
||||
} else {
|
||||
$networks = [NETWORK_DFRN, NETWORK_FACEBOOK, NETWORK_MAIL, NETWORK_DIASPORA, NETWORK_OSTATUS];
|
||||
}
|
||||
break;
|
||||
default: /// @TODO Maybe log this call?
|
||||
break;
|
||||
}
|
||||
|
||||
$x = ['options' => $options, 'size' => $size, 'single' => $single, 'mutual' => $mutual, 'exclude' => $exclude, 'networks' => $networks];
|
||||
|
||||
Addon::callHooks('contact_select_options', $x);
|
||||
|
||||
$o = '';
|
||||
|
||||
$sql_extra = '';
|
||||
|
||||
if (!empty($x['mutual'])) {
|
||||
$sql_extra .= sprintf(" AND `rel` = %d ", intval(CONTACT_IS_FRIEND));
|
||||
}
|
||||
|
||||
if (!empty($x['exclude'])) {
|
||||
$sql_extra .= sprintf(" AND `id` != %d ", intval($x['exclude']));
|
||||
}
|
||||
|
||||
if (!empty($x['networks'])) {
|
||||
/// @TODO rewrite to foreach()
|
||||
array_walk($x['networks'], function (&$value) {
|
||||
$value = "'" . dbesc($value) . "'";
|
||||
});
|
||||
$str_nets = implode(',', $x['networks']);
|
||||
$sql_extra .= " AND `network` IN ( $str_nets ) ";
|
||||
}
|
||||
|
||||
$tabindex = (!empty($options['tabindex']) ? 'tabindex="' . $options["tabindex"] . '"' : '');
|
||||
|
||||
if (!empty($x['single'])) {
|
||||
$o .= "<select name=\"$selname\" id=\"$selclass\" class=\"$selclass\" size=\"" . $x['size'] . "\" $tabindex >\r\n";
|
||||
} else {
|
||||
$o .= "<select name=\"{$selname}[]\" id=\"$selclass\" class=\"$selclass\" multiple=\"multiple\" size=\"" . $x['size'] . "$\" $tabindex >\r\n";
|
||||
}
|
||||
|
||||
$stmt = dba::p("SELECT `id`, `name`, `url`, `network` FROM `contact`
|
||||
WHERE `uid` = ? AND NOT `self` AND NOT `blocked` AND NOT `pending` AND NOT `archive` AND `notify` != ''
|
||||
$sql_extra
|
||||
ORDER BY `name` ASC ", intval(local_user())
|
||||
);
|
||||
|
||||
$contacts = dba::inArray($stmt);
|
||||
|
||||
$arr = ['contact' => $contacts, 'entry' => $o];
|
||||
|
||||
// e.g. 'network_pre_contact_deny', 'profile_pre_contact_allow'
|
||||
Addon::callHooks($a->module . '_pre_' . $selname, $arr);
|
||||
|
||||
if (DBM::is_result($contacts)) {
|
||||
foreach ($contacts as $contact) {
|
||||
if (in_array($contact['id'], $preselected)) {
|
||||
$selected = ' selected="selected" ';
|
||||
} else {
|
||||
$selected = '';
|
||||
}
|
||||
|
||||
$trimmed = mb_substr($contact['name'], 0, 20);
|
||||
|
||||
$o .= "<option value=\"{$contact['id']}\" $selected title=\"{$contact['name']}|{$contact['url']}\" >$trimmed</option>\r\n";
|
||||
}
|
||||
}
|
||||
|
||||
$o .= '</select>' . PHP_EOL;
|
||||
|
||||
Addon::callHooks($a->module . '_post_' . $selname, $o);
|
||||
|
||||
return $o;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a select input tag with all the contact of the local user
|
||||
*
|
||||
* @param string $selname Name attribute of the select input tag
|
||||
* @param string $selclass Class attribute of the select input tag
|
||||
* @param array $preselected Contact IDs that should be already selected
|
||||
* @param int $size Length of the select box
|
||||
* @param int $tabindex Select input tag tabindex attribute
|
||||
* @return string
|
||||
*/
|
||||
public static function getMessageContactSelectHTML($selname, $selclass, array $preselected = [], $size = 4, $tabindex = null)
|
||||
{
|
||||
$a = self::getApp();
|
||||
|
||||
$o = '';
|
||||
|
||||
// When used for private messages, we limit correspondence to mutual DFRN/Friendica friends and the selector
|
||||
// to one recipient. By default our selector allows multiple selects amongst all contacts.
|
||||
$sql_extra = sprintf(" AND `rel` = %d ", intval(CONTACT_IS_FRIEND));
|
||||
$sql_extra .= sprintf(" AND `network` IN ('%s' , '%s') ", NETWORK_DFRN, NETWORK_DIASPORA);
|
||||
|
||||
$tabindex_attr = !empty($tabindex) ? ' tabindex="' . intval($tabindex) . '"' : '';
|
||||
|
||||
$hidepreselected = '';
|
||||
if ($preselected) {
|
||||
$sql_extra .= " AND `id` IN (" . implode(",", $preselected) . ")";
|
||||
$hidepreselected = ' style="display: none;"';
|
||||
}
|
||||
|
||||
$o .= "<select name=\"$selname\" id=\"$selclass\" class=\"$selclass\" size=\"$size\"$tabindex_attr$hidepreselected>\r\n";
|
||||
|
||||
$stmt = dba::p("SELECT `id`, `name`, `url`, `network` FROM `contact`
|
||||
WHERE `uid` = ? AND NOT `self` AND NOT `blocked` AND NOT `pending` AND NOT `archive` AND `notify` != ''
|
||||
$sql_extra
|
||||
ORDER BY `name` ASC ", intval(local_user())
|
||||
);
|
||||
|
||||
$contacts = dba::inArray($stmt);
|
||||
|
||||
$arr = ['contact' => $contacts, 'entry' => $o];
|
||||
|
||||
// e.g. 'network_pre_contact_deny', 'profile_pre_contact_allow'
|
||||
Addon::callHooks($a->module . '_pre_' . $selname, $arr);
|
||||
|
||||
$receiverlist = [];
|
||||
|
||||
if (DBM::is_result($contacts)) {
|
||||
foreach ($contacts as $contact) {
|
||||
if (in_array($contact['id'], $preselected)) {
|
||||
$selected = ' selected="selected"';
|
||||
} else {
|
||||
$selected = '';
|
||||
}
|
||||
|
||||
$trimmed = Protocol::formatMention($contact['url'], $contact['name']);
|
||||
|
||||
$receiverlist[] = $trimmed;
|
||||
|
||||
$o .= "<option value=\"{$contact['id']}\"$selected title=\"{$contact['name']}|{$contact['url']}\" >$trimmed</option>\r\n";
|
||||
}
|
||||
}
|
||||
|
||||
$o .= '</select>' . PHP_EOL;
|
||||
|
||||
if ($preselected) {
|
||||
$o .= implode(', ', $receiverlist);
|
||||
}
|
||||
|
||||
Addon::callHooks($a->module . '_post_' . $selname, $o);
|
||||
|
||||
return $o;
|
||||
}
|
||||
|
||||
private static function fixACL(&$item)
|
||||
{
|
||||
$item = intval(str_replace(['<', '>'], ['', ''], $item));
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the default permission of the provided user array
|
||||
*
|
||||
* @param array $user
|
||||
* @return array Hash of contact id lists
|
||||
*/
|
||||
public static function getDefaultUserPermissions(array $user = null)
|
||||
{
|
||||
$matches = [];
|
||||
|
||||
$acl_regex = '/<([0-9]+)>/i';
|
||||
|
||||
preg_match_all($acl_regex, defaults($user, 'allow_cid', ''), $matches);
|
||||
$allow_cid = $matches[1];
|
||||
preg_match_all($acl_regex, defaults($user, 'allow_gid', ''), $matches);
|
||||
$allow_gid = $matches[1];
|
||||
preg_match_all($acl_regex, defaults($user, 'deny_cid', ''), $matches);
|
||||
$deny_cid = $matches[1];
|
||||
preg_match_all($acl_regex, defaults($user, 'deny_gid', ''), $matches);
|
||||
$deny_gid = $matches[1];
|
||||
|
||||
// Reformats the ACL data so that it is accepted by the JS frontend
|
||||
array_walk($allow_cid, 'self::fixACL');
|
||||
array_walk($allow_gid, 'self::fixACL');
|
||||
array_walk($deny_cid, 'self::fixACL');
|
||||
array_walk($deny_gid, 'self::fixACL');
|
||||
|
||||
Contact::pruneUnavailable($allow_cid);
|
||||
|
||||
return [
|
||||
'allow_cid' => $allow_cid,
|
||||
'allow_gid' => $allow_gid,
|
||||
'deny_cid' => $deny_cid,
|
||||
'deny_gid' => $deny_gid,
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the full jot ACL selector HTML
|
||||
*
|
||||
* @param array $user
|
||||
* @param bool $show_jotnets
|
||||
* @return string
|
||||
*/
|
||||
public static function getFullSelectorHTML(array $user = null, $show_jotnets = false)
|
||||
{
|
||||
$perms = self::getDefaultUserPermissions($user);
|
||||
|
||||
$jotnets = '';
|
||||
if ($show_jotnets) {
|
||||
$imap_disabled = !function_exists('imap_open') || Config::get('system', 'imap_disabled');
|
||||
|
||||
$mail_enabled = false;
|
||||
$pubmail_enabled = false;
|
||||
|
||||
if (!$imap_disabled) {
|
||||
$mailacct = dba::selectFirst('mailacct', ['pubmail'], ['`uid` = ? AND `server` != ""', local_user()]);
|
||||
if (DBM::is_result($mailacct)) {
|
||||
$mail_enabled = true;
|
||||
$pubmail_enabled = !empty($mailacct['pubmail']);
|
||||
}
|
||||
}
|
||||
|
||||
if (empty($user['hidewall'])) {
|
||||
if ($mail_enabled) {
|
||||
$selected = $pubmail_enabled ? ' checked="checked"' : '';
|
||||
$jotnets .= '<div class="profile-jot-net"><input type="checkbox" name="pubmail_enable"' . $selected . ' value="1" /> ' . L10n::t("Post to Email") . '</div>';
|
||||
}
|
||||
|
||||
Addon::callHooks('jot_networks', $jotnets);
|
||||
} else {
|
||||
$jotnets .= L10n::t('Connectors disabled, since "%s" is enabled.',
|
||||
L10n::t('Hide your profile details from unknown viewers?'));
|
||||
}
|
||||
}
|
||||
|
||||
$tpl = get_markup_template('acl_selector.tpl');
|
||||
$o = replace_macros($tpl, [
|
||||
'$showall' => L10n::t('Visible to everybody'),
|
||||
'$show' => L10n::t('show'),
|
||||
'$hide' => L10n::t('don\'t show'),
|
||||
'$allowcid' => json_encode($perms['allow_cid']),
|
||||
'$allowgid' => json_encode($perms['allow_gid']),
|
||||
'$denycid' => json_encode($perms['deny_cid']),
|
||||
'$denygid' => json_encode($perms['deny_gid']),
|
||||
'$networks' => $show_jotnets,
|
||||
'$emailcc' => L10n::t('CC: email addresses'),
|
||||
'$emtitle' => L10n::t('Example: bob@example.com, mary@example.com'),
|
||||
'$jotnets' => $jotnets,
|
||||
'$aclModalTitle' => L10n::t('Permissions'),
|
||||
'$aclModalDismiss' => L10n::t('Close'),
|
||||
'$features' => [
|
||||
'aclautomention' => Feature::isEnabled($user['uid'], 'aclautomention') ? 'true' : 'false'
|
||||
],
|
||||
]);
|
||||
|
||||
return $o;
|
||||
}
|
||||
|
||||
/**
|
||||
* Searching for global contacts for autocompletion
|
||||
*
|
||||
* @brief Searching for global contacts for autocompletion
|
||||
* @param string $search Name or part of a name or nick
|
||||
* @param string $mode Search mode (e.g. "community")
|
||||
* @return array with the search results
|
||||
*/
|
||||
public static function contactAutocomplete($search, $mode)
|
||||
{
|
||||
if ((Config::get('system', 'block_public')) && (!local_user()) && (!remote_user())) {
|
||||
return [];
|
||||
}
|
||||
|
||||
// don't search if search term has less than 2 characters
|
||||
if (!$search || mb_strlen($search) < 2) {
|
||||
return [];
|
||||
}
|
||||
|
||||
if (substr($search, 0, 1) === '@') {
|
||||
$search = substr($search, 1);
|
||||
}
|
||||
|
||||
// check if searching in the local global contact table is enabled
|
||||
if (Config::get('system', 'poco_local_search')) {
|
||||
$return = GContact::searchByName($search, $mode);
|
||||
} else {
|
||||
$a = self::getApp();
|
||||
$p = $a->pager['page'] != 1 ? '&p=' . $a->pager['page'] : '';
|
||||
|
||||
$response = Network::curl(get_server() . '/lsearch?f=' . $p . '&search=' . urlencode($search));
|
||||
if ($response['success']) {
|
||||
$lsearch = json_decode($response['body'], true);
|
||||
if (!empty($lsearch['results'])) {
|
||||
$return = $lsearch['results'];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return defaults($return, []);
|
||||
}
|
||||
}
|
|
@ -4,83 +4,59 @@
|
|||
*/
|
||||
namespace Friendica\Core;
|
||||
|
||||
use Friendica\Core\Cache;
|
||||
use Friendica\Core\Config;
|
||||
use Friendica\Database\DBM;
|
||||
use Friendica\Util\DateTimeFormat;
|
||||
use dba;
|
||||
use Memcache;
|
||||
|
||||
require_once 'include/dba.php';
|
||||
|
||||
/**
|
||||
* @brief Class for storing data for a short time
|
||||
*/
|
||||
class Cache
|
||||
class Cache extends \Friendica\BaseObject
|
||||
{
|
||||
const MONTH = 2592000;
|
||||
const WEEK = 604800;
|
||||
const DAY = 86400;
|
||||
const HOUR = 3600;
|
||||
const HALF_HOUR = 1800;
|
||||
const QUARTER_HOUR = 900;
|
||||
const FIVE_MINUTES = 300;
|
||||
const MINUTE = 60;
|
||||
|
||||
/**
|
||||
* @brief Check for Memcache and open a connection if configured
|
||||
*
|
||||
* @return Memcache|boolean The Memcache object - or "false" if not successful
|
||||
* @var Cache\ICacheDriver
|
||||
*/
|
||||
public static function memcache()
|
||||
static $driver = null;
|
||||
|
||||
public static function init()
|
||||
{
|
||||
if (!class_exists('Memcache', false)) {
|
||||
return false;
|
||||
switch(Config::get('system', 'cache_driver', 'database')) {
|
||||
case 'memcache':
|
||||
$memcache_host = Config::get('system', 'memcache_host', '127.0.0.1');
|
||||
$memcache_port = Config::get('system', 'memcache_port', 11211);
|
||||
|
||||
self::$driver = new Cache\MemcacheCacheDriver($memcache_host, $memcache_port);
|
||||
break;
|
||||
case 'memcached':
|
||||
$memcached_hosts = Config::get('system', 'memcached_hosts', [['127.0.0.1', 11211]]);
|
||||
|
||||
self::$driver = new Cache\MemcachedCacheDriver($memcached_hosts);
|
||||
break;
|
||||
default:
|
||||
self::$driver = new Cache\DatabaseCacheDriver();
|
||||
}
|
||||
|
||||
if (!Config::get('system', 'memcache')) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$memcache_host = Config::get('system', 'memcache_host', '127.0.0.1');
|
||||
$memcache_port = Config::get('system', 'memcache_port', 11211);
|
||||
|
||||
$memcache = new Memcache();
|
||||
|
||||
if (!$memcache->connect($memcache_host, $memcache_port)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return $memcache;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Return the duration for a given cache level
|
||||
* Returns the current cache driver
|
||||
*
|
||||
* @param integer $level Cache level
|
||||
*
|
||||
* @return integer The cache duration in seconds
|
||||
* @return Cache\ICacheDriver
|
||||
*/
|
||||
private static function duration($level)
|
||||
private static function getDriver()
|
||||
{
|
||||
switch ($level) {
|
||||
case CACHE_MONTH:
|
||||
$seconds = 2592000;
|
||||
break;
|
||||
case CACHE_WEEK:
|
||||
$seconds = 604800;
|
||||
break;
|
||||
case CACHE_DAY:
|
||||
$seconds = 86400;
|
||||
break;
|
||||
case CACHE_HOUR:
|
||||
$seconds = 3600;
|
||||
break;
|
||||
case CACHE_HALF_HOUR:
|
||||
$seconds = 1800;
|
||||
break;
|
||||
case CACHE_QUARTER_HOUR:
|
||||
$seconds = 900;
|
||||
break;
|
||||
case CACHE_FIVE_MINUTES:
|
||||
$seconds = 300;
|
||||
break;
|
||||
case CACHE_MINUTE:
|
||||
default:
|
||||
$seconds = 60;
|
||||
break;
|
||||
if (self::$driver === null) {
|
||||
self::init();
|
||||
}
|
||||
return $seconds;
|
||||
|
||||
return self::$driver;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -92,40 +68,13 @@ class Cache
|
|||
*/
|
||||
public static function get($key)
|
||||
{
|
||||
$memcache = self::memcache();
|
||||
if (is_object($memcache)) {
|
||||
// We fetch with the hostname as key to avoid problems with other applications
|
||||
$cached = $memcache->get(get_app()->get_hostname().":".$key);
|
||||
$value = @unserialize($cached);
|
||||
$time = microtime(true);
|
||||
|
||||
// Only return a value if the serialized value is valid.
|
||||
// We also check if the db entry is a serialized
|
||||
// boolean 'false' value (which we want to return).
|
||||
if ($cached === serialize(false) || $value !== false) {
|
||||
return $value;
|
||||
}
|
||||
$return = self::getDriver()->get($key);
|
||||
|
||||
return null;
|
||||
}
|
||||
self::getApp()->save_timestamp($time, 'cache');
|
||||
|
||||
// Frequently clear cache
|
||||
self::clear();
|
||||
|
||||
$cache = dba::selectFirst('cache', ['v'], ['k' => $key]);
|
||||
|
||||
if (DBM::is_result($cache)) {
|
||||
$cached = $cache['v'];
|
||||
$value = @unserialize($cached);
|
||||
|
||||
// Only return a value if the serialized value is valid.
|
||||
// We also check if the db entry is a serialized
|
||||
// boolean 'false' value (which we want to return).
|
||||
if ($cached === serialize(false) || $value !== false) {
|
||||
return $value;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
return $return;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -137,20 +86,35 @@ class Cache
|
|||
* @param mixed $value The value that is about to be stored
|
||||
* @param integer $duration The cache lifespan
|
||||
*
|
||||
* @return void
|
||||
* @return bool
|
||||
*/
|
||||
public static function set($key, $value, $duration = CACHE_MONTH)
|
||||
public static function set($key, $value, $duration = self::MONTH)
|
||||
{
|
||||
// Do we have an installed memcache? Use it instead.
|
||||
$memcache = self::memcache();
|
||||
if (is_object($memcache)) {
|
||||
// We store with the hostname as key to avoid problems with other applications
|
||||
$memcache->set(get_app()->get_hostname().":".$key, serialize($value), MEMCACHE_COMPRESSED, self::duration($duration));
|
||||
return;
|
||||
}
|
||||
$fields = ['v' => serialize($value), 'expire_mode' => $duration, 'updated' => DateTimeFormat::utcNow()];
|
||||
$condition = ['k' => $key];
|
||||
dba::update('cache', $fields, $condition, true);
|
||||
$time = microtime(true);
|
||||
|
||||
$return = self::getDriver()->set($key, $value, $duration);
|
||||
|
||||
self::getApp()->save_timestamp($time, 'cache_write');
|
||||
|
||||
return $return;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Delete a value from the cache
|
||||
*
|
||||
* @param string $key The key to the cached data
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public static function delete($key)
|
||||
{
|
||||
$time = microtime(true);
|
||||
|
||||
$return = self::getDriver()->delete($key);
|
||||
|
||||
self::getApp()->save_timestamp($time, 'cache_write');
|
||||
|
||||
return $return;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -160,76 +124,8 @@ class Cache
|
|||
*
|
||||
* @return void
|
||||
*/
|
||||
public static function clear($max_level = CACHE_MONTH)
|
||||
public static function clear()
|
||||
{
|
||||
// Clear long lasting cache entries only once a day
|
||||
if (Config::get("system", "cache_cleared_day") < time() - self::duration(CACHE_DAY)) {
|
||||
if ($max_level == CACHE_MONTH) {
|
||||
$condition = ["`updated` < ? AND `expire_mode` = ?",
|
||||
DateTimeFormat::utc("now - 30 days"),
|
||||
CACHE_MONTH];
|
||||
dba::delete('cache', $condition);
|
||||
}
|
||||
|
||||
if ($max_level <= CACHE_WEEK) {
|
||||
$condition = ["`updated` < ? AND `expire_mode` = ?",
|
||||
DateTimeFormat::utc("now - 7 days"),
|
||||
CACHE_WEEK];
|
||||
dba::delete('cache', $condition);
|
||||
}
|
||||
|
||||
if ($max_level <= CACHE_DAY) {
|
||||
$condition = ["`updated` < ? AND `expire_mode` = ?",
|
||||
DateTimeFormat::utc("now - 1 days"),
|
||||
CACHE_DAY];
|
||||
dba::delete('cache', $condition);
|
||||
}
|
||||
Config::set("system", "cache_cleared_day", time());
|
||||
}
|
||||
|
||||
if (($max_level <= CACHE_HOUR) && (Config::get("system", "cache_cleared_hour")) < time() - self::duration(CACHE_HOUR)) {
|
||||
$condition = ["`updated` < ? AND `expire_mode` = ?",
|
||||
DateTimeFormat::utc("now - 1 hours"),
|
||||
CACHE_HOUR];
|
||||
dba::delete('cache', $condition);
|
||||
|
||||
Config::set("system", "cache_cleared_hour", time());
|
||||
}
|
||||
|
||||
if (($max_level <= CACHE_HALF_HOUR) && (Config::get("system", "cache_cleared_half_hour")) < time() - self::duration(CACHE_HALF_HOUR)) {
|
||||
$condition = ["`updated` < ? AND `expire_mode` = ?",
|
||||
DateTimeFormat::utc("now - 30 minutes"),
|
||||
CACHE_HALF_HOUR];
|
||||
dba::delete('cache', $condition);
|
||||
|
||||
Config::set("system", "cache_cleared_half_hour", time());
|
||||
}
|
||||
|
||||
if (($max_level <= CACHE_QUARTER_HOUR) && (Config::get("system", "cache_cleared_quarter_hour")) < time() - self::duration(CACHE_QUARTER_HOUR)) {
|
||||
$condition = ["`updated` < ? AND `expire_mode` = ?",
|
||||
DateTimeFormat::utc("now - 15 minutes"),
|
||||
CACHE_QUARTER_HOUR];
|
||||
dba::delete('cache', $condition);
|
||||
|
||||
Config::set("system", "cache_cleared_quarter_hour", time());
|
||||
}
|
||||
|
||||
if (($max_level <= CACHE_FIVE_MINUTES) && (Config::get("system", "cache_cleared_five_minute")) < time() - self::duration(CACHE_FIVE_MINUTES)) {
|
||||
$condition = ["`updated` < ? AND `expire_mode` = ?",
|
||||
DateTimeFormat::utc("now - 5 minutes"),
|
||||
CACHE_FIVE_MINUTES];
|
||||
dba::delete('cache', $condition);
|
||||
|
||||
Config::set("system", "cache_cleared_five_minute", time());
|
||||
}
|
||||
|
||||
if (($max_level <= CACHE_MINUTE) && (Config::get("system", "cache_cleared_minute")) < time() - self::duration(CACHE_MINUTE)) {
|
||||
$condition = ["`updated` < ? AND `expire_mode` = ?",
|
||||
DateTimeFormat::utc("now - 1 minutes"),
|
||||
CACHE_MINUTE];
|
||||
dba::delete('cache', $condition);
|
||||
|
||||
Config::set("system", "cache_cleared_minute", time());
|
||||
}
|
||||
return self::getDriver()->clear();
|
||||
}
|
||||
}
|
||||
|
|
56
src/Core/Cache/DatabaseCacheDriver.php
Normal file
56
src/Core/Cache/DatabaseCacheDriver.php
Normal file
|
@ -0,0 +1,56 @@
|
|||
<?php
|
||||
|
||||
namespace Friendica\Core\Cache;
|
||||
|
||||
use dba;
|
||||
use Friendica\Core\Cache;
|
||||
use Friendica\Database\DBM;
|
||||
use Friendica\Util\DateTimeFormat;
|
||||
|
||||
/**
|
||||
* Database Cache Driver
|
||||
*
|
||||
* @author Hypolite Petovan <mrpetovan@gmail.com>
|
||||
*/
|
||||
class DatabaseCacheDriver implements ICacheDriver
|
||||
{
|
||||
public function get($key)
|
||||
{
|
||||
$cache = dba::selectFirst('cache', ['v'], ['`k` = ? AND `expires` >= ?', $key, DateTimeFormat::utcNow()]);
|
||||
|
||||
if (DBM::is_result($cache)) {
|
||||
$cached = $cache['v'];
|
||||
$value = @unserialize($cached);
|
||||
|
||||
// Only return a value if the serialized value is valid.
|
||||
// We also check if the db entry is a serialized
|
||||
// boolean 'false' value (which we want to return).
|
||||
if ($cached === serialize(false) || $value !== false) {
|
||||
return $value;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public function set($key, $value, $duration = Cache::MONTH)
|
||||
{
|
||||
$fields = [
|
||||
'v' => serialize($value),
|
||||
'expires' => DateTimeFormat::utc('now + ' . $duration . ' seconds'),
|
||||
'updated' => DateTimeFormat::utcNow()
|
||||
];
|
||||
|
||||
return dba::update('cache', $fields, ['k' => $key], true);
|
||||
}
|
||||
|
||||
public function delete($key)
|
||||
{
|
||||
return dba::delete('cache', ['k' => $key]);
|
||||
}
|
||||
|
||||
public function clear()
|
||||
{
|
||||
return dba::delete('cache', ['`expires` < NOW()']);
|
||||
}
|
||||
}
|
50
src/Core/Cache/ICacheDriver.php
Normal file
50
src/Core/Cache/ICacheDriver.php
Normal file
|
@ -0,0 +1,50 @@
|
|||
<?php
|
||||
|
||||
namespace Friendica\Core\Cache;
|
||||
|
||||
use Friendica\Core\Cache;
|
||||
|
||||
/**
|
||||
* Cache Driver Interface
|
||||
*
|
||||
* @author Hypolite Petovan <mrpetovan@gmail.com>
|
||||
*/
|
||||
interface ICacheDriver
|
||||
{
|
||||
/**
|
||||
* Fetches cached data according to the key
|
||||
*
|
||||
* @param string $key The key to the cached data
|
||||
*
|
||||
* @return mixed Cached $value or "null" if not found
|
||||
*/
|
||||
public function get($key);
|
||||
|
||||
/**
|
||||
* Stores data in the cache identified by the key. The input $value can have multiple formats.
|
||||
*
|
||||
* @param string $key The cache key
|
||||
* @param mixed $value The value to store
|
||||
* @param integer $duration The cache lifespan, must be one of the Cache constants
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function set($key, $value, $duration = Cache::MONTH);
|
||||
|
||||
|
||||
/**
|
||||
* Delete a key from the cache
|
||||
*
|
||||
* @param string $key
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function delete($key);
|
||||
|
||||
/**
|
||||
* Remove outdated data from the cache
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function clear();
|
||||
}
|
77
src/Core/Cache/MemcacheCacheDriver.php
Normal file
77
src/Core/Cache/MemcacheCacheDriver.php
Normal file
|
@ -0,0 +1,77 @@
|
|||
<?php
|
||||
|
||||
namespace Friendica\Core\Cache;
|
||||
|
||||
use Friendica\BaseObject;
|
||||
use Friendica\Core\Cache;
|
||||
|
||||
/**
|
||||
* Memcache Cache Driver
|
||||
*
|
||||
* @author Hypolite Petovan <mrpetovan@gmail.com>
|
||||
*/
|
||||
class MemcacheCacheDriver extends BaseObject implements ICacheDriver
|
||||
{
|
||||
/**
|
||||
* @var Memcache
|
||||
*/
|
||||
private $memcache;
|
||||
|
||||
public function __construct($memcache_host, $memcache_port)
|
||||
{
|
||||
if (!class_exists('Memcache', false)) {
|
||||
throw new \Exception('Memcache class isn\'t available');
|
||||
}
|
||||
|
||||
$this->memcache = new \Memcache();
|
||||
|
||||
if (!$this->memcache->connect($memcache_host, $memcache_port)) {
|
||||
throw new \Exception('Expected Memcache server at ' . $memcache_host . ':' . $memcache_port . ' isn\'t available');
|
||||
}
|
||||
}
|
||||
|
||||
public function get($key)
|
||||
{
|
||||
$return = null;
|
||||
|
||||
// We fetch with the hostname as key to avoid problems with other applications
|
||||
$cached = $this->memcache->get(self::getApp()->get_hostname() . ':' . $key);
|
||||
|
||||
// @see http://php.net/manual/en/memcache.get.php#84275
|
||||
if (is_bool($cached) || is_double($cached) || is_long($cached)) {
|
||||
return $return;
|
||||
}
|
||||
|
||||
$value = @unserialize($cached);
|
||||
|
||||
// Only return a value if the serialized value is valid.
|
||||
// We also check if the db entry is a serialized
|
||||
// boolean 'false' value (which we want to return).
|
||||
if ($cached === serialize(false) || $value !== false) {
|
||||
$return = $value;
|
||||
}
|
||||
|
||||
return $return;
|
||||
}
|
||||
|
||||
public function set($key, $value, $duration = Cache::MONTH)
|
||||
{
|
||||
// We store with the hostname as key to avoid problems with other applications
|
||||
return $this->memcache->set(
|
||||
self::getApp()->get_hostname() . ":" . $key,
|
||||
serialize($value),
|
||||
MEMCACHE_COMPRESSED,
|
||||
time() + $duration
|
||||
);
|
||||
}
|
||||
|
||||
public function delete($key)
|
||||
{
|
||||
return $this->memcache->delete($key);
|
||||
}
|
||||
|
||||
public function clear()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
68
src/Core/Cache/MemcachedCacheDriver.php
Normal file
68
src/Core/Cache/MemcachedCacheDriver.php
Normal file
|
@ -0,0 +1,68 @@
|
|||
<?php
|
||||
|
||||
namespace Friendica\Core\Cache;
|
||||
|
||||
use Friendica\BaseObject;
|
||||
use Friendica\Core\Cache;
|
||||
|
||||
/**
|
||||
* Memcached Cache Driver
|
||||
*
|
||||
* @author Hypolite Petovan <mrpetovan@gmail.com>
|
||||
*/
|
||||
class MemcachedCacheDriver extends BaseObject implements ICacheDriver
|
||||
{
|
||||
/**
|
||||
* @var Memcached
|
||||
*/
|
||||
private $memcached;
|
||||
|
||||
public function __construct(array $memcached_hosts)
|
||||
{
|
||||
if (!class_exists('Memcached', false)) {
|
||||
throw new \Exception('Memcached class isn\'t available');
|
||||
}
|
||||
|
||||
$this->memcached = new \Memcached();
|
||||
|
||||
$this->memcached->addServers($memcached_hosts);
|
||||
|
||||
if (count($this->memcached->getServerList()) == 0) {
|
||||
throw new \Exception('Expected Memcached servers aren\'t available, config:' . var_export($memcached_hosts, true));
|
||||
}
|
||||
}
|
||||
|
||||
public function get($key)
|
||||
{
|
||||
$return = null;
|
||||
|
||||
// We fetch with the hostname as key to avoid problems with other applications
|
||||
$value = $this->memcached->get(self::getApp()->get_hostname() . ':' . $key);
|
||||
|
||||
if ($this->memcached->getResultCode() === \Memcached::RES_SUCCESS) {
|
||||
$return = $value;
|
||||
}
|
||||
|
||||
return $return;
|
||||
}
|
||||
|
||||
public function set($key, $value, $duration = Cache::MONTH)
|
||||
{
|
||||
// We store with the hostname as key to avoid problems with other applications
|
||||
return $this->memcached->set(
|
||||
self::getApp()->get_hostname() . ":" . $key,
|
||||
$value,
|
||||
time() + $duration
|
||||
);
|
||||
}
|
||||
|
||||
public function delete($key)
|
||||
{
|
||||
return $this->memcached->delete($key);
|
||||
}
|
||||
|
||||
public function clear()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
|
@ -8,26 +8,33 @@
|
|||
*/
|
||||
namespace Friendica\Core;
|
||||
|
||||
use Friendica\Database\DBM;
|
||||
use dba;
|
||||
use Friendica\BaseObject;
|
||||
use Friendica\Core\Config;
|
||||
|
||||
require_once 'include/dba.php';
|
||||
|
||||
/**
|
||||
* @brief Arbitrary sytem configuration storage
|
||||
* @brief Arbitrary system configuration storage
|
||||
*
|
||||
* Note:
|
||||
* If we ever would decide to return exactly the variable type as entered,
|
||||
* we will have fun with the additional features. :-)
|
||||
*
|
||||
* The config class always returns strings but in the default features
|
||||
* we use a "false" to determine if the config value isn't set.
|
||||
*
|
||||
*/
|
||||
class Config
|
||||
class Config extends BaseObject
|
||||
{
|
||||
private static $cache;
|
||||
private static $in_db;
|
||||
/**
|
||||
* @var Friendica\Core\Config\IConfigAdapter
|
||||
*/
|
||||
private static $adapter = null;
|
||||
|
||||
public static function init()
|
||||
{
|
||||
if (self::getApp()->getConfigValue('system', 'config_adapter') == 'preload') {
|
||||
self::$adapter = new Config\PreloadConfigAdapter();
|
||||
} else {
|
||||
self::$adapter = new Config\JITConfigAdapter();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Loads all configuration values of family into a cached storage.
|
||||
|
@ -41,26 +48,11 @@ class Config
|
|||
*/
|
||||
public static function load($family = "config")
|
||||
{
|
||||
// We don't preload "system" anymore.
|
||||
// This reduces the number of database reads a lot.
|
||||
if ($family === 'system') {
|
||||
return;
|
||||
if (empty(self::$adapter)) {
|
||||
self::init();
|
||||
}
|
||||
|
||||
$a = get_app();
|
||||
|
||||
$r = dba::select('config', ['v', 'k'], ['cat' => $family]);
|
||||
while ($rr = dba::fetch($r)) {
|
||||
$k = $rr['k'];
|
||||
if ($family === 'config') {
|
||||
$a->config[$k] = $rr['v'];
|
||||
} else {
|
||||
$a->config[$family][$k] = $rr['v'];
|
||||
self::$cache[$family][$k] = $rr['v'];
|
||||
self::$in_db[$family][$k] = true;
|
||||
}
|
||||
}
|
||||
dba::close($r);
|
||||
self::$adapter->load($family);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -84,40 +76,11 @@ class Config
|
|||
*/
|
||||
public static function get($family, $key, $default_value = null, $refresh = false)
|
||||
{
|
||||
$a = get_app();
|
||||
|
||||
if (!$refresh) {
|
||||
// Do we have the cached value? Then return it
|
||||
if (isset(self::$cache[$family][$key])) {
|
||||
if (self::$cache[$family][$key] === '!<unset>!') {
|
||||
return $default_value;
|
||||
} else {
|
||||
return self::$cache[$family][$key];
|
||||
}
|
||||
}
|
||||
if (empty(self::$adapter)) {
|
||||
self::init();
|
||||
}
|
||||
|
||||
$config = dba::selectFirst('config', ['v'], ['cat' => $family, 'k' => $key]);
|
||||
if (DBM::is_result($config)) {
|
||||
// manage array value
|
||||
$val = (preg_match("|^a:[0-9]+:{.*}$|s", $config['v']) ? unserialize($config['v']) : $config['v']);
|
||||
|
||||
// Assign the value from the database to the cache
|
||||
self::$cache[$family][$key] = $val;
|
||||
self::$in_db[$family][$key] = true;
|
||||
return $val;
|
||||
} elseif (isset($a->config[$family][$key])) {
|
||||
// Assign the value (mostly) from the .htconfig.php to the cache
|
||||
self::$cache[$family][$key] = $a->config[$family][$key];
|
||||
self::$in_db[$family][$key] = false;
|
||||
|
||||
return $a->config[$family][$key];
|
||||
}
|
||||
|
||||
self::$cache[$family][$key] = '!<unset>!';
|
||||
self::$in_db[$family][$key] = false;
|
||||
|
||||
return $default_value;
|
||||
return self::$adapter->get($family, $key, $default_value, $refresh);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -136,38 +99,11 @@ class Config
|
|||
*/
|
||||
public static function set($family, $key, $value)
|
||||
{
|
||||
$a = get_app();
|
||||
|
||||
// We store our setting values in a string variable.
|
||||
// So we have to do the conversion here so that the compare below works.
|
||||
// The exception are array values.
|
||||
$dbvalue = (!is_array($value) ? (string)$value : $value);
|
||||
|
||||
$stored = self::get($family, $key, null, true);
|
||||
|
||||
if (($stored === $dbvalue) && self::$in_db[$family][$key]) {
|
||||
return true;
|
||||
if (empty(self::$adapter)) {
|
||||
self::init();
|
||||
}
|
||||
|
||||
if ($family === 'config') {
|
||||
$a->config[$key] = $dbvalue;
|
||||
} elseif ($family != 'system') {
|
||||
$a->config[$family][$key] = $dbvalue;
|
||||
}
|
||||
|
||||
// Assign the just added value to the cache
|
||||
self::$cache[$family][$key] = $dbvalue;
|
||||
|
||||
// manage array value
|
||||
$dbvalue = (is_array($value) ? serialize($value) : $dbvalue);
|
||||
|
||||
$ret = dba::update('config', ['v' => $dbvalue], ['cat' => $family, 'k' => $key], true);
|
||||
|
||||
if ($ret) {
|
||||
self::$in_db[$family][$key] = true;
|
||||
return $value;
|
||||
}
|
||||
return $ret;
|
||||
return self::$adapter->set($family, $key, $value);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -183,13 +119,10 @@ class Config
|
|||
*/
|
||||
public static function delete($family, $key)
|
||||
{
|
||||
if (isset(self::$cache[$family][$key])) {
|
||||
unset(self::$cache[$family][$key]);
|
||||
unset(self::$in_db[$family][$key]);
|
||||
if (empty(self::$adapter)) {
|
||||
self::init();
|
||||
}
|
||||
|
||||
$ret = dba::delete('config', ['cat' => $family, 'k' => $key]);
|
||||
|
||||
return $ret;
|
||||
return self::$adapter->delete($family, $key);
|
||||
}
|
||||
}
|
||||
|
|
72
src/Core/Config/IConfigAdapter.php
Normal file
72
src/Core/Config/IConfigAdapter.php
Normal file
|
@ -0,0 +1,72 @@
|
|||
<?php
|
||||
|
||||
namespace Friendica\Core\Config;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Hypolite Petovan <mrpetovan@gmail.com>
|
||||
*/
|
||||
interface IConfigAdapter
|
||||
{
|
||||
/**
|
||||
* @brief Loads all configuration values into a cached storage.
|
||||
*
|
||||
* All configuration values of the system are stored in global cache
|
||||
* which is available under the global variable $a->config
|
||||
*
|
||||
* @param string $cat The category of the configuration values to load
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function load($cat = "config");
|
||||
|
||||
/**
|
||||
* @brief Get a particular user's config variable given the category name
|
||||
* ($family) and a key.
|
||||
*
|
||||
* Get a particular config value from the given category ($family)
|
||||
* and the $key from a cached storage in $a->config[$uid].
|
||||
* $instore is only used by the set_config function
|
||||
* to determine if the key already exists in the DB
|
||||
* If a key is found in the DB but doesn't exist in
|
||||
* local config cache, pull it into the cache so we don't have
|
||||
* to hit the DB again for this item.
|
||||
*
|
||||
* @param string $cat The category of the configuration value
|
||||
* @param string $k The configuration key to query
|
||||
* @param mixed $default_value optional, The value to return if key is not set (default: null)
|
||||
* @param boolean $refresh optional, If true the config is loaded from the db and not from the cache (default: false)
|
||||
*
|
||||
* @return mixed Stored value or null if it does not exist
|
||||
*/
|
||||
public function get($cat, $k, $default_value = null, $refresh = false);
|
||||
|
||||
/**
|
||||
* @brief Sets a configuration value for system config
|
||||
*
|
||||
* Stores a config value ($value) in the category ($family) under the key ($key)
|
||||
* for the user_id $uid.
|
||||
*
|
||||
* Note: Please do not store booleans - convert to 0/1 integer values!
|
||||
*
|
||||
* @param string $family The category of the configuration value
|
||||
* @param string $key The configuration key to set
|
||||
* @param mixed $value The value to store
|
||||
*
|
||||
* @return mixed Stored $value or false if the database update failed
|
||||
*/
|
||||
public function set($cat, $k, $value);
|
||||
|
||||
/**
|
||||
* @brief Deletes the given key from the system configuration.
|
||||
*
|
||||
* Removes the configured value from the stored cache in $a->config
|
||||
* and removes it from the database.
|
||||
*
|
||||
* @param string $cat The category of the configuration value
|
||||
* @param string $k The configuration key to delete
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function delete($cat, $k);
|
||||
}
|
77
src/Core/Config/IPConfigAdapter.php
Normal file
77
src/Core/Config/IPConfigAdapter.php
Normal file
|
@ -0,0 +1,77 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* To change this license header, choose License Headers in Project Properties.
|
||||
* To change this template file, choose Tools | Templates
|
||||
* and open the template in the editor.
|
||||
*/
|
||||
|
||||
namespace Friendica\Core\Config;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author benlo
|
||||
*/
|
||||
interface IPConfigAdapter
|
||||
{
|
||||
/**
|
||||
* @brief Loads all configuration values of a user's config family into a cached storage.
|
||||
*
|
||||
* All configuration values of the given user are stored in global cache
|
||||
* which is available under the global variable $a->config[$uid].
|
||||
*
|
||||
* @param string $uid The user_id
|
||||
* @param string $cat The category of the configuration value
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function load($uid, $cat);
|
||||
|
||||
/**
|
||||
* @brief Get a particular user's config variable given the category name
|
||||
* ($family) and a key.
|
||||
*
|
||||
* Get a particular user's config value from the given category ($family)
|
||||
* and the $key from a cached storage in $a->config[$uid].
|
||||
*
|
||||
* @param string $uid The user_id
|
||||
* @param string $cat The category of the configuration value
|
||||
* @param string $k The configuration key to query
|
||||
* @param mixed $default_value optional, The value to return if key is not set (default: null)
|
||||
* @param boolean $refresh optional, If true the config is loaded from the db and not from the cache (default: false)
|
||||
*
|
||||
* @return mixed Stored value or null if it does not exist
|
||||
*/
|
||||
public function get($uid, $cat, $k, $default_value = null, $refresh = false);
|
||||
|
||||
/**
|
||||
* @brief Sets a configuration value for a user
|
||||
*
|
||||
* Stores a config value ($value) in the category ($family) under the key ($key)
|
||||
* for the user_id $uid.
|
||||
*
|
||||
* @note Please do not store booleans - convert to 0/1 integer values!
|
||||
*
|
||||
* @param string $uid The user_id
|
||||
* @param string $cat The category of the configuration value
|
||||
* @param string $k The configuration key to set
|
||||
* @param string $value The value to store
|
||||
*
|
||||
* @return mixed Stored $value or false
|
||||
*/
|
||||
public function set($uid, $cat, $k, $value);
|
||||
|
||||
/**
|
||||
* @brief Deletes the given key from the users's configuration.
|
||||
*
|
||||
* Removes the configured value from the stored cache in $a->config[$uid]
|
||||
* and removes it from the database.
|
||||
*
|
||||
* @param string $uid The user_id
|
||||
* @param string $cat The category of the configuration value
|
||||
* @param string $k The configuration key to delete
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function delete($uid, $cat, $k);
|
||||
}
|
126
src/Core/Config/JITConfigAdapter.php
Normal file
126
src/Core/Config/JITConfigAdapter.php
Normal file
|
@ -0,0 +1,126 @@
|
|||
<?php
|
||||
namespace Friendica\Core\Config;
|
||||
|
||||
use dba;
|
||||
use Friendica\BaseObject;
|
||||
use Friendica\Database\DBM;
|
||||
|
||||
require_once 'include/dba.php';
|
||||
|
||||
/**
|
||||
* JustInTime Configuration Adapter
|
||||
*
|
||||
* Default Config Adapter. Provides the best performance for pages loading few configuration variables.
|
||||
*
|
||||
* @author Hypolite Petovan <mrpetovan@gmail.com>
|
||||
*/
|
||||
class JITConfigAdapter extends BaseObject implements IConfigAdapter
|
||||
{
|
||||
private $cache;
|
||||
private $in_db;
|
||||
|
||||
public function load($cat = "config")
|
||||
{
|
||||
// We don't preload "system" anymore.
|
||||
// This reduces the number of database reads a lot.
|
||||
if ($cat === 'system') {
|
||||
return;
|
||||
}
|
||||
|
||||
$configs = dba::select('config', ['v', 'k'], ['cat' => $cat]);
|
||||
while ($config = dba::fetch($configs)) {
|
||||
$k = $config['k'];
|
||||
|
||||
self::getApp()->setConfigValue($cat, $k, $config['v']);
|
||||
|
||||
if ($cat !== 'config') {
|
||||
$this->cache[$cat][$k] = $config['v'];
|
||||
$this->in_db[$cat][$k] = true;
|
||||
}
|
||||
}
|
||||
dba::close($configs);
|
||||
}
|
||||
|
||||
public function get($cat, $k, $default_value = null, $refresh = false)
|
||||
{
|
||||
$a = self::getApp();
|
||||
|
||||
if (!$refresh) {
|
||||
// Do we have the cached value? Then return it
|
||||
if (isset($this->cache[$cat][$k])) {
|
||||
if ($this->cache[$cat][$k] === '!<unset>!') {
|
||||
return $default_value;
|
||||
} else {
|
||||
return $this->cache[$cat][$k];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$config = dba::selectFirst('config', ['v'], ['cat' => $cat, 'k' => $k]);
|
||||
if (DBM::is_result($config)) {
|
||||
// manage array value
|
||||
$value = (preg_match("|^a:[0-9]+:{.*}$|s", $config['v']) ? unserialize($config['v']) : $config['v']);
|
||||
|
||||
// Assign the value from the database to the cache
|
||||
$this->cache[$cat][$k] = $value;
|
||||
$this->in_db[$cat][$k] = true;
|
||||
return $value;
|
||||
} elseif (isset($a->config[$cat][$k])) {
|
||||
// Assign the value (mostly) from the .htconfig.php to the cache
|
||||
$this->cache[$cat][$k] = $a->config[$cat][$k];
|
||||
$this->in_db[$cat][$k] = false;
|
||||
|
||||
return $a->config[$cat][$k];
|
||||
}
|
||||
|
||||
$this->cache[$cat][$k] = '!<unset>!';
|
||||
$this->in_db[$cat][$k] = false;
|
||||
|
||||
return $default_value;
|
||||
}
|
||||
|
||||
public function set($cat, $k, $value)
|
||||
{
|
||||
$a = self::getApp();
|
||||
|
||||
// We store our setting values in a string variable.
|
||||
// So we have to do the conversion here so that the compare below works.
|
||||
// The exception are array values.
|
||||
$dbvalue = (!is_array($value) ? (string)$value : $value);
|
||||
|
||||
$stored = $this->get($cat, $k, null, true);
|
||||
|
||||
if (($stored === $dbvalue) && $this->in_db[$cat][$k]) {
|
||||
return true;
|
||||
}
|
||||
|
||||
self::getApp()->setConfigValue($cat, $k, $value);
|
||||
|
||||
// Assign the just added value to the cache
|
||||
$this->cache[$cat][$k] = $dbvalue;
|
||||
|
||||
// manage array value
|
||||
$dbvalue = (is_array($value) ? serialize($value) : $dbvalue);
|
||||
|
||||
$result = dba::update('config', ['v' => $dbvalue], ['cat' => $cat, 'k' => $k], true);
|
||||
|
||||
if ($result) {
|
||||
$this->in_db[$cat][$k] = true;
|
||||
return $value;
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
public function delete($cat, $k)
|
||||
{
|
||||
if (isset($this->cache[$cat][$k])) {
|
||||
unset($this->cache[$cat][$k]);
|
||||
unset($this->in_db[$cat][$k]);
|
||||
}
|
||||
|
||||
$result = dba::delete('config', ['cat' => $cat, 'k' => $k]);
|
||||
|
||||
return $result;
|
||||
}
|
||||
}
|
119
src/Core/Config/JITPConfigAdapter.php
Normal file
119
src/Core/Config/JITPConfigAdapter.php
Normal file
|
@ -0,0 +1,119 @@
|
|||
<?php
|
||||
namespace Friendica\Core\Config;
|
||||
|
||||
use dba;
|
||||
use Friendica\BaseObject;
|
||||
use Friendica\Database\DBM;
|
||||
|
||||
require_once 'include/dba.php';
|
||||
|
||||
/**
|
||||
* JustInTime User Configuration Adapter
|
||||
*
|
||||
* Default PConfig Adapter. Provides the best performance for pages loading few configuration variables.
|
||||
*
|
||||
* @author Hypolite Petovan <mrpetovan@gmail.com>
|
||||
*/
|
||||
class JITPConfigAdapter extends BaseObject implements IPConfigAdapter
|
||||
{
|
||||
private $in_db;
|
||||
|
||||
public function load($uid, $cat)
|
||||
{
|
||||
$a = self::getApp();
|
||||
|
||||
$pconfigs = dba::select('pconfig', ['v', 'k'], ['cat' => $cat, 'uid' => $uid]);
|
||||
if (DBM::is_result($pconfigs)) {
|
||||
while ($pconfig = dba::fetch($pconfigs)) {
|
||||
$k = $pconfig['k'];
|
||||
|
||||
self::getApp()->setPConfigValue($uid, $cat, $k, $pconfig['v']);
|
||||
|
||||
$this->in_db[$uid][$cat][$k] = true;
|
||||
}
|
||||
} else if ($cat != 'config') {
|
||||
// Negative caching
|
||||
$a->config[$uid][$cat] = "!<unset>!";
|
||||
}
|
||||
dba::close($pconfigs);
|
||||
}
|
||||
|
||||
public function get($uid, $cat, $k, $default_value = null, $refresh = false)
|
||||
{
|
||||
$a = self::getApp();
|
||||
|
||||
if (!$refresh) {
|
||||
// Looking if the whole family isn't set
|
||||
if (isset($a->config[$uid][$cat])) {
|
||||
if ($a->config[$uid][$cat] === '!<unset>!') {
|
||||
return $default_value;
|
||||
}
|
||||
}
|
||||
|
||||
if (isset($a->config[$uid][$cat][$k])) {
|
||||
if ($a->config[$uid][$cat][$k] === '!<unset>!') {
|
||||
return $default_value;
|
||||
}
|
||||
return $a->config[$uid][$cat][$k];
|
||||
}
|
||||
}
|
||||
|
||||
$pconfig = dba::selectFirst('pconfig', ['v'], ['uid' => $uid, 'cat' => $cat, 'k' => $k]);
|
||||
if (DBM::is_result($pconfig)) {
|
||||
$val = (preg_match("|^a:[0-9]+:{.*}$|s", $pconfig['v']) ? unserialize($pconfig['v']) : $pconfig['v']);
|
||||
|
||||
self::getApp()->setPConfigValue($uid, $cat, $k, $val);
|
||||
|
||||
$this->in_db[$uid][$cat][$k] = true;
|
||||
|
||||
return $val;
|
||||
} else {
|
||||
self::getApp()->setPConfigValue($uid, $cat, $k, '!<unset>!');
|
||||
|
||||
$this->in_db[$uid][$cat][$k] = false;
|
||||
|
||||
return $default_value;
|
||||
}
|
||||
}
|
||||
|
||||
public function set($uid, $cat, $k, $value)
|
||||
{
|
||||
// We store our setting values in a string variable.
|
||||
// So we have to do the conversion here so that the compare below works.
|
||||
// The exception are array values.
|
||||
$dbvalue = (!is_array($value) ? (string)$value : $value);
|
||||
|
||||
$stored = $this->get($uid, $cat, $k, null, true);
|
||||
|
||||
if (($stored === $dbvalue) && $this->in_db[$uid][$cat][$k]) {
|
||||
return true;
|
||||
}
|
||||
|
||||
self::getApp()->setPConfigValue($uid, $cat, $k, $value);
|
||||
|
||||
// manage array value
|
||||
$dbvalue = (is_array($value) ? serialize($value) : $dbvalue);
|
||||
|
||||
$result = dba::update('pconfig', ['v' => $dbvalue], ['uid' => $uid, 'cat' => $cat, 'k' => $k], true);
|
||||
|
||||
if ($result) {
|
||||
$this->in_db[$uid][$cat][$k] = true;
|
||||
return $value;
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
public function delete($uid, $cat, $k)
|
||||
{
|
||||
self::getApp()->deletePConfigValue($uid, $cat, $k);
|
||||
|
||||
if (!empty($this->in_db[$uid][$cat][$k])) {
|
||||
unset($this->in_db[$uid][$cat][$k]);
|
||||
}
|
||||
|
||||
$result = dba::delete('pconfig', ['uid' => $uid, 'cat' => $cat, 'k' => $k]);
|
||||
|
||||
return $result;
|
||||
}
|
||||
}
|
90
src/Core/Config/PreloadConfigAdapter.php
Normal file
90
src/Core/Config/PreloadConfigAdapter.php
Normal file
|
@ -0,0 +1,90 @@
|
|||
<?php
|
||||
|
||||
namespace Friendica\Core\Config;
|
||||
|
||||
use dba;
|
||||
use Exception;
|
||||
use Friendica\App;
|
||||
use Friendica\BaseObject;
|
||||
use Friendica\Database\DBM;
|
||||
|
||||
require_once 'include/dba.php';
|
||||
|
||||
/**
|
||||
* Preload Configuration Adapter
|
||||
*
|
||||
* Minimizes the number of database queries to retrieve configuration values at the cost of memory.
|
||||
*
|
||||
* @author Hypolite Petovan <mrpetovan@gmail.com>
|
||||
*/
|
||||
class PreloadConfigAdapter extends BaseObject implements IConfigAdapter
|
||||
{
|
||||
private $config_loaded = false;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this->load();
|
||||
}
|
||||
|
||||
public function load($family = 'config')
|
||||
{
|
||||
if ($this->config_loaded) {
|
||||
return;
|
||||
}
|
||||
|
||||
$configs = dba::select('config', ['cat', 'v', 'k']);
|
||||
while ($config = dba::fetch($configs)) {
|
||||
self::getApp()->setConfigValue($config['cat'], $config['k'], $config['v']);
|
||||
}
|
||||
dba::close($configs);
|
||||
|
||||
$this->config_loaded = true;
|
||||
}
|
||||
|
||||
public function get($cat, $k, $default_value = null, $refresh = false)
|
||||
{
|
||||
if ($refresh) {
|
||||
$config = dba::selectFirst('config', ['v'], ['cat' => $cat, 'k' => $k]);
|
||||
if (DBM::is_result($config)) {
|
||||
self::getApp()->setConfigValue($cat, $k, $config['v']);
|
||||
}
|
||||
}
|
||||
|
||||
$return = self::getApp()->getConfigValue($cat, $k, $default_value);
|
||||
|
||||
return $return;
|
||||
}
|
||||
|
||||
public function set($cat, $k, $value)
|
||||
{
|
||||
// We store our setting values as strings.
|
||||
// So we have to do the conversion here so that the compare below works.
|
||||
// The exception are array values.
|
||||
$compare_value = !is_array($value) ? (string)$value : $value;
|
||||
|
||||
if (self::getApp()->getConfigValue($cat, $k) === $compare_value) {
|
||||
return true;
|
||||
}
|
||||
|
||||
self::getApp()->setConfigValue($cat, $k, $value);
|
||||
|
||||
// manage array value
|
||||
$dbvalue = is_array($value) ? serialize($value) : $value;
|
||||
|
||||
$result = dba::update('config', ['v' => $dbvalue], ['cat' => $cat, 'k' => $k], true);
|
||||
if (!$result) {
|
||||
throw new Exception('Unable to store config value in [' . $cat . '][' . $k . ']');
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public function delete($cat, $k)
|
||||
{
|
||||
self::getApp()->deleteConfigValue($cat, $k);
|
||||
|
||||
$result = dba::delete('config', ['cat' => $cat, 'k' => $k]);
|
||||
|
||||
return $result;
|
||||
}
|
||||
}
|
92
src/Core/Config/PreloadPConfigAdapter.php
Normal file
92
src/Core/Config/PreloadPConfigAdapter.php
Normal file
|
@ -0,0 +1,92 @@
|
|||
<?php
|
||||
|
||||
namespace Friendica\Core\Config;
|
||||
|
||||
use dba;
|
||||
use Exception;
|
||||
use Friendica\App;
|
||||
use Friendica\BaseObject;
|
||||
use Friendica\Database\DBM;
|
||||
|
||||
require_once 'include/dba.php';
|
||||
|
||||
/**
|
||||
* Preload User Configuration Adapter
|
||||
*
|
||||
* Minimizes the number of database queries to retrieve configuration values at the cost of memory.
|
||||
*
|
||||
* @author Hypolite Petovan <mrpetovan@gmail.com>
|
||||
*/
|
||||
class PreloadPConfigAdapter extends BaseObject implements IPConfigAdapter
|
||||
{
|
||||
private $config_loaded = false;
|
||||
|
||||
public function __construct($uid)
|
||||
{
|
||||
$this->load($uid, 'config');
|
||||
}
|
||||
|
||||
public function load($uid, $family)
|
||||
{
|
||||
if ($this->config_loaded) {
|
||||
return;
|
||||
}
|
||||
|
||||
$pconfigs = dba::select('pconfig', ['cat', 'v', 'k'], ['uid' => $uid]);
|
||||
while ($pconfig = dba::fetch($pconfigs)) {
|
||||
self::getApp()->setPConfigValue($uid, $pconfig['cat'], $pconfig['k'], $pconfig['v']);
|
||||
}
|
||||
dba::close($pconfigs);
|
||||
|
||||
$this->config_loaded = true;
|
||||
}
|
||||
|
||||
public function get($uid, $cat, $k, $default_value = null, $refresh = false)
|
||||
{
|
||||
if ($refresh) {
|
||||
$config = dba::selectFirst('pconfig', ['v'], ['uid' => $uid, 'cat' => $cat, 'k' => $k]);
|
||||
if (DBM::is_result($config)) {
|
||||
self::getApp()->setPConfigValue($uid, $cat, $k, $config['v']);
|
||||
} else {
|
||||
self::getApp()->deletePConfigValue($uid, $cat, $k);
|
||||
}
|
||||
}
|
||||
|
||||
$return = self::getApp()->getPConfigValue($uid, $cat, $k, $default_value);
|
||||
|
||||
return $return;
|
||||
}
|
||||
|
||||
public function set($uid, $cat, $k, $value)
|
||||
{
|
||||
// We store our setting values as strings.
|
||||
// So we have to do the conversion here so that the compare below works.
|
||||
// The exception are array values.
|
||||
$compare_value = !is_array($value) ? (string)$value : $value;
|
||||
|
||||
if (self::getApp()->getPConfigValue($uid, $cat, $k) === $compare_value) {
|
||||
return true;
|
||||
}
|
||||
|
||||
self::getApp()->setPConfigValue($uid, $cat, $k, $value);
|
||||
|
||||
// manage array value
|
||||
$dbvalue = is_array($value) ? serialize($value) : $value;
|
||||
|
||||
$result = dba::update('pconfig', ['v' => $dbvalue], ['uid' => $uid, 'cat' => $cat, 'k' => $k], true);
|
||||
if (!$result) {
|
||||
throw new Exception('Unable to store config value in [' . $uid . '][' . $cat . '][' . $k . ']');
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public function delete($uid, $cat, $k)
|
||||
{
|
||||
self::getApp()->deletePConfigValue($uid, $cat, $k);
|
||||
|
||||
$result = dba::delete('pconfig', ['uid' => $uid, 'cat' => $cat, 'k' => $k]);
|
||||
|
||||
return $result;
|
||||
}
|
||||
}
|
123
src/Core/Console.php
Normal file
123
src/Core/Console.php
Normal file
|
@ -0,0 +1,123 @@
|
|||
<?php
|
||||
|
||||
namespace Friendica\Core;
|
||||
|
||||
/**
|
||||
* Description of Console
|
||||
*
|
||||
* @author Hypolite Petovan <mrpetovan@gmail.com>
|
||||
*/
|
||||
class Console extends \Asika\SimpleConsole\Console
|
||||
{
|
||||
// Disables the default help handling
|
||||
protected $helpOptions = [];
|
||||
protected $customHelpOptions = ['h', 'help', '?'];
|
||||
|
||||
protected $subConsoles = [
|
||||
'config' => __NAMESPACE__ . '\Console\Config',
|
||||
'createdoxygen' => __NAMESPACE__ . '\Console\CreateDoxygen',
|
||||
'docbloxerrorchecker' => __NAMESPACE__ . '\Console\DocBloxErrorChecker',
|
||||
'dbstructure' => __NAMESPACE__ . '\Console\DatabaseStructure',
|
||||
'extract' => __NAMESPACE__ . '\Console\Extract',
|
||||
'globalcommunityblock' => __NAMESPACE__ . '\Console\GlobalCommunityBlock',
|
||||
'globalcommunitysilence' => __NAMESPACE__ . '\Console\GlobalCommunitySilence',
|
||||
'maintenance' => __NAMESPACE__ . '\Console\Maintenance',
|
||||
'php2po' => __NAMESPACE__ . '\Console\PhpToPo',
|
||||
'po2php' => __NAMESPACE__ . '\Console\PoToPhp',
|
||||
'typo' => __NAMESPACE__ . '\Console\Typo',
|
||||
];
|
||||
|
||||
protected function getHelp()
|
||||
{
|
||||
$help = <<<HELP
|
||||
Usage: bin/console [--version] [-h|--help|-?] <command> [<args>] [-v]
|
||||
|
||||
Commands:
|
||||
config Edit site config
|
||||
createdoxygen Generate Doxygen headers
|
||||
dbstructure Do database updates
|
||||
docbloxerrorchecker Check the file tree for DocBlox errors
|
||||
extract Generate translation string file for the Friendica project (deprecated)
|
||||
globalcommunityblock Block remote profile from interacting with this node
|
||||
globalcommunitysilence Silence remote profile from global community page
|
||||
help Show help about a command, e.g (bin/console help config)
|
||||
maintenance Set maintenance mode for this node
|
||||
php2po Generate a messages.po file from a strings.php file
|
||||
po2php Generate a strings.php file from a messages.po file
|
||||
typo Checks for parse errors in Friendica files
|
||||
|
||||
Options:
|
||||
-h|--help|-? Show help information
|
||||
-v Show more debug information.
|
||||
HELP;
|
||||
return $help;
|
||||
}
|
||||
|
||||
protected function doExecute()
|
||||
{
|
||||
if ($this->getOption('v')) {
|
||||
$this->out('Executable: ' . $this->executable);
|
||||
$this->out('Arguments: ' . var_export($this->args, true));
|
||||
$this->out('Options: ' . var_export($this->options, true));
|
||||
}
|
||||
|
||||
$showHelp = false;
|
||||
$subHelp = false;
|
||||
$command = null;
|
||||
|
||||
if ($this->getOption('version')) {
|
||||
$this->out('Friendica Console version ' . FRIENDICA_VERSION);
|
||||
|
||||
return 0;
|
||||
} elseif ((count($this->options) === 0 || $this->getOption($this->customHelpOptions) === true || $this->getOption($this->customHelpOptions) === 1) && count($this->args) === 0
|
||||
) {
|
||||
$showHelp = true;
|
||||
} elseif (count($this->args) >= 2 && $this->getArgument(0) == 'help') {
|
||||
$command = $this->getArgument(1);
|
||||
$subHelp = true;
|
||||
array_shift($this->args);
|
||||
array_shift($this->args);
|
||||
} elseif (count($this->args) >= 1) {
|
||||
$command = $this->getArgument(0);
|
||||
array_shift($this->args);
|
||||
}
|
||||
|
||||
if (is_null($command)) {
|
||||
$this->out($this->getHelp());
|
||||
return 0;
|
||||
}
|
||||
|
||||
$console = $this->getSubConsole($command);
|
||||
|
||||
if ($subHelp) {
|
||||
$console->setOption($this->customHelpOptions, true);
|
||||
}
|
||||
|
||||
return $console->execute();
|
||||
}
|
||||
|
||||
private function getSubConsole($command)
|
||||
{
|
||||
if ($this->getOption('v')) {
|
||||
$this->out('Command: ' . $command);
|
||||
}
|
||||
|
||||
if (!isset($this->subConsoles[$command])) {
|
||||
throw new \Asika\SimpleConsole\CommandArgsException('Command ' . $command . ' doesn\'t exist');
|
||||
}
|
||||
|
||||
$subargs = $this->args;
|
||||
array_unshift($subargs, $this->executable);
|
||||
|
||||
$className = $this->subConsoles[$command];
|
||||
|
||||
$subconsole = new $className($subargs);
|
||||
|
||||
foreach ($this->options as $name => $value) {
|
||||
$subconsole->setOption($name, $value);
|
||||
}
|
||||
|
||||
return $subconsole;
|
||||
}
|
||||
|
||||
}
|
135
src/Core/Console/Config.php
Normal file
135
src/Core/Console/Config.php
Normal file
|
@ -0,0 +1,135 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* To change this license header, choose License Headers in Project Properties.
|
||||
* To change this template file, choose Tools | Templates
|
||||
* and open the template in the editor.
|
||||
*/
|
||||
|
||||
namespace Friendica\Core\Console;
|
||||
|
||||
use Asika\SimpleConsole\CommandArgsException;
|
||||
use dba;
|
||||
use Friendica\Core;
|
||||
|
||||
require_once 'include/dba.php';
|
||||
require_once 'include/text.php';
|
||||
|
||||
/**
|
||||
* @brief tool to access the system config from the CLI
|
||||
*
|
||||
* With this script you can access the system configuration of your node from
|
||||
* the CLI. You can do both, reading current values stored in the database and
|
||||
* set new values to config variables.
|
||||
*
|
||||
* Usage:
|
||||
* If you specify no parameters at the CLI, the script will list all config
|
||||
* variables defined.
|
||||
*
|
||||
* If you specify one parameter, the script will list all config variables
|
||||
* defined in this section of the configuration (e.g. "system").
|
||||
*
|
||||
* If you specify two parameters, the script will show you the current value
|
||||
* of the named configuration setting. (e.g. "system loglevel")
|
||||
*
|
||||
* If you specify three parameters, the named configuration setting will be
|
||||
* set to the value of the last parameter. (e.g. "system loglevel 0" will
|
||||
* disable logging)
|
||||
*
|
||||
* @author Tobias Diekershoff
|
||||
* @author Hypolite Petovan <mrpetovan@gmail.com>
|
||||
*/
|
||||
class Config extends \Asika\SimpleConsole\Console
|
||||
{
|
||||
protected $helpOptions = ['h', 'help', '?'];
|
||||
|
||||
protected function getHelp()
|
||||
{
|
||||
$help = <<<HELP
|
||||
console config - Manage site configuration
|
||||
Synopsis
|
||||
bin/console config [-h|--help|-?] [-v]
|
||||
bin/console config <category> [-h|--help|-?] [-v]
|
||||
bin/console config <category> <key> [-h|--help|-?] [-v]
|
||||
bin/console config <category> <key> <value> [-h|--help|-?] [-v]
|
||||
|
||||
Description
|
||||
bin/console config
|
||||
Lists all config values
|
||||
|
||||
bin/console config <category>
|
||||
Lists all config values in the provided category
|
||||
|
||||
bin/console config <category> <key>
|
||||
Shows the value of the provided key in the category
|
||||
|
||||
bin/console config <category> <key> <value>
|
||||
Sets the value of the provided key in the category
|
||||
|
||||
Notes:
|
||||
Setting config entries which are manually set in .htconfig.php may result in
|
||||
conflict between database settings and the manual startup settings.
|
||||
|
||||
Options
|
||||
-h|--help|-? Show help information
|
||||
-v Show more debug information.
|
||||
HELP;
|
||||
return $help;
|
||||
}
|
||||
|
||||
protected function doExecute()
|
||||
{
|
||||
if ($this->getOption('v')) {
|
||||
$this->out('Executable: ' . $this->executable);
|
||||
$this->out('Class: ' . __CLASS__);
|
||||
$this->out('Arguments: ' . var_export($this->args, true));
|
||||
$this->out('Options: ' . var_export($this->options, true));
|
||||
}
|
||||
|
||||
if (count($this->args) > 3) {
|
||||
throw new CommandArgsException('Too many arguments');
|
||||
}
|
||||
|
||||
require_once '.htconfig.php';
|
||||
$result = dba::connect($db_host, $db_user, $db_pass, $db_data);
|
||||
unset($db_host, $db_user, $db_pass, $db_data);
|
||||
|
||||
if (!$result) {
|
||||
throw new \RuntimeException('Unable to connect to database');
|
||||
}
|
||||
|
||||
if (count($this->args) == 3) {
|
||||
Core\Config::set($this->getArgument(0), $this->getArgument(1), $this->getArgument(2));
|
||||
$this->out("config[{$this->getArgument(0)}][{$this->getArgument(1)}] = " . Core\Config::get($this->getArgument(0),
|
||||
$this->getArgument(1)));
|
||||
}
|
||||
|
||||
if (count($this->args) == 2) {
|
||||
$this->out("config[{$this->getArgument(0)}][{$this->getArgument(1)}] = " . Core\Config::get($this->getArgument(0),
|
||||
$this->getArgument(1)));
|
||||
}
|
||||
|
||||
if (count($this->args) == 1) {
|
||||
Core\Config::load($this->getArgument(0));
|
||||
|
||||
$a = get_app();
|
||||
if (!is_null($a->config[$this->getArgument(0)])) {
|
||||
foreach ($a->config[$this->getArgument(0)] as $k => $x) {
|
||||
$this->out("config[{$this->getArgument(0)}][{$k}] = " . $x);
|
||||
}
|
||||
} else {
|
||||
$this->out('Config section ' . $this->getArgument(0) . ' returned nothing');
|
||||
}
|
||||
}
|
||||
|
||||
if (count($this->args) == 0) {
|
||||
$configs = dba::select('config');
|
||||
foreach ($configs as $config) {
|
||||
$this->out("config[{$config['cat']}][{$config['k']}] = " . $config['v']);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
}
|
148
src/Core/Console/CreateDoxygen.php
Normal file
148
src/Core/Console/CreateDoxygen.php
Normal file
|
@ -0,0 +1,148 @@
|
|||
<?php
|
||||
|
||||
namespace Friendica\Core\Console;
|
||||
|
||||
/**
|
||||
* Description of CreateDoxygen
|
||||
*
|
||||
* @author Hypolite Petovan <mrpetovan@gmail.com>
|
||||
*/
|
||||
class CreateDoxygen extends \Asika\SimpleConsole\Console
|
||||
{
|
||||
protected $helpOptions = ['h', 'help', '?'];
|
||||
|
||||
protected function getHelp()
|
||||
{
|
||||
$help = <<<HELP
|
||||
console createdoxygen - Generate Doxygen headers
|
||||
Usage
|
||||
bin/console createdoxygen <file> [-h|--help|-?] [-v]
|
||||
|
||||
Description
|
||||
Outputs the provided file with added Doxygen headers to functions
|
||||
|
||||
Options
|
||||
-h|--help|-? Show help information
|
||||
-v Show more debug information.
|
||||
HELP;
|
||||
return $help;
|
||||
}
|
||||
|
||||
protected function doExecute()
|
||||
{
|
||||
if ($this->getOption('v')) {
|
||||
$this->out('Class: ' . __CLASS__);
|
||||
$this->out('Arguments: ' . var_export($this->args, true));
|
||||
$this->out('Options: ' . var_export($this->options, true));
|
||||
}
|
||||
|
||||
if (count($this->args) == 0) {
|
||||
$this->out($this->getHelp());
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (count($this->args) > 1) {
|
||||
throw new \Asika\SimpleConsole\CommandArgsException('Too many arguments');
|
||||
}
|
||||
|
||||
$file = $this->getArgument(0);
|
||||
if (!file_exists($file)) {
|
||||
throw new \RuntimeException('Unable to find specified file.');
|
||||
}
|
||||
|
||||
$data = file_get_contents($file);
|
||||
|
||||
$lines = explode("\n", $data);
|
||||
|
||||
$previous = "";
|
||||
|
||||
foreach ($lines AS $line) {
|
||||
$line = rtrim(trim($line, "\r"));
|
||||
|
||||
if (strstr(strtolower($line), "function")) {
|
||||
$detect = strtolower(trim($line));
|
||||
$detect = implode(" ", explode(" ", $detect));
|
||||
|
||||
$found = false;
|
||||
|
||||
if (substr($detect, 0, 9) == "function ") {
|
||||
$found = true;
|
||||
}
|
||||
|
||||
if (substr($detect, 0, 19) == "protected function ") {
|
||||
$found = true;
|
||||
}
|
||||
|
||||
if (substr($detect, 0, 17) == "private function ") {
|
||||
$found = true;
|
||||
}
|
||||
|
||||
if (substr($detect, 0, 23) == "public static function ") {
|
||||
$found = true;
|
||||
}
|
||||
|
||||
if (substr($detect, 0, 24) == "private static function ") {
|
||||
$found = true;
|
||||
}
|
||||
|
||||
if (substr($detect, 0, 10) == "function (") {
|
||||
$found = false;
|
||||
}
|
||||
|
||||
if ($found && ( trim($previous) == "*/")) {
|
||||
$found = false;
|
||||
}
|
||||
|
||||
if ($found) {
|
||||
$this->out($this->addDocumentation($line));
|
||||
}
|
||||
}
|
||||
$this->out($line);
|
||||
$previous = $line;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Adds a doxygen header
|
||||
*
|
||||
* @param string $line The current line of the document
|
||||
*
|
||||
* @return string added doxygen header
|
||||
*/
|
||||
private function addDocumentation($line)
|
||||
{
|
||||
$trimmed = ltrim($line);
|
||||
$length = strlen($line) - strlen($trimmed);
|
||||
$space = substr($line, 0, $length);
|
||||
|
||||
$block = $space . "/**\n" .
|
||||
$space . " * @brief \n" .
|
||||
$space . " *\n"; /**/
|
||||
|
||||
|
||||
$left = strpos($line, "(");
|
||||
$line = substr($line, $left + 1);
|
||||
|
||||
$right = strpos($line, ")");
|
||||
$line = trim(substr($line, 0, $right));
|
||||
|
||||
if ($line != "") {
|
||||
$parameters = explode(",", $line);
|
||||
foreach ($parameters AS $parameter) {
|
||||
$parameter = trim($parameter);
|
||||
$splitted = explode("=", $parameter);
|
||||
|
||||
$block .= $space . " * @param " . trim($splitted[0], "& ") . "\n";
|
||||
}
|
||||
if (count($parameters) > 0) $block .= $space . " *\n";
|
||||
}
|
||||
|
||||
$block .= $space . " * @return \n" .
|
||||
$space . " */\n";
|
||||
|
||||
return $block;
|
||||
}
|
||||
|
||||
}
|
110
src/Core/Console/DatabaseStructure.php
Normal file
110
src/Core/Console/DatabaseStructure.php
Normal file
|
@ -0,0 +1,110 @@
|
|||
<?php
|
||||
|
||||
namespace Friendica\Core\Console;
|
||||
|
||||
use Friendica\Core;
|
||||
use Friendica\Database\DBStructure;
|
||||
|
||||
require_once 'boot.php';
|
||||
require_once 'include/dba.php';
|
||||
|
||||
/**
|
||||
* @brief Does database updates from the command line
|
||||
*
|
||||
* @author Hypolite Petovan <mrpetovan@gmail.com>
|
||||
*/
|
||||
class DatabaseStructure extends \Asika\SimpleConsole\Console
|
||||
{
|
||||
protected $helpOptions = ['h', 'help', '?'];
|
||||
|
||||
protected function getHelp()
|
||||
{
|
||||
$help = <<<HELP
|
||||
console dbstructure - Does database updates
|
||||
Usage
|
||||
bin/console dbstructure <command> [-h|--help|-?] [-v]
|
||||
|
||||
Commands
|
||||
dryrun Show database update schema queries without running them
|
||||
update Update database schema
|
||||
dumpsql Dump database schema
|
||||
toinnodb Convert all tables from MyISAM to InnoDB
|
||||
|
||||
Options
|
||||
-h|--help|-? Show help information
|
||||
-v Show more debug information.
|
||||
HELP;
|
||||
return $help;
|
||||
}
|
||||
|
||||
protected function doExecute()
|
||||
{
|
||||
if ($this->getOption('v')) {
|
||||
$this->out('Class: ' . __CLASS__);
|
||||
$this->out('Arguments: ' . var_export($this->args, true));
|
||||
$this->out('Options: ' . var_export($this->options, true));
|
||||
}
|
||||
|
||||
if (count($this->args) == 0) {
|
||||
$this->out($this->getHelp());
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (count($this->args) > 1) {
|
||||
throw new \Asika\SimpleConsole\CommandArgsException('Too many arguments');
|
||||
}
|
||||
|
||||
require_once '.htconfig.php';
|
||||
$result = \dba::connect($db_host, $db_user, $db_pass, $db_data);
|
||||
unset($db_host, $db_user, $db_pass, $db_data);
|
||||
|
||||
if (!$result) {
|
||||
throw new \RuntimeException('Unable to connect to database');
|
||||
}
|
||||
|
||||
Core\Config::load();
|
||||
|
||||
switch ($this->getArgument(0)) {
|
||||
case "dryrun":
|
||||
$output = DBStructure::update(true, false);
|
||||
break;
|
||||
case "update":
|
||||
$output = DBStructure::update(true, true);
|
||||
|
||||
$build = Core\Config::get('system', 'build');
|
||||
if (empty($build)) {
|
||||
Core\Config::set('system', 'build', DB_UPDATE_VERSION);
|
||||
$build = DB_UPDATE_VERSION;
|
||||
}
|
||||
|
||||
$stored = intval($build);
|
||||
$current = intval(DB_UPDATE_VERSION);
|
||||
|
||||
// run any left update_nnnn functions in update.php
|
||||
for ($x = $stored; $x < $current; $x ++) {
|
||||
$r = run_update_function($x);
|
||||
if (!$r) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
Core\Config::set('system', 'build', DB_UPDATE_VERSION);
|
||||
break;
|
||||
case "dumpsql":
|
||||
ob_start();
|
||||
DBStructure::printStructure();
|
||||
$output = ob_get_clean();
|
||||
break;
|
||||
case "toinnodb":
|
||||
ob_start();
|
||||
DBStructure::convertToInnoDB();
|
||||
$output = ob_get_clean();
|
||||
break;
|
||||
}
|
||||
|
||||
$this->out($output);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
}
|
192
src/Core/Console/DocBloxErrorChecker.php
Normal file
192
src/Core/Console/DocBloxErrorChecker.php
Normal file
|
@ -0,0 +1,192 @@
|
|||
<?php
|
||||
|
||||
namespace Friendica\Core\Console;
|
||||
|
||||
/**
|
||||
* When I installed docblox, I had the experience that it does not generate any output at all.
|
||||
* This script may be used to find that kind of problems with the documentation build process.
|
||||
* If docblox generates output, use another approach for debugging.
|
||||
*
|
||||
* Basically, docblox takes a list of files to build documentation from. This script assumes there is a file or set of files
|
||||
* breaking the build when it is included in that list. It tries to calculate the smallest list containing these files.
|
||||
* Unfortunatly, the original problem is NP-complete, so what the script does is a best guess only.
|
||||
*
|
||||
* So it starts with a list of all files in the project.
|
||||
* If that list can't be build, it cuts it in two parts and tries both parts independently. If only one of them breaks,
|
||||
* it takes that one and tries the same independently. If both break, it assumes this is the smallest set. This assumption
|
||||
* is not necessarily true. Maybe the smallest set consists of two files and both of them were in different parts when
|
||||
* the list was divided, but by now it is my best guess. To make this assumption better, the list is shuffled after every step.
|
||||
*
|
||||
* After that, the script tries to remove a file from the list. It tests if the list breaks and if so, it
|
||||
* assumes that the file it removed belongs to the set of erroneous files.
|
||||
* This is done for all files, so, in the end removing one file leads to a working doc build.
|
||||
*
|
||||
* @author Alexander Kampmann
|
||||
* @author Hypolite Petovan <mrpetovan@gmail.com>
|
||||
*/
|
||||
class DocBloxErrorChecker extends \Asika\SimpleConsole\Console
|
||||
{
|
||||
|
||||
protected $helpOptions = ['h', 'help', '?'];
|
||||
|
||||
protected function getHelp()
|
||||
{
|
||||
$help = <<<HELP
|
||||
console docbloxerrorchecker - Checks the file tree for docblox errors
|
||||
Usage
|
||||
bin/console docbloxerrorchecker [-h|--help|-?] [-v]
|
||||
|
||||
Options
|
||||
-h|--help|-? Show help information
|
||||
-v Show more debug information.
|
||||
HELP;
|
||||
return $help;
|
||||
}
|
||||
|
||||
protected function doExecute()
|
||||
{
|
||||
if ($this->getOption('v')) {
|
||||
$this->out('Class: ' . __CLASS__);
|
||||
$this->out('Arguments: ' . var_export($this->args, true));
|
||||
$this->out('Options: ' . var_export($this->options, true));
|
||||
}
|
||||
|
||||
if (count($this->args) > 0) {
|
||||
throw new \Asika\SimpleConsole\CommandArgsException('Too many arguments');
|
||||
}
|
||||
|
||||
if (!$this->commandExists('docblox')) {
|
||||
throw new \RuntimeException('DocBlox isn\'t available.');
|
||||
}
|
||||
|
||||
//return from util folder to frindica base dir
|
||||
$dir = get_app()->get_basepath();
|
||||
|
||||
//stack for dirs to search
|
||||
$dirstack = [];
|
||||
//list of source files
|
||||
$filelist = [];
|
||||
|
||||
//loop over all files in $dir
|
||||
while ($dh = opendir($dir)) {
|
||||
while ($file = readdir($dh)) {
|
||||
if (is_dir($dir . "/" . $file)) {
|
||||
//add to directory stack
|
||||
if (strpos($file, '.') !== 0) {
|
||||
array_push($dirstack, $dir . "/" . $file);
|
||||
$this->out('dir ' . $dir . '/' . $file);
|
||||
}
|
||||
} else {
|
||||
//test if it is a source file and add to filelist
|
||||
if (substr($file, strlen($file) - 4) == ".php") {
|
||||
array_push($filelist, $dir . "/" . $file);
|
||||
$this->out($dir . '/' . $file);
|
||||
}
|
||||
}
|
||||
}
|
||||
//look at the next dir
|
||||
$dir = array_pop($dirstack);
|
||||
}
|
||||
|
||||
//check the entire set
|
||||
if ($this->runs($filelist)) {
|
||||
throw new \RuntimeException("I can not detect a problem.");
|
||||
}
|
||||
|
||||
//check half of the set and discard if that half is okay
|
||||
$res = $filelist;
|
||||
$i = count($res);
|
||||
do {
|
||||
$this->out($i . '/' . count($filelist) . ' elements remaining.');
|
||||
$res = $this->reduce($res, count($res) / 2);
|
||||
shuffle($res);
|
||||
$i = count($res);
|
||||
} while (count($res) < $i);
|
||||
|
||||
//check one file after another
|
||||
$needed = [];
|
||||
|
||||
while (count($res) != 0) {
|
||||
$file = array_pop($res);
|
||||
|
||||
if ($this->runs(array_merge($res, $needed))) {
|
||||
$this->out('needs: ' . $file . ' and file count ' . count($needed));
|
||||
array_push($needed, $file);
|
||||
}
|
||||
}
|
||||
|
||||
$this->out('Smallest Set is: ' . $this->namesList($needed) . ' with ' . count($needed) . ' files. ');
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
private function commandExists($command)
|
||||
{
|
||||
$prefix = strpos(strtolower(PHP_OS),'win') > -1 ? 'where' : 'which';
|
||||
exec("{$prefix} {$command}", $output, $returnVal);
|
||||
return $returnVal === 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* This function generates a comma separated list of file names.
|
||||
*
|
||||
* @package util
|
||||
*
|
||||
* @param array $fileset Set of file names
|
||||
*
|
||||
* @return string comma-separated list of the file names
|
||||
*/
|
||||
private function namesList($fileset)
|
||||
{
|
||||
return implode(',', $fileset);
|
||||
}
|
||||
|
||||
/**
|
||||
* This functions runs phpdoc on the provided list of files
|
||||
* @package util
|
||||
*
|
||||
* @param array $fileset Set of filenames
|
||||
*
|
||||
* @return bool true, if that set can be built
|
||||
*/
|
||||
private function runs($fileset)
|
||||
{
|
||||
$fsParam = $this->namesList($fileset);
|
||||
$this->exec('docblox -t phpdoc_out -f ' . $fsParam);
|
||||
if (file_exists("phpdoc_out/index.html")) {
|
||||
$this->out('Subset ' . $fsParam . ' is okay.');
|
||||
$this->exec('rm -r phpdoc_out');
|
||||
return true;
|
||||
} else {
|
||||
$this->out('Subset ' . $fsParam . ' failed.');
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This functions cuts down a fileset by removing files until it finally works.
|
||||
* it was meant to be recursive, but php's maximum stack size is to small. So it just simulates recursion.
|
||||
*
|
||||
* In that version, it does not necessarily generate the smallest set, because it may not alter the elements order enough.
|
||||
*
|
||||
* @package util
|
||||
*
|
||||
* @param array $fileset set of filenames
|
||||
* @param int $ps number of files in subsets
|
||||
*
|
||||
* @return array a part of $fileset, that crashes
|
||||
*/
|
||||
private function reduce($fileset, $ps)
|
||||
{
|
||||
//split array...
|
||||
$parts = array_chunk($fileset, $ps);
|
||||
//filter working subsets...
|
||||
$parts = array_filter($parts, [$this, 'runs']);
|
||||
//melt remaining parts together
|
||||
if (is_array($parts)) {
|
||||
return array_reduce($parts, "array_merge", []);
|
||||
}
|
||||
return [];
|
||||
}
|
||||
|
||||
}
|
140
src/Core/Console/Extract.php
Normal file
140
src/Core/Console/Extract.php
Normal file
|
@ -0,0 +1,140 @@
|
|||
<?php
|
||||
|
||||
namespace Friendica\Core\Console;
|
||||
|
||||
/**
|
||||
* Extracts translation strings from the Friendica project's files to be exported
|
||||
* to Transifex for translation.
|
||||
*
|
||||
* Outputs a PHP file with language strings used by Friendica
|
||||
*
|
||||
* @author Hypolite Petovan <mrpetovan@gmail.com>
|
||||
*/
|
||||
class Extract extends \Asika\SimpleConsole\Console
|
||||
{
|
||||
protected $helpOptions = ['h', 'help', '?'];
|
||||
|
||||
protected function getHelp()
|
||||
{
|
||||
$help = <<<HELP
|
||||
console extract - Generate translation string file for the Friendica project (deprecated)
|
||||
Usage
|
||||
bin/console extract [-h|--help|-?] [-v]
|
||||
|
||||
Description
|
||||
This script was used to generate the translation string file to be exported to Transifex,
|
||||
please use bin/run_xgettext.sh instead
|
||||
|
||||
Options
|
||||
-h|--help|-? Show help information
|
||||
-v Show more debug information.
|
||||
HELP;
|
||||
return $help;
|
||||
}
|
||||
|
||||
protected function doExecute()
|
||||
{
|
||||
if ($this->getOption('v')) {
|
||||
$this->out('Class: ' . __CLASS__);
|
||||
$this->out('Arguments: ' . var_export($this->args, true));
|
||||
$this->out('Options: ' . var_export($this->options, true));
|
||||
}
|
||||
|
||||
if (count($this->args) > 0) {
|
||||
throw new \Asika\SimpleConsole\CommandArgsException('Too many arguments');
|
||||
}
|
||||
|
||||
$s = '<?php' . PHP_EOL;
|
||||
$s .= '
|
||||
function string_plural_select($n){
|
||||
return ($n != 1);
|
||||
}
|
||||
|
||||
';
|
||||
|
||||
$arr = [];
|
||||
|
||||
$files = array_merge(
|
||||
['index.php', 'boot.php'],
|
||||
glob('mod/*'),
|
||||
glob('include/*'),
|
||||
glob('addon/*/*'),
|
||||
$this->globRecursive('src')
|
||||
);
|
||||
|
||||
foreach ($files as $file) {
|
||||
$str = file_get_contents($file);
|
||||
|
||||
$pat = '|L10n::t\(([^\)]*+)[\)]|';
|
||||
$patt = '|L10n::tt\(([^\)]*+)[\)]|';
|
||||
|
||||
$matches = [];
|
||||
$matchestt = [];
|
||||
|
||||
preg_match_all($pat, $str, $matches);
|
||||
preg_match_all($patt, $str, $matchestt);
|
||||
|
||||
if (count($matches) || count($matchestt)) {
|
||||
$s .= '// ' . $file . PHP_EOL;
|
||||
}
|
||||
|
||||
if (!empty($matches[1])) {
|
||||
foreach ($matches[1] as $long_match) {
|
||||
$match_arr = preg_split('/(?<=[\'"])\s*,/', $long_match);
|
||||
$match = $match_arr[0];
|
||||
if (!in_array($match, $arr)) {
|
||||
if (substr($match, 0, 1) == '$') {
|
||||
continue;
|
||||
}
|
||||
|
||||
$arr[] = $match;
|
||||
|
||||
$s .= '$a->strings[' . $match . '] = ' . $match . ';' . "\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!empty($matchestt[1])) {
|
||||
foreach ($matchestt[1] as $match) {
|
||||
$matchtkns = preg_split("|[ \t\r\n]*,[ \t\r\n]*|", $match);
|
||||
if (count($matchtkns) == 3 && !in_array($matchtkns[0], $arr)) {
|
||||
if (substr($matchtkns[1], 0, 1) == '$') {
|
||||
continue;
|
||||
}
|
||||
|
||||
$arr[] = $matchtkns[0];
|
||||
|
||||
$s .= '$a->strings[' . $matchtkns[0] . "] = array(\n";
|
||||
$s .= "\t0 => " . $matchtkns[0] . ",\n";
|
||||
$s .= "\t1 => " . $matchtkns[1] . ",\n";
|
||||
$s .= ");\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$s .= '// Timezones' . PHP_EOL;
|
||||
|
||||
$zones = timezone_identifiers_list();
|
||||
foreach ($zones as $zone) {
|
||||
$s .= '$a->strings[\'' . $zone . '\'] = \'' . $zone . '\';' . "\n";
|
||||
}
|
||||
|
||||
$this->out($s);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
private function globRecursive($path) {
|
||||
$dir_iterator = new \RecursiveDirectoryIterator($path);
|
||||
$iterator = new \RecursiveIteratorIterator($dir_iterator, \RecursiveIteratorIterator::SELF_FIRST);
|
||||
|
||||
$return = [];
|
||||
foreach ($iterator as $file) {
|
||||
if ($file->getBasename() != '.' && $file->getBasename() != '..') {
|
||||
$return[] = $file->getPathname();
|
||||
}
|
||||
}
|
||||
|
||||
return $return;
|
||||
}
|
||||
}
|
77
src/Core/Console/GlobalCommunityBlock.php
Normal file
77
src/Core/Console/GlobalCommunityBlock.php
Normal file
|
@ -0,0 +1,77 @@
|
|||
<?php
|
||||
|
||||
namespace Friendica\Core\Console;
|
||||
|
||||
use Friendica\Core\L10n;
|
||||
use Friendica\Model\Contact;
|
||||
|
||||
/**
|
||||
* @brief tool to block an account from the node
|
||||
*
|
||||
* With this tool, you can block an account in such a way, that no postings
|
||||
* or comments this account writes are accepted to the node.
|
||||
*
|
||||
* License: AGPLv3 or later, same as Friendica
|
||||
*
|
||||
* @author Tobias Diekershoff <mrpetovan@gmail.com>
|
||||
* @author Hypolite Petovan <mrpetovan@gmail.com>
|
||||
*/
|
||||
class GlobalCommunityBlock extends \Asika\SimpleConsole\Console
|
||||
{
|
||||
protected $helpOptions = ['h', 'help', '?'];
|
||||
|
||||
protected function getHelp()
|
||||
{
|
||||
$help = <<<HELP
|
||||
console globalcommunityblock - Block remote profile from interacting with this node
|
||||
Usage
|
||||
bin/console globalcommunityblock <profile_url> [-h|--help|-?] [-v]
|
||||
|
||||
Description
|
||||
Blocks an account in such a way that no postings or comments this account writes are accepted to this node.
|
||||
|
||||
Options
|
||||
-h|--help|-? Show help information
|
||||
-v Show more debug information.
|
||||
HELP;
|
||||
return $help;
|
||||
}
|
||||
|
||||
protected function doExecute()
|
||||
{
|
||||
if ($this->getOption('v')) {
|
||||
$this->out('Class: ' . __CLASS__);
|
||||
$this->out('Arguments: ' . var_export($this->args, true));
|
||||
$this->out('Options: ' . var_export($this->options, true));
|
||||
}
|
||||
|
||||
if (count($this->args) == 0) {
|
||||
$this->out($this->getHelp());
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (count($this->args) > 1) {
|
||||
throw new \Asika\SimpleConsole\CommandArgsException('Too many arguments');
|
||||
}
|
||||
|
||||
require_once '.htconfig.php';
|
||||
$result = \dba::connect($db_host, $db_user, $db_pass, $db_data);
|
||||
unset($db_host, $db_user, $db_pass, $db_data);
|
||||
|
||||
if (!$result) {
|
||||
throw new \RuntimeException('Unable to connect to database');
|
||||
}
|
||||
|
||||
$contact_id = Contact::getIdForURL($this->getArgument(0));
|
||||
if (!$contact_id) {
|
||||
throw new \RuntimeException(L10n::t('Could not find any contact entry for this URL (%s)', $nurl));
|
||||
}
|
||||
if(Contact::block($contact_id)) {
|
||||
$this->out(L10n::t('The contact has been blocked from the node'));
|
||||
} else {
|
||||
throw new \RuntimeException('The contact block failed.');
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
94
src/Core/Console/GlobalCommunitySilence.php
Normal file
94
src/Core/Console/GlobalCommunitySilence.php
Normal file
|
@ -0,0 +1,94 @@
|
|||
<?php
|
||||
|
||||
namespace Friendica\Core\Console;
|
||||
|
||||
use Friendica\Core\Protocol;
|
||||
use Friendica\Database\DBM;
|
||||
use Friendica\Network\Probe;
|
||||
|
||||
require_once 'include/text.php';
|
||||
|
||||
/**
|
||||
* @brief tool to silence accounts on the global community page
|
||||
*
|
||||
* With this tool, you can silence an account on the global community page.
|
||||
* Postings from silenced accounts will not be displayed on the community
|
||||
* page. This silencing does only affect the display on the community page,
|
||||
* accounts following the silenced accounts will still get their postings.
|
||||
*
|
||||
* License: AGPLv3 or later, same as Friendica
|
||||
*
|
||||
* @author Tobias Diekershoff
|
||||
* @author Hypolite Petovan <mrpetovan@gmail.com>
|
||||
*/
|
||||
class GlobalCommunitySilence extends \Asika\SimpleConsole\Console
|
||||
{
|
||||
protected $helpOptions = ['h', 'help', '?'];
|
||||
|
||||
protected function getHelp()
|
||||
{
|
||||
$help = <<<HELP
|
||||
console globalcommunitysilence - Silence remote profile from global community page
|
||||
Usage
|
||||
bin/console globalcommunitysilence <profile_url> [-h|--help|-?] [-v]
|
||||
|
||||
Description
|
||||
With this tool, you can silence an account on the global community page.
|
||||
Postings from silenced accounts will not be displayed on the community page.
|
||||
This silencing does only affect the display on the community page, accounts
|
||||
following the silenced accounts will still get their postings.
|
||||
|
||||
Options
|
||||
-h|--help|-? Show help information
|
||||
-v Show more debug information.
|
||||
HELP;
|
||||
return $help;
|
||||
}
|
||||
|
||||
protected function doExecute()
|
||||
{
|
||||
if ($this->getOption('v')) {
|
||||
$this->out('Class: ' . __CLASS__);
|
||||
$this->out('Arguments: ' . var_export($this->args, true));
|
||||
$this->out('Options: ' . var_export($this->options, true));
|
||||
}
|
||||
|
||||
if (count($this->args) == 0) {
|
||||
$this->out($this->getHelp());
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (count($this->args) > 1) {
|
||||
throw new \Asika\SimpleConsole\CommandArgsException('Too many arguments');
|
||||
}
|
||||
|
||||
require_once '.htconfig.php';
|
||||
$result = \dba::connect($db_host, $db_user, $db_pass, $db_data);
|
||||
unset($db_host, $db_user, $db_pass, $db_data);
|
||||
|
||||
if (!$result) {
|
||||
throw new \RuntimeException('Unable to connect to database');
|
||||
}
|
||||
|
||||
/**
|
||||
* 1. make nurl from last parameter
|
||||
* 2. check DB (contact) if there is a contact with uid=0 and that nurl, get the ID
|
||||
* 3. set the flag hidden=1 for the contact entry with the found ID
|
||||
* */
|
||||
$net = Probe::uri($this->getArgument(0));
|
||||
if (in_array($net['network'], [Protocol::PHANTOM, Protocol::MAIL])) {
|
||||
throw new \RuntimeException('This account seems not to exist.');
|
||||
}
|
||||
|
||||
$nurl = normalise_link($net['url']);
|
||||
$contact = \dba::selectFirst("contact", ["id"], ["nurl" => $nurl, "uid" => 0]);
|
||||
if (DBM::is_result($contact)) {
|
||||
\dba::update("contact", ["hidden" => true], ["id" => $contact["id"]]);
|
||||
$this->out('NOTICE: The account should be silenced from the global community page');
|
||||
} else {
|
||||
throw new \RuntimeException('NOTICE: Could not find any entry for this URL (' . $nurl . ')');
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
105
src/Core/Console/Maintenance.php
Normal file
105
src/Core/Console/Maintenance.php
Normal file
|
@ -0,0 +1,105 @@
|
|||
<?php
|
||||
|
||||
namespace Friendica\Core\Console;
|
||||
|
||||
use Friendica\Core;
|
||||
|
||||
require_once 'boot.php';
|
||||
require_once 'include/dba.php';
|
||||
|
||||
/**
|
||||
* @brief Sets maintenance mode for this node
|
||||
*
|
||||
* @author Hypolite Petovan <mrpetovan@gmail.com>
|
||||
*/
|
||||
class Maintenance extends \Asika\SimpleConsole\Console
|
||||
{
|
||||
protected $helpOptions = ['h', 'help', '?'];
|
||||
|
||||
protected function getHelp()
|
||||
{
|
||||
$help = <<<HELP
|
||||
console maintenance - Sets maintenance mode for this node
|
||||
Usage
|
||||
bin/console maintenance <enable> [<reason>] [-h|--help|-?] [-v]
|
||||
|
||||
Description
|
||||
<enable> cen be either 0 or 1 to disabled or enable the maintenance mode on this node.
|
||||
|
||||
<reason> is a quote-enclosed string with the optional reason for the maintenance mode.
|
||||
|
||||
Examples
|
||||
bin/console maintenance 1
|
||||
Enables the maintenance mode without setting a reason message
|
||||
|
||||
bin/console maintenance 1 "SSL certification update"
|
||||
Enables the maintenance mode with setting a reason message
|
||||
|
||||
bin/console maintenance 0
|
||||
Disables the maintenance mode
|
||||
|
||||
Options
|
||||
-h|--help|-? Show help information
|
||||
-v Show more debug information.
|
||||
HELP;
|
||||
return $help;
|
||||
}
|
||||
|
||||
protected function doExecute()
|
||||
{
|
||||
if ($this->getOption('v')) {
|
||||
$this->out('Class: ' . __CLASS__);
|
||||
$this->out('Arguments: ' . var_export($this->args, true));
|
||||
$this->out('Options: ' . var_export($this->options, true));
|
||||
}
|
||||
|
||||
if (count($this->args) == 0) {
|
||||
$this->out($this->getHelp());
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (count($this->args) > 2) {
|
||||
throw new \Asika\SimpleConsole\CommandArgsException('Too many arguments');
|
||||
}
|
||||
|
||||
require_once '.htconfig.php';
|
||||
$result = \dba::connect($db_host, $db_user, $db_pass, $db_data);
|
||||
unset($db_host, $db_user, $db_pass, $db_data);
|
||||
|
||||
if (!$result) {
|
||||
throw new \RuntimeException('Unable to connect to database');
|
||||
}
|
||||
|
||||
Core\Config::load();
|
||||
|
||||
$lang = Core\L10n::getBrowserLanguage();
|
||||
Core\L10n::loadTranslationTable($lang);
|
||||
|
||||
$enabled = intval($this->getArgument(0));
|
||||
|
||||
Core\Config::set('system', 'maintenance', $enabled);
|
||||
|
||||
$reason = $this->getArgument(1);
|
||||
|
||||
if ($enabled && $this->getArgument(1)) {
|
||||
Core\Config::set('system', 'maintenance_reason', $this->getArgument(1));
|
||||
} else {
|
||||
Core\Config::set('system', 'maintenance_reason', '');
|
||||
}
|
||||
|
||||
if ($enabled) {
|
||||
$mode_str = "maintenance mode";
|
||||
} else {
|
||||
$mode_str = "normal mode";
|
||||
}
|
||||
|
||||
$this->out('System set in ' . $mode_str);
|
||||
|
||||
if ($enabled && $reason != '') {
|
||||
$this->out('Maintenance reason: ' . $reason);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
}
|
234
src/Core/Console/PhpToPo.php
Normal file
234
src/Core/Console/PhpToPo.php
Normal file
|
@ -0,0 +1,234 @@
|
|||
<?php
|
||||
|
||||
namespace Friendica\Core\Console;
|
||||
|
||||
/**
|
||||
* Read a strings.php file and create messages.po in the same directory
|
||||
*
|
||||
* @author Hypolite Petovan <mrpetovan@gmail.com>
|
||||
*/
|
||||
class PhpToPo extends \Asika\SimpleConsole\Console
|
||||
{
|
||||
|
||||
protected $helpOptions = ['h', 'help', '?'];
|
||||
|
||||
private $normBaseMsgIds = [];
|
||||
const NORM_REGEXP = "|[\\\]|";
|
||||
|
||||
protected function getHelp()
|
||||
{
|
||||
$help = <<<HELP
|
||||
console php2po - Generate a messages.po file from a strings.php file
|
||||
Usage
|
||||
bin/console php2po [-p <n>] [--base <file>] <path/to/strings.php> [-h|--help|-?] [-v]
|
||||
|
||||
Description
|
||||
Read a strings.php file and create the according messages.po in the same directory
|
||||
|
||||
Options
|
||||
-p <n> Number of plural forms. Default: 2
|
||||
--base <file> Path to base messages.po file. Default: util/messages.po
|
||||
-h|--help|-? Show help information
|
||||
-v Show more debug information.
|
||||
HELP;
|
||||
return $help;
|
||||
}
|
||||
|
||||
protected function doExecute()
|
||||
{
|
||||
if ($this->getOption('v')) {
|
||||
$this->out('Class: ' . __CLASS__);
|
||||
$this->out('Arguments: ' . var_export($this->args, true));
|
||||
$this->out('Options: ' . var_export($this->options, true));
|
||||
}
|
||||
|
||||
if (count($this->args) == 0) {
|
||||
$this->out($this->getHelp());
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (count($this->args) > 1) {
|
||||
throw new \Asika\SimpleConsole\CommandArgsException('Too many arguments');
|
||||
}
|
||||
|
||||
$a = get_app();
|
||||
|
||||
$phpfile = realpath($this->getArgument(0));
|
||||
|
||||
if (!file_exists($phpfile)) {
|
||||
throw new \RuntimeException('Supplied file path doesn\'t exist.');
|
||||
}
|
||||
|
||||
if (!is_writable(dirname($phpfile))) {
|
||||
throw new \RuntimeException('Supplied directory isn\'t writable.');
|
||||
}
|
||||
|
||||
$pofile = dirname($phpfile) . DIRECTORY_SEPARATOR . 'messages.po';
|
||||
|
||||
// start !
|
||||
include_once($phpfile);
|
||||
|
||||
$out = '';
|
||||
$out .= "# FRIENDICA Distributed Social Network\n";
|
||||
$out .= "# Copyright (C) 2010, 2011, 2012, 2013 the Friendica Project\n";
|
||||
$out .= "# This file is distributed under the same license as the Friendica package.\n";
|
||||
$out .= "# \n";
|
||||
$out .= 'msgid ""' . "\n";
|
||||
$out .= 'msgstr ""' . "\n";
|
||||
$out .= '"Project-Id-Version: friendica\n"' . "\n";
|
||||
$out .= '"Report-Msgid-Bugs-To: \n"' . "\n";
|
||||
$out .= '"POT-Creation-Date: ' . date("Y-m-d H:i:sO") . '\n"' . "\n";
|
||||
$out .= '"MIME-Version: 1.0\n"' . "\n";
|
||||
$out .= '"Content-Type: text/plain; charset=UTF-8\n"' . "\n";
|
||||
$out .= '"Content-Transfer-Encoding: 8bit\n"' . "\n";
|
||||
|
||||
// search for plural info
|
||||
$lang = "";
|
||||
$lang_logic = "";
|
||||
$lang_pnum = $this->getOption('p', 2);
|
||||
|
||||
$infile = file($phpfile);
|
||||
foreach ($infile as $l) {
|
||||
$l = trim($l);
|
||||
if ($this->startsWith($l, 'function string_plural_select_')) {
|
||||
$lang = str_replace('function string_plural_select_', '', str_replace('($n){', '', $l));
|
||||
}
|
||||
if ($this->startsWith($l, 'return')) {
|
||||
$lang_logic = str_replace('$', '', trim(str_replace('return ', '', $l), ';'));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
$this->out('Language: ' . $lang);
|
||||
$this->out('Plural forms: ' . $lang_pnum);
|
||||
$this->out('Plural forms: ' . $lang_logic);
|
||||
|
||||
$out .= sprintf('"Language: %s\n"', $lang) . "\n";
|
||||
$out .= sprintf('"Plural-Forms: nplurals=%s; plural=%s;\n"', $lang_pnum, $lang_logic) . "\n";
|
||||
$out .= "\n";
|
||||
|
||||
$base_path = $this->getOption('base', 'util' . DIRECTORY_SEPARATOR . 'messages.po');
|
||||
|
||||
// load base messages.po and extract msgids
|
||||
$base_msgids = [];
|
||||
$base_f = file($base_path);
|
||||
if (!$base_f) {
|
||||
throw new \RuntimeException('The base ' . $base_path . ' file is missing or unavailable to read.');
|
||||
}
|
||||
|
||||
$this->out('Loading base file ' . $base_path . '...');
|
||||
|
||||
$_f = 0;
|
||||
$_mid = "";
|
||||
$_mids = [];
|
||||
foreach ($base_f as $l) {
|
||||
$l = trim($l);
|
||||
|
||||
if ($this->startsWith($l, 'msgstr')) {
|
||||
if ($_mid != '""') {
|
||||
$base_msgids[$_mid] = $_mids;
|
||||
$this->normBaseMsgIds[preg_replace(self::NORM_REGEXP, "", $_mid)] = $_mid;
|
||||
}
|
||||
|
||||
$_f = 0;
|
||||
$_mid = "";
|
||||
$_mids = [];
|
||||
}
|
||||
|
||||
if ($this->startsWith($l, '"') && $_f == 2) {
|
||||
$_mids[count($_mids) - 1] .= "\n" . $l;
|
||||
}
|
||||
if ($this->startsWith($l, 'msgid_plural ')) {
|
||||
$_f = 2;
|
||||
$_mids[] = str_replace('msgid_plural ', '', $l);
|
||||
}
|
||||
|
||||
if ($this->startsWith($l, '"') && $_f == 1) {
|
||||
$_mid .= "\n" . $l;
|
||||
$_mids[count($_mids) - 1] .= "\n" . $l;
|
||||
}
|
||||
if ($this->startsWith($l, 'msgid ')) {
|
||||
$_f = 1;
|
||||
$_mid = str_replace('msgid ', '', $l);
|
||||
$_mids = [$_mid];
|
||||
}
|
||||
}
|
||||
|
||||
$this->out('Creating ' . $pofile . '...');
|
||||
|
||||
// create msgid and msgstr
|
||||
$warnings = "";
|
||||
foreach ($a->strings as $key => $str) {
|
||||
$msgid = $this->massageString($key);
|
||||
|
||||
if (preg_match("|%[sd0-9](\$[sn])*|", $msgid)) {
|
||||
$out .= "#, php-format\n";
|
||||
}
|
||||
$msgid = $this->findOriginalMsgId($msgid);
|
||||
$out .= 'msgid ' . $msgid . "\n";
|
||||
|
||||
if (is_array($str)) {
|
||||
if (array_key_exists($msgid, $base_msgids) && isset($base_msgids[$msgid][1])) {
|
||||
$out .= 'msgid_plural ' . $base_msgids[$msgid][1] . "\n";
|
||||
} else {
|
||||
$out .= 'msgid_plural ' . $msgid . "\n";
|
||||
$warnings .= "[W] No source plural form for msgid:\n" . str_replace("\n", "\n\t", $msgid) . "\n\n";
|
||||
}
|
||||
foreach ($str as $n => $msgstr) {
|
||||
$out .= 'msgstr[' . $n . '] ' . $this->massageString($msgstr) . "\n";
|
||||
}
|
||||
} else {
|
||||
$out .= 'msgstr ' . $this->massageString($str) . "\n";
|
||||
}
|
||||
|
||||
$out .= "\n";
|
||||
}
|
||||
|
||||
if (!file_put_contents($pofile, $out)) {
|
||||
throw new \RuntimeException('Unable to write to ' . $pofile);
|
||||
}
|
||||
|
||||
if ($warnings != '') {
|
||||
$this->out($warnings);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
private function startsWith($haystack, $needle)
|
||||
{
|
||||
// search backwards starting from haystack length characters from the end
|
||||
return $needle === "" || strrpos($haystack, $needle, -strlen($haystack)) !== FALSE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a string and retun a message.po ready text
|
||||
* - replace " with \"
|
||||
* - replace tab char with \t
|
||||
* - manage multiline strings
|
||||
*/
|
||||
private function massageString($str)
|
||||
{
|
||||
$str = str_replace('\\', '\\\\', $str);
|
||||
$str = str_replace('"', '\"', $str);
|
||||
$str = str_replace("\t", '\t', $str);
|
||||
$str = str_replace("\n", '\n"' . "\n" . '"', $str);
|
||||
if (strpos($str, "\n") !== false && $str[0] !== '"') {
|
||||
$str = '"' . "\n" . $str;
|
||||
}
|
||||
|
||||
$str = preg_replace("|\n([^\"])|", "\n\"$1", $str);
|
||||
return sprintf('"%s"', $str);
|
||||
}
|
||||
|
||||
private function findOriginalMsgId($str)
|
||||
{
|
||||
$norm_str = preg_replace(self::NORM_REGEXP, "", $str);
|
||||
if (array_key_exists($norm_str, $this->normBaseMsgIds)) {
|
||||
return $this->normBaseMsgIds[$norm_str];
|
||||
}
|
||||
|
||||
return $str;
|
||||
}
|
||||
|
||||
}
|
201
src/Core/Console/PoToPhp.php
Normal file
201
src/Core/Console/PoToPhp.php
Normal file
|
@ -0,0 +1,201 @@
|
|||
<?php
|
||||
|
||||
namespace Friendica\Core\Console;
|
||||
|
||||
/**
|
||||
* Read a messages.po file and create strings.php in the same directory
|
||||
*
|
||||
* @author Hypolite Petovan <mrpetovan@gmail.com>
|
||||
*/
|
||||
class PoToPhp extends \Asika\SimpleConsole\Console
|
||||
{
|
||||
protected $helpOptions = ['h', 'help', '?'];
|
||||
|
||||
const DQ_ESCAPE = "__DQ__";
|
||||
|
||||
protected function getHelp()
|
||||
{
|
||||
$help = <<<HELP
|
||||
console php2po - Generate a strings.php file from a messages.po file
|
||||
Usage
|
||||
bin/console php2po <path/to/messages.po> [-h|--help|-?] [-v]
|
||||
|
||||
Description
|
||||
Read a messages.po file and create the according strings.php in the same directory
|
||||
|
||||
Options
|
||||
-h|--help|-? Show help information
|
||||
-v Show more debug information.
|
||||
HELP;
|
||||
return $help;
|
||||
}
|
||||
|
||||
protected function doExecute()
|
||||
{
|
||||
if ($this->getOption('v')) {
|
||||
$this->out('Class: ' . __CLASS__);
|
||||
$this->out('Arguments: ' . var_export($this->args, true));
|
||||
$this->out('Options: ' . var_export($this->options, true));
|
||||
}
|
||||
|
||||
if (count($this->args) == 0) {
|
||||
$this->out($this->getHelp());
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (count($this->args) > 1) {
|
||||
throw new \Asika\SimpleConsole\CommandArgsException('Too many arguments');
|
||||
}
|
||||
|
||||
$a = get_app();
|
||||
|
||||
$pofile = realpath($this->getArgument(0));
|
||||
|
||||
if (!file_exists($pofile)) {
|
||||
throw new \RuntimeException('Supplied file path doesn\'t exist.');
|
||||
}
|
||||
|
||||
if (!is_writable(dirname($pofile))) {
|
||||
throw new \RuntimeException('Supplied directory isn\'t writable.');
|
||||
}
|
||||
|
||||
$outfile = dirname($pofile) . DIRECTORY_SEPARATOR . 'strings.php';
|
||||
|
||||
if (strstr($outfile, 'util')) {
|
||||
$lang = 'en';
|
||||
} else {
|
||||
$lang = str_replace('-', '_', basename(dirname($pofile)));
|
||||
}
|
||||
|
||||
$this->out('Out to ' . $outfile);
|
||||
|
||||
$out = "<?php\n\n";
|
||||
|
||||
$infile = file($pofile);
|
||||
$k = '';
|
||||
$v = '';
|
||||
$arr = false;
|
||||
$ink = false;
|
||||
$inv = false;
|
||||
$escape_s_exp = '|[^\\\\]\$[a-z]|';
|
||||
|
||||
foreach ($infile as $l) {
|
||||
$l = str_replace('\"', self::DQ_ESCAPE, $l);
|
||||
$len = strlen($l);
|
||||
if ($l[0] == "#") {
|
||||
$l = "";
|
||||
}
|
||||
|
||||
if (substr($l, 0, 15) == '"Plural-Forms: ') {
|
||||
$match = [];
|
||||
preg_match("|nplurals=([0-9]*); *plural=(.*)[;\\\\]|", $l, $match);
|
||||
$cond = str_replace('n', '$n', $match[2]);
|
||||
// define plural select function if not already defined
|
||||
$fnname = 'string_plural_select_' . $lang;
|
||||
$out .= 'if(! function_exists("' . $fnname . '")) {' . "\n";
|
||||
$out .= 'function ' . $fnname . '($n){' . "\n";
|
||||
$out .= ' return ' . $cond . ';' . "\n";
|
||||
$out .= '}}' . "\n";
|
||||
}
|
||||
|
||||
if ($k != '' && substr($l, 0, 7) == 'msgstr ') {
|
||||
if ($ink) {
|
||||
$ink = false;
|
||||
$out .= '$a->strings["' . $k . '"] = ';
|
||||
}
|
||||
|
||||
if ($inv) {
|
||||
$inv = false;
|
||||
$out .= '"' . $v . '"';
|
||||
}
|
||||
|
||||
$v = substr($l, 8, $len - 10);
|
||||
$v = preg_replace_callback($escape_s_exp, [$this, 'escapeDollar'], $v);
|
||||
|
||||
$inv = true;
|
||||
}
|
||||
|
||||
if ($k != "" && substr($l, 0, 7) == 'msgstr[') {
|
||||
if ($ink) {
|
||||
$ink = false;
|
||||
$out .= '$a->strings["' . $k . '"] = ';
|
||||
}
|
||||
if ($inv) {
|
||||
$inv = false;
|
||||
$out .= '"' . $v . '"';
|
||||
}
|
||||
|
||||
if (!$arr) {
|
||||
$arr = true;
|
||||
$out .= "[\n";
|
||||
}
|
||||
|
||||
$match = [];
|
||||
preg_match("|\[([0-9]*)\] (.*)|", $l, $match);
|
||||
$out .= "\t"
|
||||
. preg_replace_callback($escape_s_exp, [$this, 'escapeDollar'], $match[1])
|
||||
. ' => '
|
||||
. preg_replace_callback($escape_s_exp, [$this, 'escapeDollar'], $match[2])
|
||||
. ",\n";
|
||||
}
|
||||
|
||||
if (substr($l, 0, 6) == 'msgid_') {
|
||||
$ink = false;
|
||||
$out .= '$a->strings["' . $k . '"] = ';
|
||||
}
|
||||
|
||||
if ($ink) {
|
||||
$k .= trim($l, "\"\r\n");
|
||||
$k = preg_replace_callback($escape_s_exp, [$this, 'escapeDollar'], $k);
|
||||
}
|
||||
|
||||
if (substr($l, 0, 6) == 'msgid ') {
|
||||
if ($inv) {
|
||||
$inv = false;
|
||||
$out .= '"' . $v . '"';
|
||||
}
|
||||
|
||||
if ($k != "") {
|
||||
$out .= ($arr) ? "];\n" : ";\n";
|
||||
}
|
||||
|
||||
$arr = false;
|
||||
$k = str_replace("msgid ", "", $l);
|
||||
if ($k != '""') {
|
||||
$k = trim($k, "\"\r\n");
|
||||
} else {
|
||||
$k = '';
|
||||
}
|
||||
|
||||
$k = preg_replace_callback($escape_s_exp, [$this, 'escapeDollar'], $k);
|
||||
$ink = true;
|
||||
}
|
||||
|
||||
if ($inv && substr($l, 0, 6) != "msgstr") {
|
||||
$v .= trim($l, "\"\r\n");
|
||||
$v = preg_replace_callback($escape_s_exp, [$this, 'escapeDollar'], $v);
|
||||
}
|
||||
}
|
||||
|
||||
if ($inv) {
|
||||
$inv = false;
|
||||
$out .= '"' . $v . '"';
|
||||
}
|
||||
|
||||
if ($k != '') {
|
||||
$out .= ($arr ? "];\n" : ";\n");
|
||||
}
|
||||
|
||||
$out = str_replace(self::DQ_ESCAPE, '\"', $out);
|
||||
if (!file_put_contents($outfile, $out)) {
|
||||
throw new \RuntimeException('Unable to write to ' . $outfile);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
private function escapeDollar($match)
|
||||
{
|
||||
return str_replace('$', '\$', $match[0]);
|
||||
}
|
||||
}
|
119
src/Core/Console/Typo.php
Normal file
119
src/Core/Console/Typo.php
Normal file
|
@ -0,0 +1,119 @@
|
|||
<?php
|
||||
|
||||
namespace Friendica\Core\Console;
|
||||
|
||||
/**
|
||||
* Tired of chasing typos and finding them after a commit.
|
||||
* Run this and quickly see if we've got any parse errors in our application files.
|
||||
*
|
||||
* @author Hypolite Petovan <mrpetovan@gmail.com>
|
||||
*/
|
||||
class Typo extends \Asika\SimpleConsole\Console
|
||||
{
|
||||
protected $helpOptions = ['h', 'help', '?'];
|
||||
|
||||
protected function getHelp()
|
||||
{
|
||||
$help = <<<HELP
|
||||
console typo - Checks for parse errors in Friendica files
|
||||
Usage
|
||||
bin/console typo [-h|--help|-?] [-v]
|
||||
|
||||
Description
|
||||
Checks all PHP files in the Friendica file tree for parse errors
|
||||
|
||||
Options
|
||||
-h|--help|-? Show help information
|
||||
-v Show more debug information.
|
||||
HELP;
|
||||
return $help;
|
||||
}
|
||||
|
||||
protected function doExecute()
|
||||
{
|
||||
if ($this->getOption('v')) {
|
||||
$this->out('Class: ' . __CLASS__);
|
||||
$this->out('Arguments: ' . var_export($this->args, true));
|
||||
$this->out('Options: ' . var_export($this->options, true));
|
||||
}
|
||||
|
||||
if (count($this->args) > 0) {
|
||||
throw new \Asika\SimpleConsole\CommandArgsException('Too many arguments');
|
||||
}
|
||||
|
||||
$a = get_app();
|
||||
|
||||
$php_path = $a->getConfigValue('config', 'php_path', 'php');
|
||||
|
||||
if ($this->getOption('v')) {
|
||||
$this->out('Directory: src');
|
||||
}
|
||||
|
||||
$Iterator = new \RecursiveDirectoryIterator('src');
|
||||
|
||||
foreach (new \RecursiveIteratorIterator($Iterator) as $file) {
|
||||
if (substr($file, -4) === '.php') {
|
||||
$this->checkFile($php_path, $file);
|
||||
}
|
||||
}
|
||||
|
||||
if ($this->getOption('v')) {
|
||||
$this->out('Directory: mod');
|
||||
}
|
||||
|
||||
$files = glob('mod/*.php');
|
||||
$this->checkFiles($php_path, $files);
|
||||
|
||||
if ($this->getOption('v')) {
|
||||
$this->out('Directory: include');
|
||||
}
|
||||
|
||||
$files = glob('include/*.php');
|
||||
$this->checkFiles($php_path, $files);
|
||||
|
||||
if ($this->getOption('v')) {
|
||||
$this->out('Directory: addon');
|
||||
}
|
||||
|
||||
$dirs = glob('addon/*');
|
||||
foreach ($dirs as $dir) {
|
||||
$addon = basename($dir);
|
||||
$files = glob($dir . '/' . $addon . '.php');
|
||||
$this->checkFiles($php_path, $files);
|
||||
}
|
||||
|
||||
if ($this->getOption('v')) {
|
||||
$this->out('String files');
|
||||
}
|
||||
|
||||
$this->checkFile($php_path, 'util/strings.php');
|
||||
|
||||
$files = glob('view/lang/*/strings.php');
|
||||
$this->checkFiles($php_path, $files);
|
||||
|
||||
$this->out('No errors.');
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
private function checkFiles($php_path, array $files)
|
||||
{
|
||||
foreach ($files as $file) {
|
||||
$this->checkFile($php_path, $file);
|
||||
}
|
||||
}
|
||||
|
||||
private function checkFile($php_path, $file)
|
||||
{
|
||||
if ($this->getOption('v')) {
|
||||
$this->out('Checking ' . $file);
|
||||
}
|
||||
|
||||
$output = [];
|
||||
$ret = 0;
|
||||
exec("$php_path -l $file", $output, $ret);
|
||||
if ($ret !== 0) {
|
||||
throw new \RuntimeException('Parse error found in ' . $file . ', scan stopped.');
|
||||
}
|
||||
}
|
||||
}
|
|
@ -8,6 +8,7 @@ namespace Friendica\Core;
|
|||
|
||||
use Friendica\BaseObject;
|
||||
use Friendica\Content\Text\BBCode;
|
||||
use Friendica\Content\Text\HTML;
|
||||
use Friendica\Core\L10n;
|
||||
use Friendica\Core\PConfig;
|
||||
use Friendica\Core\System;
|
||||
|
@ -19,7 +20,6 @@ use Friendica\Util\Temporal;
|
|||
use Friendica\Util\XML;
|
||||
|
||||
require_once 'include/dba.php';
|
||||
require_once 'include/html2plain.php';
|
||||
|
||||
/**
|
||||
* @brief Methods for read and write notifications from/to database
|
||||
|
@ -47,7 +47,7 @@ class NotificationsManager extends BaseObject
|
|||
$n['timestamp'] = strtotime($local_time);
|
||||
$n['date_rel'] = Temporal::getRelativeDate($n['date']);
|
||||
$n['msg_html'] = BBCode::convert($n['msg'], false);
|
||||
$n['msg_plain'] = explode("\n", trim(html2plain($n['msg_html'], 0)))[0];
|
||||
$n['msg_plain'] = explode("\n", trim(HTML::toPlaintext($n['msg_html'], 0)))[0];
|
||||
|
||||
$rets[] = $n;
|
||||
}
|
||||
|
|
|
@ -1,20 +1,18 @@
|
|||
<?php
|
||||
/**
|
||||
* @file src/Core/PConfig.php
|
||||
* User Configuration Class
|
||||
*
|
||||
* @file include/Core/PConfig.php
|
||||
*
|
||||
* @brief Contains the class with methods for user configuration
|
||||
*/
|
||||
namespace Friendica\Core;
|
||||
|
||||
use Friendica\Database\DBM;
|
||||
use dba;
|
||||
use Friendica\BaseObject;
|
||||
use Friendica\Core\Config;
|
||||
|
||||
require_once 'include/dba.php';
|
||||
|
||||
/**
|
||||
* @file include/Core/PConfig.php
|
||||
* @brief contains the class with methods for the management
|
||||
* of the user configuration
|
||||
*/
|
||||
|
||||
/**
|
||||
* @brief Management of user configuration storage
|
||||
* Note:
|
||||
|
@ -22,9 +20,23 @@ require_once 'include/dba.php';
|
|||
* The PConfig::get() functions return boolean false for keys that are unset,
|
||||
* and this could lead to subtle bugs.
|
||||
*/
|
||||
class PConfig
|
||||
class PConfig extends BaseObject
|
||||
{
|
||||
private static $in_db;
|
||||
/**
|
||||
* @var Friendica\Core\Config\IPConfigAdapter
|
||||
*/
|
||||
private static $adapter = null;
|
||||
|
||||
public static function init($uid)
|
||||
{
|
||||
$a = self::getApp();
|
||||
|
||||
if (isset($a->config['system']['config_adapter']) && $a->config['system']['config_adapter'] == 'preload') {
|
||||
self::$adapter = new Config\PreloadPConfigAdapter($uid);
|
||||
} else {
|
||||
self::$adapter = new Config\JITPConfigAdapter($uid);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Loads all configuration values of a user's config family into a cached storage.
|
||||
|
@ -39,20 +51,11 @@ class PConfig
|
|||
*/
|
||||
public static function load($uid, $family)
|
||||
{
|
||||
$a = get_app();
|
||||
|
||||
$r = dba::select('pconfig', ['v', 'k'], ['cat' => $family, 'uid' => $uid]);
|
||||
if (DBM::is_result($r)) {
|
||||
while ($rr = dba::fetch($r)) {
|
||||
$k = $rr['k'];
|
||||
$a->config[$uid][$family][$k] = $rr['v'];
|
||||
self::$in_db[$uid][$family][$k] = true;
|
||||
}
|
||||
} else if ($family != 'config') {
|
||||
// Negative caching
|
||||
$a->config[$uid][$family] = "!<unset>!";
|
||||
if (empty(self::$adapter)) {
|
||||
self::init($uid);
|
||||
}
|
||||
dba::close($r);
|
||||
|
||||
self::$adapter->load($uid, $family);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -72,37 +75,11 @@ class PConfig
|
|||
*/
|
||||
public static function get($uid, $family, $key, $default_value = null, $refresh = false)
|
||||
{
|
||||
$a = get_app();
|
||||
|
||||
if (!$refresh) {
|
||||
// Looking if the whole family isn't set
|
||||
if (isset($a->config[$uid][$family])) {
|
||||
if ($a->config[$uid][$family] === '!<unset>!') {
|
||||
return $default_value;
|
||||
}
|
||||
}
|
||||
|
||||
if (isset($a->config[$uid][$family][$key])) {
|
||||
if ($a->config[$uid][$family][$key] === '!<unset>!') {
|
||||
return $default_value;
|
||||
}
|
||||
return $a->config[$uid][$family][$key];
|
||||
}
|
||||
if (empty(self::$adapter)) {
|
||||
self::init($uid);
|
||||
}
|
||||
|
||||
$pconfig = dba::selectFirst('pconfig', ['v'], ['uid' => $uid, 'cat' => $family, 'k' => $key]);
|
||||
if (DBM::is_result($pconfig)) {
|
||||
$val = (preg_match("|^a:[0-9]+:{.*}$|s", $pconfig['v']) ? unserialize($pconfig['v']) : $pconfig['v']);
|
||||
$a->config[$uid][$family][$key] = $val;
|
||||
self::$in_db[$uid][$family][$key] = true;
|
||||
|
||||
return $val;
|
||||
} else {
|
||||
$a->config[$uid][$family][$key] = '!<unset>!';
|
||||
self::$in_db[$uid][$family][$key] = false;
|
||||
|
||||
return $default_value;
|
||||
}
|
||||
return self::$adapter->get($uid, $family, $key, $default_value, $refresh);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -122,31 +99,11 @@ class PConfig
|
|||
*/
|
||||
public static function set($uid, $family, $key, $value)
|
||||
{
|
||||
$a = get_app();
|
||||
|
||||
// We store our setting values in a string variable.
|
||||
// So we have to do the conversion here so that the compare below works.
|
||||
// The exception are array values.
|
||||
$dbvalue = (!is_array($value) ? (string)$value : $value);
|
||||
|
||||
$stored = self::get($uid, $family, $key, null, true);
|
||||
|
||||
if (($stored === $dbvalue) && self::$in_db[$uid][$family][$key]) {
|
||||
return true;
|
||||
if (empty(self::$adapter)) {
|
||||
self::init($uid);
|
||||
}
|
||||
|
||||
$a->config[$uid][$family][$key] = $dbvalue;
|
||||
|
||||
// manage array value
|
||||
$dbvalue = (is_array($value) ? serialize($value) : $dbvalue);
|
||||
|
||||
$ret = dba::update('pconfig', ['v' => $dbvalue], ['uid' => $uid, 'cat' => $family, 'k' => $key], true);
|
||||
|
||||
if ($ret) {
|
||||
self::$in_db[$uid][$family][$key] = true;
|
||||
return $value;
|
||||
}
|
||||
return $ret;
|
||||
return self::$adapter->set($uid, $family, $key, $value);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -163,15 +120,10 @@ class PConfig
|
|||
*/
|
||||
public static function delete($uid, $family, $key)
|
||||
{
|
||||
$a = get_app();
|
||||
|
||||
if (x($a->config[$uid][$family], $key)) {
|
||||
unset($a->config[$uid][$family][$key]);
|
||||
unset(self::$in_db[$uid][$family][$key]);
|
||||
if (empty(self::$adapter)) {
|
||||
self::init($uid);
|
||||
}
|
||||
|
||||
$ret = dba::delete('pconfig', ['uid' => $uid, 'cat' => $family, 'k' => $key]);
|
||||
|
||||
return $ret;
|
||||
return self::$adapter->delete($uid, $family, $key);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -119,6 +119,6 @@ class Protocol
|
|||
*/
|
||||
public static function formatMention($profile_url, $display_name)
|
||||
{
|
||||
return $display_name . '(' . self::getAddrFromProfileUrl($profile_url) . ')';
|
||||
return $display_name . ' (' . self::getAddrFromProfileUrl($profile_url) . ')';
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,8 +5,8 @@
|
|||
*/
|
||||
namespace Friendica\Core;
|
||||
|
||||
use Friendica\Core\Session\CacheSessionHandler;
|
||||
use Friendica\Core\Session\DatabaseSessionHandler;
|
||||
use Friendica\Core\Session\MemcacheSessionHandler;
|
||||
|
||||
/**
|
||||
* High-level Session service class
|
||||
|
@ -28,10 +28,10 @@ class Session
|
|||
ini_set('session.cookie_secure', 1);
|
||||
}
|
||||
|
||||
if (!Config::get('system', 'disable_database_session')) {
|
||||
$memcache = Cache::memcache();
|
||||
if (is_object($memcache)) {
|
||||
$SessionHandler = new MemcacheSessionHandler($memcache);
|
||||
$session_handler = Config::get('system', 'session_handler', 'database');
|
||||
if ($session_handler != 'native') {
|
||||
if ($session_handler == 'cache' && Config::get('system', 'cache_driver', 'database') != 'database') {
|
||||
$SessionHandler = new CacheSessionHandler();
|
||||
} else {
|
||||
$SessionHandler = new DatabaseSessionHandler();
|
||||
}
|
||||
|
|
|
@ -3,34 +3,20 @@
|
|||
namespace Friendica\Core\Session;
|
||||
|
||||
use Friendica\BaseObject;
|
||||
use Friendica\Core\Cache;
|
||||
use Friendica\Core\Session;
|
||||
use SessionHandlerInterface;
|
||||
use Memcache;
|
||||
|
||||
require_once 'boot.php';
|
||||
require_once 'include/text.php';
|
||||
|
||||
/**
|
||||
* SessionHandler using Memcache
|
||||
* SessionHandler using Friendica Cache
|
||||
*
|
||||
* @author Hypolite Petovan <mrpetovan@gmail.com>
|
||||
*/
|
||||
class MemcacheSessionHandler extends BaseObject implements SessionHandlerInterface
|
||||
class CacheSessionHandler extends BaseObject implements SessionHandlerInterface
|
||||
{
|
||||
/**
|
||||
* @var Memcache
|
||||
*/
|
||||
private $memcache = null;
|
||||
|
||||
/**
|
||||
*
|
||||
* @param Memcache $memcache
|
||||
*/
|
||||
public function __construct(Memcache $memcache)
|
||||
{
|
||||
$this->memcache = $memcache;
|
||||
}
|
||||
|
||||
public function open($save_path, $session_name)
|
||||
{
|
||||
return true;
|
||||
|
@ -42,8 +28,8 @@ class MemcacheSessionHandler extends BaseObject implements SessionHandlerInterfa
|
|||
return '';
|
||||
}
|
||||
|
||||
$data = $this->memcache->get(self::getApp()->get_hostname() . ":session:" . $session_id);
|
||||
if (!is_bool($data)) {
|
||||
$data = Cache::get('session:' . $session_id);
|
||||
if (!empty($data)) {
|
||||
Session::$exists = true;
|
||||
return $data;
|
||||
}
|
||||
|
@ -72,14 +58,7 @@ class MemcacheSessionHandler extends BaseObject implements SessionHandlerInterfa
|
|||
return true;
|
||||
}
|
||||
|
||||
$expire = time() + Session::$expire;
|
||||
|
||||
$this->memcache->set(
|
||||
self::getApp()->get_hostname() . ":session:" . $session_id,
|
||||
$session_data,
|
||||
MEMCACHE_COMPRESSED,
|
||||
$expire
|
||||
);
|
||||
Cache::set('session:' . $session_id, $session_data, Session::$expire);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
@ -91,7 +70,7 @@ class MemcacheSessionHandler extends BaseObject implements SessionHandlerInterfa
|
|||
|
||||
public function destroy($id)
|
||||
{
|
||||
$this->memcache->delete(self::getApp()->get_hostname() . ":session:" . $id);
|
||||
Cache::delete('session:' . $id);
|
||||
return true;
|
||||
}
|
||||
|
|
@ -325,6 +325,8 @@ class Worker
|
|||
$a->performance["start"] = microtime(true);
|
||||
$a->performance["database"] = 0;
|
||||
$a->performance["database_write"] = 0;
|
||||
$a->performance["cache"] = 0;
|
||||
$a->performance["cache_write"] = 0;
|
||||
$a->performance["network"] = 0;
|
||||
$a->performance["file"] = 0;
|
||||
$a->performance["rendering"] = 0;
|
||||
|
@ -409,6 +411,24 @@ class Worker
|
|||
}
|
||||
}
|
||||
}
|
||||
if (isset($a->callstack["dache"])) {
|
||||
$o .= "\nCache Read:\n";
|
||||
foreach ($a->callstack["dache"] as $func => $time) {
|
||||
$time = round($time, 3);
|
||||
if ($time > 0) {
|
||||
$o .= $func.": ".$time."\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
if (isset($a->callstack["dache_write"])) {
|
||||
$o .= "\nCache Write:\n";
|
||||
foreach ($a->callstack["dache_write"] as $func => $time) {
|
||||
$time = round($time, 3);
|
||||
if ($time > 0) {
|
||||
$o .= $func.": ".$time."\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
if (isset($a->callstack["network"])) {
|
||||
$o .= "\nNetwork:\n";
|
||||
foreach ($a->callstack["network"] as $func => $time) {
|
||||
|
@ -422,12 +442,16 @@ class Worker
|
|||
|
||||
logger(
|
||||
"ID ".$queue["id"].": ".$funcname.": ".sprintf(
|
||||
"DB: %s/%s, Net: %s, I/O: %s, Other: %s, Total: %s".$o,
|
||||
"DB: %s/%s, Cache: %s/%s, Net: %s, I/O: %s, Other: %s, Total: %s".$o,
|
||||
number_format($a->performance["database"] - $a->performance["database_write"], 2),
|
||||
number_format($a->performance["database_write"], 2),
|
||||
number_format($a->performance["cache"], 2),
|
||||
number_format($a->performance["cache_write"], 2),
|
||||
number_format($a->performance["network"], 2),
|
||||
number_format($a->performance["file"], 2),
|
||||
number_format($duration - ($a->performance["database"] + $a->performance["network"] + $a->performance["file"]), 2),
|
||||
number_format($duration - ($a->performance["database"]
|
||||
+ $a->performance["cache"] + $a->performance["cache_write"]
|
||||
+ $a->performance["network"] + $a->performance["file"]), 2),
|
||||
number_format($duration, 2)
|
||||
),
|
||||
LOGGER_DEBUG
|
||||
|
@ -979,7 +1003,7 @@ class Worker
|
|||
*/
|
||||
public static function spawnWorker()
|
||||
{
|
||||
$args = ["scripts/worker.php", "no_cron"];
|
||||
$args = ["bin/worker.php", "no_cron"];
|
||||
get_app()->proc_run($args);
|
||||
}
|
||||
|
||||
|
|
|
@ -715,16 +715,16 @@ class DBStructure
|
|||
]
|
||||
];
|
||||
$database["cache"] = [
|
||||
"comment" => "Used to store different data that doesn't to be stored for a long time",
|
||||
"comment" => "Stores temporary data",
|
||||
"fields" => [
|
||||
"k" => ["type" => "varbinary(255)", "not null" => "1", "primary" => "1", "comment" => ""],
|
||||
"v" => ["type" => "mediumtext", "comment" => ""],
|
||||
"expire_mode" => ["type" => "tinyint unsigned", "not null" => "1", "default" => "0", "comment" => ""],
|
||||
"updated" => ["type" => "datetime", "not null" => "1", "default" => NULL_DATE, "comment" => ""],
|
||||
"k" => ["type" => "varbinary(255)", "not null" => "1", "primary" => "1", "comment" => "cache key"],
|
||||
"v" => ["type" => "mediumtext", "comment" => "cached serialized value"],
|
||||
"expires" => ["type" => "datetime", "not null" => "1", "default" => NULL_DATE, "comment" => "datetime of cache expiration"],
|
||||
"updated" => ["type" => "datetime", "not null" => "1", "default" => NULL_DATE, "comment" => "datetime of cache insertion"],
|
||||
],
|
||||
"indexes" => [
|
||||
"PRIMARY" => ["k"],
|
||||
"expire_mode_updated" => ["expire_mode", "updated"],
|
||||
"k_expires" => ["k", "expires"],
|
||||
]
|
||||
];
|
||||
$database["challenge"] = [
|
||||
|
@ -788,9 +788,9 @@ class DBStructure
|
|||
"xmpp" => ["type" => "varchar(255)", "not null" => "1", "default" => "", "comment" => ""],
|
||||
"attag" => ["type" => "varchar(255)", "not null" => "1", "default" => "", "comment" => ""],
|
||||
"avatar" => ["type" => "varchar(255)", "not null" => "1", "default" => "", "comment" => ""],
|
||||
"photo" => ["type" => "varchar(255)", "not null" => "1", "default" => "", "comment" => ""],
|
||||
"thumb" => ["type" => "varchar(255)", "not null" => "1", "default" => "", "comment" => ""],
|
||||
"micro" => ["type" => "varchar(255)", "not null" => "1", "default" => "", "comment" => ""],
|
||||
"photo" => ["type" => "varchar(255)", "default" => "", "comment" => ""],
|
||||
"thumb" => ["type" => "varchar(255)", "default" => "", "comment" => ""],
|
||||
"micro" => ["type" => "varchar(255)", "default" => "", "comment" => ""],
|
||||
"site-pubkey" => ["type" => "text", "comment" => ""],
|
||||
"issued-id" => ["type" => "varchar(255)", "not null" => "1", "default" => "", "comment" => ""],
|
||||
"dfrn-id" => ["type" => "varchar(255)", "not null" => "1", "default" => "", "comment" => ""],
|
||||
|
|
|
@ -1582,4 +1582,29 @@ class Contact extends BaseObject
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove the unavailable contact ids from the provided list
|
||||
*
|
||||
* @param array $contact_ids Contact id list
|
||||
*/
|
||||
public static function pruneUnavailable(array &$contact_ids)
|
||||
{
|
||||
if (empty($contact_ids)) {
|
||||
return;
|
||||
}
|
||||
|
||||
$str = dbesc(implode(',', $contact_ids));
|
||||
|
||||
$stmt = dba::p("SELECT `id` FROM `contact` WHERE `id` IN ( " . $str . ") AND `blocked` = 0 AND `pending` = 0 AND `archive` = 0");
|
||||
|
||||
$return = [];
|
||||
while($contact = dba::fetch($stmt)) {
|
||||
$return[] = $contact['id'];
|
||||
}
|
||||
|
||||
dba::close($stmt);
|
||||
|
||||
$contact_ids = $return;
|
||||
}
|
||||
}
|
||||
|
|
959
src/Model/Event.php
Normal file
959
src/Model/Event.php
Normal file
|
@ -0,0 +1,959 @@
|
|||
<?php
|
||||
/**
|
||||
* @file src/Model/Event.php
|
||||
*/
|
||||
|
||||
namespace Friendica\Model;
|
||||
|
||||
use dba;
|
||||
use Friendica\BaseObject;
|
||||
use Friendica\Content\Text\BBCode;
|
||||
use Friendica\Core\Addon;
|
||||
use Friendica\Core\L10n;
|
||||
use Friendica\Core\PConfig;
|
||||
use Friendica\Core\System;
|
||||
use Friendica\Database\DBM;
|
||||
use Friendica\Model\Item;
|
||||
use Friendica\Util\DateTimeFormat;
|
||||
use Friendica\Util\Map;
|
||||
|
||||
require_once 'boot.php';
|
||||
require_once 'include/dba.php';
|
||||
require_once 'include/items.php';
|
||||
|
||||
/**
|
||||
* @brief functions for interacting with the event database table
|
||||
*/
|
||||
class Event extends BaseObject
|
||||
{
|
||||
|
||||
public static function getHTML(array $event, $simple = false)
|
||||
{
|
||||
if (empty($event)) {
|
||||
return '';
|
||||
}
|
||||
|
||||
$bd_format = L10n::t('l F d, Y \@ g:i A'); // Friday January 18, 2011 @ 8 AM.
|
||||
|
||||
$event_start = day_translate(
|
||||
$event['adjust'] ?
|
||||
DateTimeFormat::local($event['start'], $bd_format) : DateTimeFormat::utc($event['start'], $bd_format)
|
||||
);
|
||||
|
||||
$event_end = day_translate(
|
||||
$event['adjust'] ?
|
||||
DateTimeFormat::local($event['finish'], $bd_format) : DateTimeFormat::utc($event['finish'], $bd_format)
|
||||
);
|
||||
|
||||
if ($simple) {
|
||||
$o = "<h3>" . BBCode::convert($event['summary'], false, $simple) . "</h3>";
|
||||
|
||||
$o .= "<div>" . BBCode::convert($event['desc'], false, $simple) . "</div>";
|
||||
|
||||
$o .= "<h4>" . L10n::t('Starts:') . "</h4><p>" . $event_start . "</p>";
|
||||
|
||||
if (!$event['nofinish']) {
|
||||
$o .= "<h4>" . L10n::t('Finishes:') . "</h4><p>" . $event_end . "</p>";
|
||||
}
|
||||
|
||||
if (strlen($event['location'])) {
|
||||
$o .= "<h4>" . L10n::t('Location:') . "</h4><p>" . BBCode::convert($event['location'], false, $simple) . "</p>";
|
||||
}
|
||||
|
||||
return $o;
|
||||
}
|
||||
|
||||
$o = '<div class="vevent">' . "\r\n";
|
||||
|
||||
$o .= '<div class="summary event-summary">' . BBCode::convert($event['summary'], false, $simple) . '</div>' . "\r\n";
|
||||
|
||||
$o .= '<div class="event-start"><span class="event-label">' . L10n::t('Starts:') . '</span> <span class="dtstart" title="'
|
||||
. DateTimeFormat::utc($event['start'], (($event['adjust']) ? DateTimeFormat::ATOM : 'Y-m-d\TH:i:s'))
|
||||
. '" >' . $event_start
|
||||
. '</span></div>' . "\r\n";
|
||||
|
||||
if (!$event['nofinish']) {
|
||||
$o .= '<div class="event-end" ><span class="event-label">' . L10n::t('Finishes:') . '</span> <span class="dtend" title="'
|
||||
. DateTimeFormat::utc($event['finish'], (($event['adjust']) ? DateTimeFormat::ATOM : 'Y-m-d\TH:i:s'))
|
||||
. '" >' . $event_end
|
||||
. '</span></div>' . "\r\n";
|
||||
}
|
||||
|
||||
$o .= '<div class="description event-description">' . BBCode::convert($event['desc'], false, $simple) . '</div>' . "\r\n";
|
||||
|
||||
if (strlen($event['location'])) {
|
||||
$o .= '<div class="event-location"><span class="event-label">' . L10n::t('Location:') . '</span> <span class="location">'
|
||||
. BBCode::convert($event['location'], false, $simple)
|
||||
. '</span></div>' . "\r\n";
|
||||
|
||||
// Include a map of the location if the [map] BBCode is used.
|
||||
if (strpos($event['location'], "[map") !== false) {
|
||||
$map = Map::byLocation($event['location'], $simple);
|
||||
if ($map !== $event['location']) {
|
||||
$o .= $map;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$o .= '</div>' . "\r\n";
|
||||
return $o;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Convert an array with event data to bbcode.
|
||||
*
|
||||
* @param array $event Array which contains the event data.
|
||||
* @return string The event as a bbcode formatted string.
|
||||
*/
|
||||
private static function getBBCode(array $event)
|
||||
{
|
||||
$o = '';
|
||||
|
||||
if ($event['summary']) {
|
||||
$o .= '[event-summary]' . $event['summary'] . '[/event-summary]';
|
||||
}
|
||||
|
||||
if ($event['desc']) {
|
||||
$o .= '[event-description]' . $event['desc'] . '[/event-description]';
|
||||
}
|
||||
|
||||
if ($event['start']) {
|
||||
$o .= '[event-start]' . $event['start'] . '[/event-start]';
|
||||
}
|
||||
|
||||
if (($event['finish']) && (!$event['nofinish'])) {
|
||||
$o .= '[event-finish]' . $event['finish'] . '[/event-finish]';
|
||||
}
|
||||
|
||||
if ($event['location']) {
|
||||
$o .= '[event-location]' . $event['location'] . '[/event-location]';
|
||||
}
|
||||
|
||||
if ($event['adjust']) {
|
||||
$o .= '[event-adjust]' . $event['adjust'] . '[/event-adjust]';
|
||||
}
|
||||
|
||||
return $o;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Extract bbcode formatted event data from a string.
|
||||
*
|
||||
* @params: string $s The string which should be parsed for event data.
|
||||
* @return array The array with the event information.
|
||||
*/
|
||||
public static function fromBBCode($text)
|
||||
{
|
||||
$ev = [];
|
||||
|
||||
$match = '';
|
||||
if (preg_match("/\[event\-summary\](.*?)\[\/event\-summary\]/is", $text, $match)) {
|
||||
$ev['summary'] = $match[1];
|
||||
}
|
||||
|
||||
$match = '';
|
||||
if (preg_match("/\[event\-description\](.*?)\[\/event\-description\]/is", $text, $match)) {
|
||||
$ev['desc'] = $match[1];
|
||||
}
|
||||
|
||||
$match = '';
|
||||
if (preg_match("/\[event\-start\](.*?)\[\/event\-start\]/is", $text, $match)) {
|
||||
$ev['start'] = $match[1];
|
||||
}
|
||||
|
||||
$match = '';
|
||||
if (preg_match("/\[event\-finish\](.*?)\[\/event\-finish\]/is", $text, $match)) {
|
||||
$ev['finish'] = $match[1];
|
||||
}
|
||||
|
||||
$match = '';
|
||||
if (preg_match("/\[event\-location\](.*?)\[\/event\-location\]/is", $text, $match)) {
|
||||
$ev['location'] = $match[1];
|
||||
}
|
||||
|
||||
$match = '';
|
||||
if (preg_match("/\[event\-adjust\](.*?)\[\/event\-adjust\]/is", $text, $match)) {
|
||||
$ev['adjust'] = $match[1];
|
||||
}
|
||||
|
||||
$ev['nofinish'] = !empty($ev['start']) && empty($ev['finish']) ? 1 : 0;
|
||||
|
||||
return $ev;
|
||||
}
|
||||
|
||||
public static function sortByDate($event_list)
|
||||
{
|
||||
usort($event_list, ['self', 'compareDatesCallback']);
|
||||
return $event_list;
|
||||
}
|
||||
|
||||
private static function compareDatesCallback($event_a, $event_b)
|
||||
{
|
||||
$date_a = (($event_a['adjust']) ? DateTimeFormat::local($event_a['start']) : $event_a['start']);
|
||||
$date_b = (($event_b['adjust']) ? DateTimeFormat::local($event_b['start']) : $event_b['start']);
|
||||
|
||||
if ($date_a === $date_b) {
|
||||
return strcasecmp($event_a['desc'], $event_b['desc']);
|
||||
}
|
||||
|
||||
return strcmp($date_a, $date_b);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Delete an event from the event table.
|
||||
*
|
||||
* Note: This function does only delete the event from the event table not its
|
||||
* related entry in the item table.
|
||||
*
|
||||
* @param int $event_id Event ID.
|
||||
* @return void
|
||||
*/
|
||||
public static function delete($event_id)
|
||||
{
|
||||
if ($event_id == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
dba::delete('event', ['id' => $event_id]);
|
||||
logger("Deleted event ".$event_id, LOGGER_DEBUG);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Store the event.
|
||||
*
|
||||
* Store the event in the event table and create an event item in the item table.
|
||||
*
|
||||
* @param array $arr Array with event data.
|
||||
* @return int The new event id.
|
||||
*/
|
||||
public static function store($arr)
|
||||
{
|
||||
$a = self::getApp();
|
||||
|
||||
$event = [];
|
||||
$event['id'] = intval(defaults($arr, 'id' , 0));
|
||||
$event['uid'] = intval(defaults($arr, 'uid' , 0));
|
||||
$event['cid'] = intval(defaults($arr, 'cid' , 0));
|
||||
$event['uri'] = defaults($arr, 'uri' , item_new_uri($a->get_hostname(), $event['uid']));
|
||||
$event['type'] = defaults($arr, 'type' , 'event');
|
||||
$event['summary'] = defaults($arr, 'summary' , '');
|
||||
$event['desc'] = defaults($arr, 'desc' , '');
|
||||
$event['location'] = defaults($arr, 'location' , '');
|
||||
$event['allow_cid'] = defaults($arr, 'allow_cid', '');
|
||||
$event['allow_gid'] = defaults($arr, 'allow_gid', '');
|
||||
$event['deny_cid'] = defaults($arr, 'deny_cid' , '');
|
||||
$event['deny_gid'] = defaults($arr, 'deny_gid' , '');
|
||||
$event['adjust'] = intval(defaults($arr, 'adjust' , 0));
|
||||
$event['nofinish'] = intval(defaults($arr, 'nofinish' , !empty($event['start']) && empty($event['finish'])));
|
||||
|
||||
$event['created'] = DateTimeFormat::utc(defaults($arr, 'created' , 'now'));
|
||||
$event['edited'] = DateTimeFormat::utc(defaults($arr, 'edited' , 'now'));
|
||||
$event['start'] = DateTimeFormat::utc(defaults($arr, 'start' , NULL_DATE));
|
||||
$event['finish'] = DateTimeFormat::utc(defaults($arr, 'finish' , NULL_DATE));
|
||||
if ($event['finish'] < NULL_DATE) {
|
||||
$event['finish'] = NULL_DATE;
|
||||
}
|
||||
$private = intval(defaults($arr, 'private', 0));
|
||||
|
||||
$conditions = ['uid' => $event['uid']];
|
||||
if ($event['cid']) {
|
||||
$conditions['id'] = $event['cid'];
|
||||
} else {
|
||||
$conditions['self'] = true;
|
||||
}
|
||||
|
||||
$contact = dba::selectFirst('contact', [], $conditions);
|
||||
|
||||
// Existing event being modified.
|
||||
if ($event['id']) {
|
||||
// has the event actually changed?
|
||||
$existing_event = dba::selectFirst('event', ['edited'], ['id' => $event['id'], 'uid' => $event['uid']]);
|
||||
if ((! DBM::is_result($existing_event)) || ($existing_event['edited'] === $event['edited'])) {
|
||||
|
||||
$item = dba::selectFirst('item', [], ['event-id' => $event['id'], 'uid' => $event['uid']]);
|
||||
|
||||
return DBM::is_result($item) ? $item['id'] : 0;
|
||||
}
|
||||
|
||||
$updated_fields = [
|
||||
'edited' => $event['edited'],
|
||||
'start' => $event['start'],
|
||||
'finish' => $event['finish'],
|
||||
'summary' => $event['summary'],
|
||||
'desc' => $event['desc'],
|
||||
'location' => $event['location'],
|
||||
'type' => $event['type'],
|
||||
'adjust' => $event['adjust'],
|
||||
'nofinish' => $event['nofinish'],
|
||||
];
|
||||
|
||||
dba::update('event', $updated_fields, ['id' => $event['cid'], 'uid' => $event['uid']]);
|
||||
|
||||
$item = dba::selectFirst('item', ['id'], ['event-id' => $event['id'], 'uid' => $event['uid']]);
|
||||
if (DBM::is_result($item)) {
|
||||
$object = '<object><type>' . xmlify(ACTIVITY_OBJ_EVENT) . '</type><title></title><id>' . xmlify($event['uri']) . '</id>';
|
||||
$object .= '<content>' . xmlify(self::getBBCode($event)) . '</content>';
|
||||
$object .= '</object>' . "\n";
|
||||
|
||||
$fields = ['body' => self::getBBCode($event), 'object' => $object, 'edited' => $event['edited']];
|
||||
Item::update($fields, ['id' => $item['id']]);
|
||||
|
||||
$item_id = $item['id'];
|
||||
} else {
|
||||
$item_id = 0;
|
||||
}
|
||||
|
||||
Addon::callHooks('event_updated', $event['id']);
|
||||
} else {
|
||||
$event['guid'] = get_guid(32);
|
||||
|
||||
// New event. Store it.
|
||||
dba::insert('event', $event);
|
||||
|
||||
$event['id'] = dba::lastInsertId();
|
||||
|
||||
$item_arr = [];
|
||||
|
||||
$item_arr['uid'] = $event['uid'];
|
||||
$item_arr['contact-id'] = $event['cid'];
|
||||
$item_arr['uri'] = $event['uri'];
|
||||
$item_arr['parent-uri'] = $event['uri'];
|
||||
$item_arr['guid'] = $event['guid'];
|
||||
$item_arr['type'] = 'activity';
|
||||
$item_arr['wall'] = $event['cid'] ? 0 : 1;
|
||||
$item_arr['contact-id'] = $contact['id'];
|
||||
$item_arr['owner-name'] = $contact['name'];
|
||||
$item_arr['owner-link'] = $contact['url'];
|
||||
$item_arr['owner-avatar'] = $contact['thumb'];
|
||||
$item_arr['author-name'] = $contact['name'];
|
||||
$item_arr['author-link'] = $contact['url'];
|
||||
$item_arr['author-avatar'] = $contact['thumb'];
|
||||
$item_arr['title'] = '';
|
||||
$item_arr['allow_cid'] = $event['allow_cid'];
|
||||
$item_arr['allow_gid'] = $event['allow_gid'];
|
||||
$item_arr['deny_cid'] = $event['deny_cid'];
|
||||
$item_arr['deny_gid'] = $event['deny_gid'];
|
||||
$item_arr['private'] = $private;
|
||||
$item_arr['visible'] = 1;
|
||||
$item_arr['verb'] = ACTIVITY_POST;
|
||||
$item_arr['object-type'] = ACTIVITY_OBJ_EVENT;
|
||||
$item_arr['origin'] = $event['cid'] === 0 ? 1 : 0;
|
||||
$item_arr['body'] = self::getBBCode($event);
|
||||
$item_arr['event-id'] = $event['id'];
|
||||
|
||||
$item_arr['object'] = '<object><type>' . xmlify(ACTIVITY_OBJ_EVENT) . '</type><title></title><id>' . xmlify($event['uri']) . '</id>';
|
||||
$item_arr['object'] .= '<content>' . xmlify(self::getBBCode($event)) . '</content>';
|
||||
$item_arr['object'] .= '</object>' . "\n";
|
||||
|
||||
$item_id = Item::insert($item_arr);
|
||||
|
||||
Addon::callHooks("event_created", $event['id']);
|
||||
}
|
||||
|
||||
return $item_id;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Create an array with translation strings used for events.
|
||||
*
|
||||
* @return array Array with translations strings.
|
||||
*/
|
||||
public static function getStrings()
|
||||
{
|
||||
// First day of the week (0 = Sunday).
|
||||
$firstDay = PConfig::get(local_user(), 'system', 'first_day_of_week', 0);
|
||||
|
||||
$i18n = [
|
||||
"firstDay" => $firstDay,
|
||||
"allday" => L10n::t("all-day"),
|
||||
|
||||
"Sun" => L10n::t("Sun"),
|
||||
"Mon" => L10n::t("Mon"),
|
||||
"Tue" => L10n::t("Tue"),
|
||||
"Wed" => L10n::t("Wed"),
|
||||
"Thu" => L10n::t("Thu"),
|
||||
"Fri" => L10n::t("Fri"),
|
||||
"Sat" => L10n::t("Sat"),
|
||||
|
||||
"Sunday" => L10n::t("Sunday"),
|
||||
"Monday" => L10n::t("Monday"),
|
||||
"Tuesday" => L10n::t("Tuesday"),
|
||||
"Wednesday" => L10n::t("Wednesday"),
|
||||
"Thursday" => L10n::t("Thursday"),
|
||||
"Friday" => L10n::t("Friday"),
|
||||
"Saturday" => L10n::t("Saturday"),
|
||||
|
||||
"Jan" => L10n::t("Jan"),
|
||||
"Feb" => L10n::t("Feb"),
|
||||
"Mar" => L10n::t("Mar"),
|
||||
"Apr" => L10n::t("Apr"),
|
||||
"May" => L10n::t("May"),
|
||||
"Jun" => L10n::t("Jun"),
|
||||
"Jul" => L10n::t("Jul"),
|
||||
"Aug" => L10n::t("Aug"),
|
||||
"Sep" => L10n::t("Sept"),
|
||||
"Oct" => L10n::t("Oct"),
|
||||
"Nov" => L10n::t("Nov"),
|
||||
"Dec" => L10n::t("Dec"),
|
||||
|
||||
"January" => L10n::t("January"),
|
||||
"February" => L10n::t("February"),
|
||||
"March" => L10n::t("March"),
|
||||
"April" => L10n::t("April"),
|
||||
"May" => L10n::t("May"),
|
||||
"June" => L10n::t("June"),
|
||||
"July" => L10n::t("July"),
|
||||
"August" => L10n::t("August"),
|
||||
"September" => L10n::t("September"),
|
||||
"October" => L10n::t("October"),
|
||||
"November" => L10n::t("November"),
|
||||
"December" => L10n::t("December"),
|
||||
|
||||
"today" => L10n::t("today"),
|
||||
"month" => L10n::t("month"),
|
||||
"week" => L10n::t("week"),
|
||||
"day" => L10n::t("day"),
|
||||
|
||||
"noevent" => L10n::t("No events to display"),
|
||||
|
||||
"dtstart_label" => L10n::t("Starts:"),
|
||||
"dtend_label" => L10n::t("Finishes:"),
|
||||
"location_label" => L10n::t("Location:")
|
||||
];
|
||||
|
||||
return $i18n;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Removes duplicated birthday events.
|
||||
*
|
||||
* @param array $dates Array of possibly duplicated events.
|
||||
* @return array Cleaned events.
|
||||
*
|
||||
* @todo We should replace this with a separate update function if there is some time left.
|
||||
*/
|
||||
private static function removeDuplicates(array $dates)
|
||||
{
|
||||
$dates2 = [];
|
||||
|
||||
foreach ($dates as $date) {
|
||||
if ($date['type'] == 'birthday') {
|
||||
$dates2[$date['uid'] . "-" . $date['cid'] . "-" . $date['start']] = $date;
|
||||
} else {
|
||||
$dates2[] = $date;
|
||||
}
|
||||
}
|
||||
return array_values($dates2);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get an event by its event ID.
|
||||
*
|
||||
* @param int $owner_uid The User ID of the owner of the event
|
||||
* @param int $event_id The ID of the event in the event table
|
||||
* @param string $sql_extra
|
||||
* @return array Query result
|
||||
*/
|
||||
public static function getListById($owner_uid, $event_id, $sql_extra = '')
|
||||
{
|
||||
$return = [];
|
||||
|
||||
// Ownly allow events if there is a valid owner_id.
|
||||
if ($owner_uid == 0) {
|
||||
return $return;
|
||||
}
|
||||
|
||||
// Query for the event by event id
|
||||
$r = q("SELECT `event`.*, `item`.`id` AS `itemid`,`item`.`plink`,
|
||||
`item`.`author-name`, `item`.`author-avatar`, `item`.`author-link` FROM `event`
|
||||
LEFT JOIN `item` ON `item`.`event-id` = `event`.`id` AND `item`.`uid` = `event`.`uid`
|
||||
WHERE `event`.`uid` = %d AND `event`.`id` = %d $sql_extra",
|
||||
intval($owner_uid),
|
||||
intval($event_id)
|
||||
);
|
||||
|
||||
if (DBM::is_result($r)) {
|
||||
$return = self::removeDuplicates($r);
|
||||
}
|
||||
|
||||
return $return;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get all events in a specific time frame.
|
||||
*
|
||||
* @param int $owner_uid The User ID of the owner of the events.
|
||||
* @param array $event_params An associative array with
|
||||
* int 'ignore' =>
|
||||
* string 'start' => Start time of the timeframe.
|
||||
* string 'finish' => Finish time of the timeframe.
|
||||
* string 'adjust_start' =>
|
||||
* string 'adjust_finish' =>
|
||||
*
|
||||
* @param string $sql_extra Additional sql conditions (e.g. permission request).
|
||||
*
|
||||
* @return array Query results.
|
||||
*/
|
||||
public static function getListByDate($owner_uid, $event_params, $sql_extra = '')
|
||||
{
|
||||
$return = [];
|
||||
|
||||
// Only allow events if there is a valid owner_id.
|
||||
if ($owner_uid == 0) {
|
||||
return $return;
|
||||
}
|
||||
|
||||
// Query for the event by date.
|
||||
// @todo Slow query (518 seconds to run), to be optimzed
|
||||
$r = q("SELECT `event`.*, `item`.`id` AS `itemid`,`item`.`plink`,
|
||||
`item`.`author-name`, `item`.`author-avatar`, `item`.`author-link` FROM `event`
|
||||
LEFT JOIN `item` ON `item`.`event-id` = `event`.`id` AND `item`.`uid` = `event`.`uid`
|
||||
WHERE `event`.`uid` = %d AND event.ignore = %d
|
||||
AND ((`adjust` = 0 AND (`finish` >= '%s' OR (nofinish AND start >= '%s')) AND `start` <= '%s')
|
||||
OR (`adjust` = 1 AND (`finish` >= '%s' OR (nofinish AND start >= '%s')) AND `start` <= '%s'))
|
||||
$sql_extra ",
|
||||
intval($owner_uid),
|
||||
intval($event_params["ignore"]),
|
||||
dbesc($event_params["start"]),
|
||||
dbesc($event_params["start"]),
|
||||
dbesc($event_params["finish"]),
|
||||
dbesc($event_params["adjust_start"]),
|
||||
dbesc($event_params["adjust_start"]),
|
||||
dbesc($event_params["adjust_finish"])
|
||||
);
|
||||
|
||||
if (DBM::is_result($r)) {
|
||||
$return = self::removeDuplicates($r);
|
||||
}
|
||||
|
||||
return $return;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Convert an array query results in an array which could be used by the events template.
|
||||
*
|
||||
* @param array $event_result Event query array.
|
||||
* @return array Event array for the template.
|
||||
*/
|
||||
public static function prepareListForTemplate(array $event_result)
|
||||
{
|
||||
$event_list = [];
|
||||
|
||||
$last_date = '';
|
||||
$fmt = L10n::t('l, F j');
|
||||
foreach ($event_result as $event) {
|
||||
$start = $event['adjust'] ? DateTimeFormat::local($event['start'], 'c') : DateTimeFormat::utc($event['start'], 'c');
|
||||
$j = $event['adjust'] ? DateTimeFormat::local($event['start'], 'j') : DateTimeFormat::utc($event['start'], 'j');
|
||||
$day = $event['adjust'] ? DateTimeFormat::local($event['start'], $fmt) : DateTimeFormat::utc($event['start'], $fmt);
|
||||
$day = day_translate($day);
|
||||
|
||||
if ($event['nofinish']) {
|
||||
$end = null;
|
||||
} else {
|
||||
$end = $event['adjust'] ? DateTimeFormat::local($event['finish'], 'c') : DateTimeFormat::utc($event['finish'], 'c');
|
||||
}
|
||||
|
||||
$is_first = ($day !== $last_date);
|
||||
|
||||
$last_date = $day;
|
||||
|
||||
// Show edit and drop actions only if the user is the owner of the event and the event
|
||||
// is a real event (no bithdays).
|
||||
$edit = null;
|
||||
$copy = null;
|
||||
$drop = null;
|
||||
if (local_user() && local_user() == $event['uid'] && $event['type'] == 'event') {
|
||||
$edit = !$event['cid'] ? [System::baseUrl() . '/events/event/' . $event['id'], L10n::t('Edit event') , '', ''] : null;
|
||||
$copy = !$event['cid'] ? [System::baseUrl() . '/events/copy/' . $event['id'] , L10n::t('Duplicate event'), '', ''] : null;
|
||||
$drop = [System::baseUrl() . '/events/drop/' . $event['id'] , L10n::t('Delete event') , '', ''];
|
||||
}
|
||||
|
||||
$title = strip_tags(html_entity_decode(BBCode::convert($event['summary']), ENT_QUOTES, 'UTF-8'));
|
||||
if (!$title) {
|
||||
list($title, $_trash) = explode("<br", BBCode::convert($event['desc']), 2);
|
||||
$title = strip_tags(html_entity_decode($title, ENT_QUOTES, 'UTF-8'));
|
||||
}
|
||||
|
||||
$html = self::getHTML($event);
|
||||
$event['desc'] = BBCode::convert($event['desc']);
|
||||
$event['location'] = BBCode::convert($event['location']);
|
||||
$event_list[] = [
|
||||
'id' => $event['id'],
|
||||
'start' => $start,
|
||||
'end' => $end,
|
||||
'allDay' => false,
|
||||
'title' => $title,
|
||||
'j' => $j,
|
||||
'd' => $day,
|
||||
'edit' => $edit,
|
||||
'drop' => $drop,
|
||||
'copy' => $copy,
|
||||
'is_first' => $is_first,
|
||||
'item' => $event,
|
||||
'html' => $html,
|
||||
'plink' => [$event['plink'], L10n::t('link to source'), '', ''],
|
||||
];
|
||||
}
|
||||
|
||||
return $event_list;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Format event to export format (ical/csv).
|
||||
*
|
||||
* @param array $events Query result for events.
|
||||
* @param string $format The output format (ical/csv).
|
||||
* @param string $timezone The timezone of the user (not implemented yet).
|
||||
*
|
||||
* @return string Content according to selected export format.
|
||||
*
|
||||
* @todo Implement timezone support
|
||||
*/
|
||||
private static function formatListForExport(array $events, $format, $timezone)
|
||||
{
|
||||
if (!count($events)) {
|
||||
return '';
|
||||
}
|
||||
|
||||
switch ($format) {
|
||||
// Format the exported data as a CSV file.
|
||||
case "csv":
|
||||
header("Content-type: text/csv");
|
||||
$o = '"Subject", "Start Date", "Start Time", "Description", "End Date", "End Time", "Location"' . PHP_EOL;
|
||||
|
||||
foreach ($events as $event) {
|
||||
/// @todo The time / date entries don't include any information about the
|
||||
/// timezone the event is scheduled in :-/
|
||||
$tmp1 = strtotime($event['start']);
|
||||
$tmp2 = strtotime($event['finish']);
|
||||
$time_format = "%H:%M:%S";
|
||||
$date_format = "%Y-%m-%d";
|
||||
|
||||
$o .= '"' . $event['summary'] . '", "' . strftime($date_format, $tmp1) .
|
||||
'", "' . strftime($time_format, $tmp1) . '", "' . $event['desc'] .
|
||||
'", "' . strftime($date_format, $tmp2) .
|
||||
'", "' . strftime($time_format, $tmp2) .
|
||||
'", "' . $event['location'] . '"' . PHP_EOL;
|
||||
}
|
||||
break;
|
||||
|
||||
// Format the exported data as a ics file.
|
||||
case "ical":
|
||||
header("Content-type: text/ics");
|
||||
$o = 'BEGIN:VCALENDAR' . PHP_EOL
|
||||
. 'VERSION:2.0' . PHP_EOL
|
||||
. 'PRODID:-//friendica calendar export//0.1//EN' . PHP_EOL;
|
||||
/// @todo include timezone informations in cases were the time is not in UTC
|
||||
// see http://tools.ietf.org/html/rfc2445#section-4.8.3
|
||||
// . 'BEGIN:VTIMEZONE' . PHP_EOL
|
||||
// . 'TZID:' . $timezone . PHP_EOL
|
||||
// . 'END:VTIMEZONE' . PHP_EOL;
|
||||
// TODO instead of PHP_EOL CRLF should be used for long entries
|
||||
// but test your solution against http://icalvalid.cloudapp.net/
|
||||
// also long lines SHOULD be split at 75 characters length
|
||||
foreach ($events as $event) {
|
||||
if ($event['adjust'] == 1) {
|
||||
$UTC = 'Z';
|
||||
} else {
|
||||
$UTC = '';
|
||||
}
|
||||
$o .= 'BEGIN:VEVENT' . PHP_EOL;
|
||||
|
||||
if ($event['start']) {
|
||||
$tmp = strtotime($event['start']);
|
||||
$dtformat = "%Y%m%dT%H%M%S" . $UTC;
|
||||
$o .= 'DTSTART:' . strftime($dtformat, $tmp) . PHP_EOL;
|
||||
}
|
||||
|
||||
if (!$event['nofinish']) {
|
||||
$tmp = strtotime($event['finish']);
|
||||
$dtformat = "%Y%m%dT%H%M%S" . $UTC;
|
||||
$o .= 'DTEND:' . strftime($dtformat, $tmp) . PHP_EOL;
|
||||
}
|
||||
|
||||
if ($event['summary']) {
|
||||
$tmp = $event['summary'];
|
||||
$tmp = str_replace(PHP_EOL, PHP_EOL . ' ', $tmp);
|
||||
$tmp = addcslashes($tmp, ',;');
|
||||
$o .= 'SUMMARY:' . $tmp . PHP_EOL;
|
||||
}
|
||||
|
||||
if ($event['desc']) {
|
||||
$tmp = $event['desc'];
|
||||
$tmp = str_replace(PHP_EOL, PHP_EOL . ' ', $tmp);
|
||||
$tmp = addcslashes($tmp, ',;');
|
||||
$o .= 'DESCRIPTION:' . $tmp . PHP_EOL;
|
||||
}
|
||||
|
||||
if ($event['location']) {
|
||||
$tmp = $event['location'];
|
||||
$tmp = str_replace(PHP_EOL, PHP_EOL . ' ', $tmp);
|
||||
$tmp = addcslashes($tmp, ',;');
|
||||
$o .= 'LOCATION:' . $tmp . PHP_EOL;
|
||||
}
|
||||
|
||||
$o .= 'END:VEVENT' . PHP_EOL;
|
||||
$o .= PHP_EOL;
|
||||
}
|
||||
|
||||
$o .= 'END:VCALENDAR' . PHP_EOL;
|
||||
break;
|
||||
}
|
||||
|
||||
return $o;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get all events for a user ID.
|
||||
*
|
||||
* The query for events is done permission sensitive.
|
||||
* If the user is the owner of the calendar they
|
||||
* will get all of their available events.
|
||||
* If the user is only a visitor only the public events will
|
||||
* be available.
|
||||
*
|
||||
* @param int $uid The user ID.
|
||||
*
|
||||
* @return array Query results.
|
||||
*/
|
||||
private static function getListByUserId($uid = 0)
|
||||
{
|
||||
$return = [];
|
||||
|
||||
if ($uid == 0) {
|
||||
return $return;
|
||||
}
|
||||
|
||||
$fields = ['start', 'finish', 'adjust', 'summary', 'desc', 'location', 'nofinish'];
|
||||
|
||||
$conditions = ['uid' => $uid, 'cid' => 0];
|
||||
|
||||
// Does the user who requests happen to be the owner of the events
|
||||
// requested? then show all of your events, otherwise only those that
|
||||
// don't have limitations set in allow_cid and allow_gid.
|
||||
if (local_user() != $uid) {
|
||||
$conditions += ['allow_cid' => '', 'allow_gid' => ''];
|
||||
}
|
||||
|
||||
$events = dba::select('event', $fields, $conditions);
|
||||
if (DBM::is_result($events)) {
|
||||
$return = $events;
|
||||
}
|
||||
|
||||
return $return;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param int $uid The user ID.
|
||||
* @param string $format Output format (ical/csv).
|
||||
* @return array With the results:
|
||||
* bool 'success' => True if the processing was successful,<br>
|
||||
* string 'format' => The output format,<br>
|
||||
* string 'extension' => The file extension of the output format,<br>
|
||||
* string 'content' => The formatted output content.<br>
|
||||
*
|
||||
* @todo Respect authenticated users with events_by_uid().
|
||||
*/
|
||||
public static function exportListByUserId($uid, $format = 'ical')
|
||||
{
|
||||
$process = false;
|
||||
|
||||
$user = dba::selectFirst('user', ['timezone'], ['uid' => $uid]);
|
||||
if (DBM::is_result($user)) {
|
||||
$timezone = $user['timezone'];
|
||||
}
|
||||
|
||||
// Get all events which are owned by a uid (respects permissions).
|
||||
$events = self::getListByUserId($uid);
|
||||
|
||||
// We have the events that are available for the requestor.
|
||||
// Now format the output according to the requested format.
|
||||
$res = self::formatListForExport($events, $format, $timezone);
|
||||
|
||||
// If there are results the precess was successfull.
|
||||
if (!empty($res)) {
|
||||
$process = true;
|
||||
}
|
||||
|
||||
// Get the file extension for the format.
|
||||
switch ($format) {
|
||||
case "ical":
|
||||
$file_ext = "ics";
|
||||
break;
|
||||
|
||||
case "csv":
|
||||
$file_ext = "csv";
|
||||
break;
|
||||
|
||||
default:
|
||||
$file_ext = "";
|
||||
}
|
||||
|
||||
$return = [
|
||||
'success' => $process,
|
||||
'format' => $format,
|
||||
'extension' => $file_ext,
|
||||
'content' => $res,
|
||||
];
|
||||
|
||||
return $return;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Format an item array with event data to HTML.
|
||||
*
|
||||
* @param arr $item Array with item and event data.
|
||||
* @return string HTML output.
|
||||
*/
|
||||
public static function getItemHTML($item) {
|
||||
$same_date = false;
|
||||
$finish = false;
|
||||
|
||||
// Set the different time formats.
|
||||
$dformat = L10n::t('l F d, Y \@ g:i A'); // Friday January 18, 2011 @ 8:01 AM.
|
||||
$dformat_short = L10n::t('D g:i A'); // Fri 8:01 AM.
|
||||
$tformat = L10n::t('g:i A'); // 8:01 AM.
|
||||
|
||||
// Convert the time to different formats.
|
||||
$dtstart_dt = day_translate(
|
||||
$item['event-adjust'] ?
|
||||
DateTimeFormat::local($item['event-start'], $dformat)
|
||||
: DateTimeFormat::utc($item['event-start'], $dformat)
|
||||
);
|
||||
$dtstart_title = DateTimeFormat::utc($item['event-start'], $item['event-adjust'] ? DateTimeFormat::ATOM : 'Y-m-d\TH:i:s');
|
||||
// Format: Jan till Dec.
|
||||
$month_short = day_short_translate(
|
||||
$item['event-adjust'] ?
|
||||
DateTimeFormat::local($item['event-start'], 'M')
|
||||
: DateTimeFormat::utc($item['event-start'], 'M')
|
||||
);
|
||||
// Format: 1 till 31.
|
||||
$date_short = $item['event-adjust'] ?
|
||||
DateTimeFormat::local($item['event-start'], 'j')
|
||||
: DateTimeFormat::utc($item['event-start'], 'j');
|
||||
$start_time = $item['event-adjust'] ?
|
||||
DateTimeFormat::local($item['event-start'], $tformat)
|
||||
: DateTimeFormat::utc($item['event-start'], $tformat);
|
||||
$start_short = day_short_translate(
|
||||
$item['event-adjust'] ?
|
||||
DateTimeFormat::local($item['event-start'], $dformat_short)
|
||||
: DateTimeFormat::utc($item['event-start'], $dformat_short)
|
||||
);
|
||||
|
||||
// If the option 'nofinisch' isn't set, we need to format the finish date/time.
|
||||
if (!$item['event-nofinish']) {
|
||||
$finish = true;
|
||||
$dtend_dt = day_translate(
|
||||
$item['event-adjust'] ?
|
||||
DateTimeFormat::local($item['event-finish'], $dformat)
|
||||
: DateTimeFormat::utc($item['event-finish'], $dformat)
|
||||
);
|
||||
$dtend_title = DateTimeFormat::utc($item['event-finish'], $item['event-adjust'] ? DateTimeFormat::ATOM : 'Y-m-d\TH:i:s');
|
||||
$end_short = day_short_translate(
|
||||
$item['event-adjust'] ?
|
||||
DateTimeFormat::local($item['event-finish'], $dformat_short)
|
||||
: DateTimeFormat::utc($item['event-finish'], $dformat_short)
|
||||
);
|
||||
$end_time = $item['event-adjust'] ?
|
||||
DateTimeFormat::local($item['event-finish'], $tformat)
|
||||
: DateTimeFormat::utc($item['event-finish'], $tformat);
|
||||
// Check if start and finish time is at the same day.
|
||||
if (substr($dtstart_title, 0, 10) === substr($dtend_title, 0, 10)) {
|
||||
$same_date = true;
|
||||
}
|
||||
}
|
||||
|
||||
// Format the event location.
|
||||
$location = self::locationToArray($item['event-location']);
|
||||
|
||||
// Construct the profile link (magic-auth).
|
||||
$sp = false;
|
||||
$profile_link = best_link_url($item, $sp);
|
||||
|
||||
if (!$sp) {
|
||||
$profile_link = Profile::zrl($profile_link);
|
||||
}
|
||||
|
||||
$tpl = get_markup_template('event_stream_item.tpl');
|
||||
$return = replace_macros($tpl, [
|
||||
'$id' => $item['event-id'],
|
||||
'$title' => prepare_text($item['event-summary']),
|
||||
'$dtstart_label' => L10n::t('Starts:'),
|
||||
'$dtstart_title' => $dtstart_title,
|
||||
'$dtstart_dt' => $dtstart_dt,
|
||||
'$finish' => $finish,
|
||||
'$dtend_label' => L10n::t('Finishes:'),
|
||||
'$dtend_title' => $dtend_title,
|
||||
'$dtend_dt' => $dtend_dt,
|
||||
'$month_short' => $month_short,
|
||||
'$date_short' => $date_short,
|
||||
'$same_date' => $same_date,
|
||||
'$start_time' => $start_time,
|
||||
'$start_short' => $start_short,
|
||||
'$end_time' => $end_time,
|
||||
'$end_short' => $end_short,
|
||||
'$author_name' => $item['author-name'],
|
||||
'$author_link' => $profile_link,
|
||||
'$author_avatar' => $item['author-avatar'],
|
||||
'$description' => prepare_text($item['event-desc']),
|
||||
'$location_label' => L10n::t('Location:'),
|
||||
'$show_map_label' => L10n::t('Show map'),
|
||||
'$hide_map_label' => L10n::t('Hide map'),
|
||||
'$map_btn_label' => L10n::t('Show map'),
|
||||
'$location' => $location
|
||||
]);
|
||||
|
||||
return $return;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Format a string with map bbcode to an array with location data.
|
||||
*
|
||||
* Note: The string must only contain location data. A string with no bbcode will be
|
||||
* handled as location name.
|
||||
*
|
||||
* @param string $s The string with the bbcode formatted location data.
|
||||
*
|
||||
* @return array The array with the location data.
|
||||
* 'name' => The name of the location,<br>
|
||||
* 'address' => The address of the location,<br>
|
||||
* 'coordinates' => Latitude and longitude (e.g. '48.864716,2.349014').<br>
|
||||
*/
|
||||
private static function locationToArray($s = '') {
|
||||
if ($s == '') {
|
||||
return [];
|
||||
}
|
||||
|
||||
$location = ['name' => $s];
|
||||
|
||||
// Map tag with location name - e.g. [map]Paris[/map].
|
||||
if (strpos($s, '[/map]') !== false) {
|
||||
$found = preg_match("/\[map\](.*?)\[\/map\]/ism", $s, $match);
|
||||
if (intval($found) > 0 && array_key_exists(1, $match)) {
|
||||
$location['address'] = $match[1];
|
||||
// Remove the map bbcode from the location name.
|
||||
$location['name'] = str_replace($match[0], "", $s);
|
||||
}
|
||||
// Map tag with coordinates - e.g. [map=48.864716,2.349014].
|
||||
} elseif (strpos($s, '[map=') !== false) {
|
||||
$found = preg_match("/\[map=(.*?)\]/ism", $s, $match);
|
||||
if (intval($found) > 0 && array_key_exists(1, $match)) {
|
||||
$location['coordinates'] = $match[1];
|
||||
// Remove the map bbcode from the location name.
|
||||
$location['name'] = str_replace($match[0], "", $s);
|
||||
}
|
||||
}
|
||||
|
||||
$location['name'] = prepare_text($location['name']);
|
||||
|
||||
// Construct the map HTML.
|
||||
if (isset($location['address'])) {
|
||||
$location['map'] = '<div class="map">' . Map::byLocation($location['address']) . '</div>';
|
||||
} elseif (isset($location['coordinates'])) {
|
||||
$location['map'] = '<div class="map">' . Map::byCoordinates(str_replace('/', ' ', $location['coordinates'])) . '</div>';
|
||||
}
|
||||
|
||||
return $location;
|
||||
}
|
||||
}
|
|
@ -20,7 +20,6 @@ use dba;
|
|||
use Exception;
|
||||
|
||||
require_once 'include/dba.php';
|
||||
require_once 'include/html2bbcode.php';
|
||||
|
||||
/**
|
||||
* @brief This class handles GlobalContact related functions
|
||||
|
|
|
@ -4,8 +4,8 @@
|
|||
*/
|
||||
namespace Friendica\Model;
|
||||
|
||||
use Friendica\Core\L10n;
|
||||
use Friendica\BaseObject;
|
||||
use Friendica\Core\L10n;
|
||||
use Friendica\Database\DBM;
|
||||
use dba;
|
||||
|
||||
|
@ -40,7 +40,7 @@ class Group extends BaseObject
|
|||
// was restricted to this group may now be seen by the new group members.
|
||||
$group = dba::selectFirst('group', ['deleted'], ['id' => $gid]);
|
||||
if (DBM::is_result($group) && $group['deleted']) {
|
||||
dba::update('group', ['deleted' => 0], ['gid' => $gid]);
|
||||
dba::update('group', ['deleted' => 0], ['id' => $gid]);
|
||||
notice(L10n::t('A deleted group with this name was revived. Existing item permissions <strong>may</strong> apply to this group and any future members. If this is not what you intended, please create another group with a different name.') . EOL);
|
||||
}
|
||||
return true;
|
||||
|
@ -138,7 +138,7 @@ class Group extends BaseObject
|
|||
return false;
|
||||
}
|
||||
|
||||
$group = dba::selectFirst('group', ['uid'], ['gid' => $gid]);
|
||||
$group = dba::selectFirst('group', ['uid'], ['id' => $gid]);
|
||||
if (!DBM::is_result($group)) {
|
||||
return false;
|
||||
}
|
||||
|
@ -289,8 +289,7 @@ class Group extends BaseObject
|
|||
}
|
||||
|
||||
if ($check_dead && !$use_gcontact) {
|
||||
require_once 'include/acl_selectors.php';
|
||||
$return = prune_deadguys($return);
|
||||
Contact::pruneUnavailable($return);
|
||||
}
|
||||
return $return;
|
||||
}
|
||||
|
|
|
@ -29,7 +29,6 @@ use Text_LanguageDetect;
|
|||
require_once 'boot.php';
|
||||
require_once 'include/items.php';
|
||||
require_once 'include/text.php';
|
||||
require_once 'include/event.php';
|
||||
|
||||
class Item extends BaseObject
|
||||
{
|
||||
|
@ -98,7 +97,7 @@ class Item extends BaseObject
|
|||
* @param integer $item_id Item ID that should be delete
|
||||
* @param integer $priority Priority for the notification
|
||||
*
|
||||
* @return $boolean success
|
||||
* @return boolean success
|
||||
*/
|
||||
public static function deleteById($item_id, $priority = PRIORITY_HIGH)
|
||||
{
|
||||
|
@ -153,7 +152,7 @@ class Item extends BaseObject
|
|||
|
||||
// If item is a link to an event, delete the event.
|
||||
if (intval($item['event-id'])) {
|
||||
event_delete($item['event-id']);
|
||||
Event::delete($item['event-id']);
|
||||
}
|
||||
|
||||
// If item has attachments, drop them
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
*/
|
||||
namespace Friendica\Model;
|
||||
|
||||
use DivineOmega\PasswordExposed\PasswordStatus;
|
||||
use Friendica\Core\Addon;
|
||||
use Friendica\Core\Config;
|
||||
use Friendica\Core\L10n;
|
||||
|
@ -22,6 +23,7 @@ use Friendica\Util\Network;
|
|||
use dba;
|
||||
use Exception;
|
||||
use LightOpenID;
|
||||
use function password_exposed;
|
||||
|
||||
require_once 'boot.php';
|
||||
require_once 'include/dba.php';
|
||||
|
@ -101,7 +103,7 @@ class User
|
|||
* @param string $password
|
||||
* @return int|boolean
|
||||
* @deprecated since version 3.6
|
||||
* @see Friendica\Model\User::getIdFromPasswordAuthentication()
|
||||
* @see User::getIdFromPasswordAuthentication()
|
||||
*/
|
||||
public static function authenticate($user_info, $password)
|
||||
{
|
||||
|
@ -216,6 +218,17 @@ class User
|
|||
return autoname(6) . mt_rand(100, 9999);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the provided plaintext password has been exposed or not
|
||||
*
|
||||
* @param string $password
|
||||
* @return bool
|
||||
*/
|
||||
public static function isPasswordExposed($password)
|
||||
{
|
||||
return password_exposed($password) === PasswordStatus::EXPOSED;
|
||||
}
|
||||
|
||||
/**
|
||||
* Legacy hashing function, kept for password migration purposes
|
||||
*
|
||||
|
|
40
src/Module/Hashtag.php
Normal file
40
src/Module/Hashtag.php
Normal file
|
@ -0,0 +1,40 @@
|
|||
<?php
|
||||
/**
|
||||
* @file src/Module/Hashtag.php
|
||||
*/
|
||||
namespace Friendica\Module;
|
||||
|
||||
use Friendica\BaseModule;
|
||||
use Friendica\Core\System;
|
||||
use dba;
|
||||
|
||||
require_once 'include/dba.php';
|
||||
require_once 'include/text.php';
|
||||
|
||||
/**
|
||||
* Hashtag module.
|
||||
*/
|
||||
class Hashtag extends BaseModule
|
||||
{
|
||||
|
||||
public static function content()
|
||||
{
|
||||
$result = [];
|
||||
|
||||
$t = escape_tags($_REQUEST['t']);
|
||||
if (empty($t)) {
|
||||
System::jsonExit($result);
|
||||
}
|
||||
|
||||
$taglist = dba::p("SELECT DISTINCT(`term`) FROM `term` WHERE `term` LIKE ? AND `type` = ? ORDER BY `term`",
|
||||
$t . '%',
|
||||
intval(TERM_HASHTAG)
|
||||
);
|
||||
while ($tag = dba::fetch($taglist)) {
|
||||
$result[] = ['text' => strtolower($tag['term'])];
|
||||
}
|
||||
dba::close($taglist);
|
||||
|
||||
System::jsonExit($result);
|
||||
}
|
||||
}
|
|
@ -11,6 +11,7 @@ namespace Friendica\Protocol;
|
|||
use Friendica\App;
|
||||
use Friendica\Content\OEmbed;
|
||||
use Friendica\Content\Text\BBCode;
|
||||
use Friendica\Content\Text\HTML;
|
||||
use Friendica\Core\Addon;
|
||||
use Friendica\Core\Config;
|
||||
use Friendica\Core\L10n;
|
||||
|
@ -18,11 +19,11 @@ use Friendica\Core\System;
|
|||
use Friendica\Core\Worker;
|
||||
use Friendica\Database\DBM;
|
||||
use Friendica\Model\Contact;
|
||||
use Friendica\Model\Event;
|
||||
use Friendica\Model\GContact;
|
||||
use Friendica\Model\Group;
|
||||
use Friendica\Model\Item;
|
||||
use Friendica\Model\Profile;
|
||||
use Friendica\Model\Term;
|
||||
use Friendica\Model\User;
|
||||
use Friendica\Object\Image;
|
||||
use Friendica\Protocol\OStatus;
|
||||
|
@ -40,9 +41,7 @@ require_once 'boot.php';
|
|||
require_once 'include/dba.php';
|
||||
require_once "include/enotify.php";
|
||||
require_once "include/items.php";
|
||||
require_once "include/event.php";
|
||||
require_once "include/text.php";
|
||||
require_once "include/html2bbcode.php";
|
||||
|
||||
/**
|
||||
* @brief This class contain functions to create and send DFRN XML files
|
||||
|
@ -2454,7 +2453,7 @@ class DFRN
|
|||
$purifier = new HTMLPurifier($config);
|
||||
$item['body'] = $purifier->purify($item['body']);
|
||||
|
||||
$item['body'] = @html2bbcode($item['body']);
|
||||
$item['body'] = @HTML::toBBCode($item['body']);
|
||||
}
|
||||
|
||||
/// @todo We should check for a repeated post and if we know the repeated author.
|
||||
|
@ -2614,7 +2613,7 @@ class DFRN
|
|||
// Is it an event?
|
||||
if ($item["object-type"] == ACTIVITY_OBJ_EVENT) {
|
||||
logger("Item ".$item["uri"]." seems to contain an event.", LOGGER_DEBUG);
|
||||
$ev = bbtoevent($item["body"]);
|
||||
$ev = Event::fromBBCode($item["body"]);
|
||||
if ((x($ev, "desc") || x($ev, "summary")) && x($ev, "start")) {
|
||||
logger("Event in item ".$item["uri"]." was found.", LOGGER_DEBUG);
|
||||
$ev["cid"] = $importer["id"];
|
||||
|
@ -2633,7 +2632,7 @@ class DFRN
|
|||
$ev["id"] = $r[0]["id"];
|
||||
}
|
||||
|
||||
$event_id = event_store($ev);
|
||||
$event_id = Event::store($ev);
|
||||
logger("Event ".$event_id." was stored", LOGGER_DEBUG);
|
||||
return;
|
||||
}
|
||||
|
|
|
@ -7,9 +7,11 @@
|
|||
* This implementation here interprets the old and the new protocol and sends the new one.
|
||||
* In the future we will remove most stuff from "validPosting" and interpret only the new protocol.
|
||||
*/
|
||||
|
||||
namespace Friendica\Protocol;
|
||||
|
||||
use Friendica\Content\Text\BBCode;
|
||||
use Friendica\Content\Text\Markdown;
|
||||
use Friendica\Core\Cache;
|
||||
use Friendica\Core\Config;
|
||||
use Friendica\Core\L10n;
|
||||
|
@ -35,7 +37,6 @@ use SimpleXMLElement;
|
|||
|
||||
require_once 'include/dba.php';
|
||||
require_once 'include/items.php';
|
||||
require_once 'include/bb2diaspora.php';
|
||||
|
||||
/**
|
||||
* @brief This class contain functions to create and send Diaspora XML files
|
||||
|
@ -1748,7 +1749,7 @@ class Diaspora
|
|||
|
||||
$datarray["plink"] = self::plink($author, $guid, $parent_item['guid']);
|
||||
|
||||
$body = diaspora2bb($text);
|
||||
$body = Markdown::toBBCode($text);
|
||||
|
||||
$datarray["body"] = self::replacePeopleGuid($body, $person["url"]);
|
||||
|
||||
|
@ -1815,7 +1816,7 @@ class Diaspora
|
|||
return false;
|
||||
}
|
||||
|
||||
$body = diaspora2bb($msg_text);
|
||||
$body = Markdown::toBBCode($msg_text);
|
||||
$message_uri = $msg_author.":".$msg_guid;
|
||||
|
||||
$person = self::personByHandle($msg_author);
|
||||
|
@ -2149,7 +2150,7 @@ class Diaspora
|
|||
return false;
|
||||
}
|
||||
|
||||
$body = diaspora2bb($text);
|
||||
$body = Markdown::toBBCode($text);
|
||||
|
||||
$body = self::replacePeopleGuid($body, $person["url"]);
|
||||
|
||||
|
@ -2304,8 +2305,8 @@ class Diaspora
|
|||
$image_url = unxmlify($data->image_url);
|
||||
$birthday = unxmlify($data->birthday);
|
||||
$gender = unxmlify($data->gender);
|
||||
$about = diaspora2bb(unxmlify($data->bio));
|
||||
$location = diaspora2bb(unxmlify($data->location));
|
||||
$about = Markdown::toBBCode(unxmlify($data->bio));
|
||||
$location = Markdown::toBBCode(unxmlify($data->location));
|
||||
$searchable = (unxmlify($data->searchable) == "true");
|
||||
$nsfw = (unxmlify($data->nsfw) == "true");
|
||||
$tags = unxmlify($data->tag_string);
|
||||
|
@ -2682,7 +2683,7 @@ class Diaspora
|
|||
if (self::isReshare($r[0]["body"], true)) {
|
||||
$r = [];
|
||||
} elseif (self::isReshare($r[0]["body"], false) || strstr($r[0]["body"], "[share")) {
|
||||
$r[0]["body"] = diaspora2bb(bb2diaspora($r[0]["body"]));
|
||||
$r[0]["body"] = Markdown::toBBCode(BBCode::toMarkdown($r[0]["body"]));
|
||||
|
||||
$r[0]["body"] = self::replacePeopleGuid($r[0]["body"], $r[0]["author-link"]);
|
||||
|
||||
|
@ -2717,7 +2718,7 @@ class Diaspora
|
|||
if (DBM::is_result($r)) {
|
||||
// If it is a reshared post from another network then reformat to avoid display problems with two share elements
|
||||
if (self::isReshare($r[0]["body"], false)) {
|
||||
$r[0]["body"] = diaspora2bb(bb2diaspora($r[0]["body"]));
|
||||
$r[0]["body"] = Markdown::toBBCode(BBCode::toMarkdown($r[0]["body"]));
|
||||
$r[0]["body"] = self::replacePeopleGuid($r[0]["body"], $r[0]["author-link"]);
|
||||
}
|
||||
|
||||
|
@ -2961,7 +2962,7 @@ class Diaspora
|
|||
}
|
||||
}
|
||||
|
||||
$body = diaspora2bb($text);
|
||||
$body = Markdown::toBBCode($text);
|
||||
|
||||
$datarray = [];
|
||||
|
||||
|
@ -3613,17 +3614,17 @@ class Diaspora
|
|||
$eventdata['end'] = DateTimeFormat::convert($event['finish'], "UTC", $eventdata['timezone'], $mask);
|
||||
}
|
||||
if ($event['summary']) {
|
||||
$eventdata['summary'] = html_entity_decode(bb2diaspora($event['summary']));
|
||||
$eventdata['summary'] = html_entity_decode(BBCode::toMarkdown($event['summary']));
|
||||
}
|
||||
if ($event['desc']) {
|
||||
$eventdata['description'] = html_entity_decode(bb2diaspora($event['desc']));
|
||||
$eventdata['description'] = html_entity_decode(BBCode::toMarkdown($event['desc']));
|
||||
}
|
||||
if ($event['location']) {
|
||||
$event['location'] = preg_replace("/\[map\](.*?)\[\/map\]/ism", '$1', $event['location']);
|
||||
$coord = Map::getCoordinates($event['location']);
|
||||
|
||||
$location = [];
|
||||
$location["address"] = html_entity_decode(bb2diaspora($event['location']));
|
||||
$location["address"] = html_entity_decode(BBCode::toMarkdown($event['location']));
|
||||
if (!empty($coord['lat']) && !empty($coord['lon'])) {
|
||||
$location["lat"] = $coord['lat'];
|
||||
$location["lng"] = $coord['lon'];
|
||||
|
@ -3678,7 +3679,7 @@ class Diaspora
|
|||
$body = $item["body"];
|
||||
|
||||
// convert to markdown
|
||||
$body = html_entity_decode(bb2diaspora($body));
|
||||
$body = html_entity_decode(BBCode::toMarkdown($body));
|
||||
|
||||
// Adding the title
|
||||
if (strlen($title)) {
|
||||
|
@ -3869,7 +3870,7 @@ class Diaspora
|
|||
|
||||
$parent = $p[0];
|
||||
|
||||
$text = html_entity_decode(bb2diaspora($item["body"]));
|
||||
$text = html_entity_decode(BBCode::toMarkdown($item["body"]));
|
||||
$created = DateTimeFormat::utc($item["created"], DateTimeFormat::ATOM);
|
||||
|
||||
$comment = ["author" => self::myHandle($owner),
|
||||
|
@ -4105,7 +4106,7 @@ class Diaspora
|
|||
"participants" => $cnv["recips"]
|
||||
];
|
||||
|
||||
$body = bb2diaspora($item["body"]);
|
||||
$body = BBCode::toMarkdown($item["body"]);
|
||||
$created = DateTimeFormat::utc($item["created"], DateTimeFormat::ATOM);
|
||||
|
||||
$msg = [
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
*/
|
||||
namespace Friendica\Protocol;
|
||||
|
||||
require_once 'include/html2plain.php';
|
||||
use Friendica\Content\Text\HTML;
|
||||
|
||||
/**
|
||||
* @brief Email class
|
||||
|
@ -111,7 +111,7 @@ class Email
|
|||
if (trim($ret['body']) == '') {
|
||||
$ret['body'] = self::messageGetPart($mbox, $uid, $struc, 0, 'plain');
|
||||
} else {
|
||||
$ret['body'] = html2bbcode($ret['body']);
|
||||
$ret['body'] = HTML::toBBCode($ret['body']);
|
||||
}
|
||||
} else {
|
||||
$text = '';
|
||||
|
@ -128,7 +128,7 @@ class Email
|
|||
}
|
||||
}
|
||||
if (trim($html) != '') {
|
||||
$ret['body'] = html2bbcode($html);
|
||||
$ret['body'] = HTML::toBBCode($html);
|
||||
} else {
|
||||
$ret['body'] = $text;
|
||||
}
|
||||
|
@ -328,7 +328,7 @@ class Email
|
|||
$body .= "Content-Transfer-Encoding: 8bit\n";
|
||||
$body .= "Content-Type: text/plain; charset=utf-8; format=flowed\n\n";
|
||||
|
||||
$body .= html2plain($html)."\n";
|
||||
$body .= HTML::toPlaintext($html)."\n";
|
||||
|
||||
$body .= "--=_".$part."\n";
|
||||
$body .= "Content-Transfer-Encoding: 8bit\n";
|
||||
|
|
|
@ -10,12 +10,13 @@ use Friendica\Database\DBM;
|
|||
use Friendica\Core\System;
|
||||
use Friendica\Model\Item;
|
||||
use Friendica\Util\Network;
|
||||
use Friendica\Content\Text\HTML;
|
||||
|
||||
use dba;
|
||||
use DOMDocument;
|
||||
use DOMXPath;
|
||||
|
||||
require_once 'include/dba.php';
|
||||
require_once 'include/html2bbcode.php';
|
||||
require_once 'include/items.php';
|
||||
|
||||
/**
|
||||
|
@ -360,7 +361,7 @@ class Feed {
|
|||
if (self::titleIsBody($item["title"], $body)) {
|
||||
$item["title"] = "";
|
||||
}
|
||||
$item["body"] = html2bbcode($body, $basepath);
|
||||
$item["body"] = HTML::toBBCode($body, $basepath);
|
||||
|
||||
if (($item["body"] == '') && ($item["title"] != '')) {
|
||||
$item["body"] = $item["title"];
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
namespace Friendica\Protocol;
|
||||
|
||||
use Friendica\Content\Text\BBCode;
|
||||
use Friendica\Content\Text\HTML;
|
||||
use Friendica\Core\Cache;
|
||||
use Friendica\Core\Config;
|
||||
use Friendica\Core\L10n;
|
||||
|
@ -25,7 +26,6 @@ use DOMDocument;
|
|||
use DOMXPath;
|
||||
|
||||
require_once 'include/dba.php';
|
||||
require_once 'include/html2bbcode.php';
|
||||
require_once 'include/items.php';
|
||||
require_once 'mod/share.php';
|
||||
require_once 'include/enotify.php';
|
||||
|
@ -171,7 +171,7 @@ class OStatus
|
|||
|
||||
$value = $xpath->evaluate('atom:author/poco:note/text()', $context)->item(0)->nodeValue;
|
||||
if ($value != "") {
|
||||
$contact["about"] = html2bbcode($value);
|
||||
$contact["about"] = HTML::toBBCode($value);
|
||||
}
|
||||
|
||||
$value = $xpath->evaluate('atom:author/poco:address/poco:formatted/text()', $context)->item(0)->nodeValue;
|
||||
|
@ -559,7 +559,7 @@ class OStatus
|
|||
*/
|
||||
private static function processPost($xpath, $entry, &$item, $importer)
|
||||
{
|
||||
$item["body"] = html2bbcode($xpath->query('atom:content/text()', $entry)->item(0)->nodeValue);
|
||||
$item["body"] = HTML::toBBCode($xpath->query('atom:content/text()', $entry)->item(0)->nodeValue);
|
||||
$item["object-type"] = $xpath->query('activity:object-type/text()', $entry)->item(0)->nodeValue;
|
||||
if (($item["object-type"] == ACTIVITY_OBJ_BOOKMARK) || ($item["object-type"] == ACTIVITY_OBJ_EVENT)) {
|
||||
$item["title"] = $xpath->query('atom:title/text()', $entry)->item(0)->nodeValue;
|
||||
|
@ -661,7 +661,7 @@ class OStatus
|
|||
if (($item["verb"] == ACTIVITY_POST) && $xpath->evaluate('boolean(atom:summary)', $entry)) {
|
||||
$clear_text = $xpath->query('atom:summary/text()', $entry)->item(0)->nodeValue;
|
||||
if (!empty($clear_text)) {
|
||||
$item['content-warning'] = html2bbcode($clear_text);
|
||||
$item['content-warning'] = HTML::toBBCode($clear_text);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1019,7 +1019,7 @@ class OStatus
|
|||
$item["author-link"] = $orig_author["author-link"];
|
||||
$item["author-avatar"] = $orig_author["author-avatar"];
|
||||
|
||||
$item["body"] = html2bbcode($orig_body);
|
||||
$item["body"] = HTML::toBBCode($orig_body);
|
||||
$item["created"] = $orig_created;
|
||||
$item["edited"] = $orig_edited;
|
||||
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
|
||||
namespace Friendica\Protocol;
|
||||
|
||||
use Friendica\Content\Text\HTML;
|
||||
use Friendica\Core\Config;
|
||||
use Friendica\Core\Worker;
|
||||
use Friendica\Database\DBM;
|
||||
|
@ -23,7 +24,6 @@ use DOMXPath;
|
|||
use Exception;
|
||||
|
||||
require_once 'include/dba.php';
|
||||
require_once 'include/html2bbcode.php';
|
||||
|
||||
class PortableContact
|
||||
{
|
||||
|
@ -155,7 +155,7 @@ class PortableContact
|
|||
}
|
||||
|
||||
if (isset($entry->aboutMe)) {
|
||||
$about = html2bbcode($entry->aboutMe);
|
||||
$about = HTML::toBBCode($entry->aboutMe);
|
||||
}
|
||||
|
||||
if (isset($entry->gender)) {
|
||||
|
@ -1678,7 +1678,7 @@ class PortableContact
|
|||
}
|
||||
|
||||
if (isset($entry->aboutMe)) {
|
||||
$about = html2bbcode($entry->aboutMe);
|
||||
$about = HTML::toBBCode($entry->aboutMe);
|
||||
}
|
||||
|
||||
if (isset($entry->gender)) {
|
||||
|
|
|
@ -13,14 +13,14 @@
|
|||
* Installation:
|
||||
*
|
||||
* - Change it's owner to whichever user is running the server, ie. ejabberd
|
||||
* $ chown ejabberd:ejabberd /path/to/friendica/scripts/auth_ejabberd.php
|
||||
* $ chown ejabberd:ejabberd /path/to/friendica/bin/auth_ejabberd.php
|
||||
*
|
||||
* - Change the access mode so it is readable only to the user ejabberd and has exec
|
||||
* $ chmod 700 /path/to/friendica/scripts/auth_ejabberd.php
|
||||
* $ chmod 700 /path/to/friendica/bin/auth_ejabberd.php
|
||||
*
|
||||
* - Edit your ejabberd.cfg file, comment out your auth_method and add:
|
||||
* {auth_method, external}.
|
||||
* {extauth_program, "/path/to/friendica/script/auth_ejabberd.php"}.
|
||||
* {extauth_program, "/path/to/friendica/bin/auth_ejabberd.php"}.
|
||||
*
|
||||
* - Restart your ejabberd service, you should be able to login with your friendica auth info
|
||||
*
|
||||
|
|
|
@ -79,6 +79,18 @@ class Network
|
|||
|
||||
$a = get_app();
|
||||
|
||||
$parts = parse_url($url);
|
||||
$path_parts = explode('/', $parts['path']);
|
||||
foreach ($path_parts as $part) {
|
||||
if (strlen($part) <> mb_strlen($part)) {
|
||||
$parts2[] = rawurlencode($part);
|
||||
} else {
|
||||
$parts2[] = $part;
|
||||
}
|
||||
}
|
||||
$parts['path'] = implode('/', $parts2);
|
||||
$url = self::unparseURL($parts);
|
||||
|
||||
if (self::isUrlBlocked($url)) {
|
||||
logger('domain of ' . $url . ' is blocked', LOGGER_DATA);
|
||||
return $ret;
|
||||
|
|
|
@ -17,7 +17,6 @@ use Friendica\Protocol\Diaspora;
|
|||
use Friendica\Protocol\Email;
|
||||
use dba;
|
||||
|
||||
require_once 'include/html2plain.php';
|
||||
require_once 'include/items.php';
|
||||
|
||||
/// @todo This is some ugly code that needs to be split into several methods
|
||||
|
|
|
@ -18,7 +18,6 @@ use Friendica\Protocol\Salmon;
|
|||
use dba;
|
||||
|
||||
require_once 'include/dba.php';
|
||||
require_once 'include/html2plain.php';
|
||||
require_once 'include/items.php';
|
||||
|
||||
/*
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue