2015-03-21 23:06:08 +00:00
< ? php
/**
* @ file include / text . php
2020-05-10 23:19:01 +00:00
* This file started as some additional text handling functions but has grown to include
* a number of miscellaneous functions that didn ' t really fit anywhere else . Perhaps it should be named " misc.php " instead .
2015-03-21 23:06:08 +00:00
*/
2011-08-01 23:51:01 +00:00
2018-07-03 23:40:54 +00:00
use Zotlabs\Lib\MarkdownSoap ;
2019-02-14 23:26:37 +00:00
use Zotlabs\Lib\AccessList ;
2018-07-23 05:18:58 +00:00
use Zotlabs\Lib\Libzot ;
2019-11-06 05:34:47 +00:00
use Zotlabs\Lib\SvgSanitizer ;
2020-03-05 02:55:25 +00:00
use Zotlabs\Lib\Img_cache ;
2020-06-01 00:24:09 +00:00
use Zotlabs\Lib\PConfig ;
use Zotlabs\Lib\Config ;
2020-11-04 23:02:01 +00:00
use Zotlabs\Lib\Activity ;
2018-07-23 05:18:58 +00:00
2018-07-03 23:40:54 +00:00
use Michelf\MarkdownExtra ;
2018-09-05 03:59:11 +00:00
use Ramsey\Uuid\Uuid ;
use Ramsey\Uuid\Exception\UnsatisfiedDependencyException ;
2017-01-30 23:01:22 +00:00
2015-03-21 23:06:08 +00:00
2013-05-08 07:51:38 +00:00
/**
2015-03-21 23:06:08 +00:00
* @ brief This is our template processor .
2015-01-09 00:02:15 +00:00
*
2016-05-21 02:11:14 +00:00
* @ param string | SmartyEngine $s the string requiring macro substitution ,
* or an instance of SmartyEngine
2013-05-08 07:51:38 +00:00
* @ param array $r key value pairs ( search => replace )
2016-10-01 22:41:25 +00:00
*
2013-05-08 07:51:38 +00:00
* @ return string substituted string
*/
2015-03-21 23:06:08 +00:00
function replace_macros ( $s , $r ) {
2017-12-23 13:42:23 +00:00
$arr = [
2018-09-05 03:59:11 +00:00
'template' => $s ,
'params' => $r
2017-12-23 13:42:23 +00:00
];
2013-01-06 21:42:51 +00:00
2017-12-23 13:42:23 +00:00
/**
* @ hooks replace_macros
* * \e string \b template
* * \e array \b params
*/
2020-05-10 23:19:01 +00:00
2013-11-29 03:17:20 +00:00
call_hooks ( 'replace_macros' , $arr );
2015-01-09 00:02:15 +00:00
2016-03-31 23:06:03 +00:00
$t = App :: template_engine ();
2018-09-14 21:35:12 +00:00
2020-05-10 23:19:01 +00:00
try {
$output = $t -> replace_macros ( $arr [ 'template' ], $arr [ 'params' ]);
}
catch ( Exception $e ) {
2020-09-22 23:49:44 +00:00
btlogger ( " Unable to render template: " . $e -> getMessage ());
2020-05-10 23:19:01 +00:00
$output = " <h3>ERROR: there was an error creating the output.</h3> " ;
}
2015-01-09 00:02:15 +00:00
2013-01-06 21:42:51 +00:00
return $output ;
2013-02-27 02:26:33 +00:00
}
2011-08-01 23:51:01 +00:00
2015-03-21 23:06:08 +00:00
/**
* @ brief Generates a random string .
*
* @ param number $size
* @ param int $type
2016-10-01 22:41:25 +00:00
*
2015-03-21 23:06:08 +00:00
* @ return string
2020-05-10 23:19:01 +00:00
*
* There are 86 characters max in text mode , 128 for hex . output is urlsafe .
2015-03-21 23:06:08 +00:00
*/
2020-05-10 23:19:01 +00:00
define ( 'RANDOM_STRING_HEX' , 0x00 );
define ( 'RANDOM_STRING_TEXT' , 0x01 );
2015-03-21 23:06:08 +00:00
function random_string ( $size = 64 , $type = RANDOM_STRING_HEX ) {
2011-08-11 04:06:35 +00:00
// generate a bit of entropy and run it through the whirlpool
$s = hash ( 'whirlpool' , ( string ) rand () . uniqid ( rand (), true ) . ( string ) rand (),(( $type == RANDOM_STRING_TEXT ) ? true : false ));
$s = (( $type == RANDOM_STRING_TEXT ) ? str_replace ( " \n " , " " , base64url_encode ( $s , true )) : $s );
2015-03-21 23:06:08 +00:00
return ( substr ( $s , 0 , $size ));
2013-02-27 02:26:33 +00:00
}
2011-08-01 23:51:01 +00:00
/**
2020-05-10 23:19:01 +00:00
* @ brief Input filter to replace HTML tag characters with something safe - without changing the string length .
2011-08-01 23:51:01 +00:00
*
2013-05-08 07:51:38 +00:00
* @ param string $string Input string
2016-10-01 22:41:25 +00:00
*
2013-05-08 07:51:38 +00:00
* @ return string Filtered string
2020-05-10 23:19:01 +00:00
*
2011-08-01 23:51:01 +00:00
*/
function notags ( $string ) {
return ( str_replace ( array ( " < " , " > " ), array ( '[' , ']' ), $string ));
2013-02-27 02:26:33 +00:00
}
2011-08-01 23:51:01 +00:00
2013-05-08 07:51:38 +00:00
/**
2018-09-05 03:59:11 +00:00
* use this on input where angle chars shouldn ' t be removed ,
* and allow them to be safely used in HTML .
2016-10-01 22:41:25 +00:00
*
2013-05-08 07:51:38 +00:00
* @ param string $string
2016-10-01 22:41:25 +00:00
*
2013-05-08 07:51:38 +00:00
* @ return string
*/
2011-08-01 23:51:01 +00:00
function escape_tags ( $string ) {
2012-12-07 00:12:45 +00:00
return ( htmlspecialchars ( $string , ENT_COMPAT , 'UTF-8' , false ));
2013-02-27 02:26:33 +00:00
}
2011-08-01 23:51:01 +00:00
2021-03-22 04:56:18 +00:00
function z_input_filter ( $s , $type = 'text/x-multicode' , $allow_code = false ) {
2013-09-02 08:38:17 +00:00
2021-03-08 05:32:28 +00:00
if ( in_array ( $type , [ 'text/bbcode' , 'text/x-multicode' ])) {
2021-02-11 01:55:10 +00:00
return ( multicode_purify ( $s ));
2021-02-02 22:49:11 +00:00
}
2013-09-02 08:38:17 +00:00
if ( $type == 'text/plain' )
return escape_tags ( $s );
2015-11-13 01:47:38 +00:00
if ( $type == 'application/x-pdl' )
return escape_tags ( $s );
2015-04-09 06:12:39 +00:00
2016-03-31 23:06:03 +00:00
if ( App :: $is_sys ) {
2015-04-09 06:20:28 +00:00
return $s ;
2015-04-09 06:12:39 +00:00
}
2017-03-15 00:07:29 +00:00
if ( $allow_code ) {
if ( $type === 'text/markdown' )
return htmlspecialchars ( $s , ENT_QUOTES );
2017-03-13 23:19:47 +00:00
return $s ;
2013-09-02 08:38:17 +00:00
}
2017-03-15 00:07:29 +00:00
if ( $type === 'text/markdown' ) {
2018-07-03 23:40:54 +00:00
$x = new MarkdownSoap ( $s );
2017-03-15 00:07:29 +00:00
return $x -> clean ();
}
2013-09-02 08:38:17 +00:00
if ( $type === 'text/html' )
return purify_html ( $s );
return escape_tags ( $s );
}
2017-03-18 16:50:05 +00:00
/**
* @ brief Use HTMLPurifier to get standards compliant HTML .
*
* Use the < a href = " http://htmlpurifier.org/ " target = " _blank " > HTMLPurifier </ a >
* library to get filtered and standards compliant HTML .
*
* @ see HTMLPurifier
*
* @ param string $s raw HTML
* @ param boolean $allow_position allow CSS position
* @ return string standards compliant filtered HTML
*/
2021-02-04 22:45:07 +00:00
function purify_html ( $s , $opts = []) {
2013-05-28 08:40:27 +00:00
$config = HTMLPurifier_Config :: createDefault ();
$config -> set ( 'Cache.DefinitionImpl' , null );
2014-07-11 22:28:26 +00:00
$config -> set ( 'Attr.EnableID' , true );
2013-05-28 08:40:27 +00:00
2021-06-19 23:04:32 +00:00
// disable Unicode version of RTL over-ride
$s = str_replace ([ '‮' , '‮' , html_entity_decode ( '‮' , ENT_QUOTES , 'UTF-8' ) ],[ '' , '' , '' ], $s );
2021-02-04 22:45:07 +00:00
// This will escape invalid tags in the output instead of removing.
// This is necessary for mixed format (text+bbcode+html+markdown) messages or
// some angle brackets in plaintext may get stripped if they look like an HTML tag
if ( in_array ( 'escape' , $opts )) {
$config -> set ( 'Core.EscapeInvalidChildren' , true );
$config -> set ( 'Core.EscapeInvalidTags' , true );
}
2017-03-18 16:50:05 +00:00
// If enabled, target=blank attributes are added to all links.
//$config->set('HTML.TargetBlank', true);
//$config->set('Attr.AllowedFrameTargets', ['_blank', '_self', '_parent', '_top']);
// restore old behavior of HTMLPurifier < 4.8, only used when targets allowed at all
// do not add rel="noreferrer" to all links with target attributes
//$config->set('HTML.TargetNoreferrer', false);
// do not add noopener rel attributes to links which have a target attribute associated with them
//$config->set('HTML.TargetNoopener', false);
2015-05-27 13:25:45 +00:00
//Allow some custom data- attributes used by built-in libs.
//In this way members which do not have allowcode set can still use the built-in js libs in webpages to some extent.
$def = $config -> getHTMLDefinition ( true );
//data- attributes used by the foundation library
2016-09-07 10:57:52 +00:00
// f6 navigation
//dropdown menu
$def -> info_global_attr [ 'data-dropdown-menu' ] = new HTMLPurifier_AttrDef_Text ;
//drilldown menu
$def -> info_global_attr [ 'data-drilldown' ] = new HTMLPurifier_AttrDef_Text ;
//accordion menu
$def -> info_global_attr [ 'data-accordion-menu' ] = new HTMLPurifier_AttrDef_Text ;
2016-09-08 09:22:58 +00:00
//responsive navigation
$def -> info_global_attr [ 'data-responsive-menu' ] = new HTMLPurifier_AttrDef_Text ;
$def -> info_global_attr [ 'data-responsive-toggle' ] = new HTMLPurifier_AttrDef_Text ;
2021-02-04 22:45:07 +00:00
//magellan
2016-09-07 10:57:52 +00:00
$def -> info_global_attr [ 'data-magellan' ] = new HTMLPurifier_AttrDef_Text ;
$def -> info_global_attr [ 'data-magellan-target' ] = new HTMLPurifier_AttrDef_Text ;
// f6 containers
//accordion
$def -> info_global_attr [ 'data-accordion' ] = new HTMLPurifier_AttrDef_Text ;
$def -> info_global_attr [ 'data-accordion-item' ] = new HTMLPurifier_AttrDef_Text ;
$def -> info_global_attr [ 'data-tab-content' ] = new HTMLPurifier_AttrDef_Text ;
//dropdown
2015-05-27 13:25:45 +00:00
$def -> info_global_attr [ 'data-dropdown' ] = new HTMLPurifier_AttrDef_Text ;
2016-09-07 10:57:52 +00:00
//off-canvas
$def -> info_global_attr [ 'data-off-canvas-wrapper' ] = new HTMLPurifier_AttrDef_Text ;
$def -> info_global_attr [ 'data-off-canvas' ] = new HTMLPurifier_AttrDef_Text ;
$def -> info_global_attr [ 'data-off-canvas-content' ] = new HTMLPurifier_AttrDef_Text ;
//reveal
2015-05-27 13:25:45 +00:00
$def -> info_global_attr [ 'data-reveal' ] = new HTMLPurifier_AttrDef_Text ;
2016-09-07 10:57:52 +00:00
//tabs
$def -> info_global_attr [ 'data-tabs' ] = new HTMLPurifier_AttrDef_Text ;
$def -> info_global_attr [ 'data-tabs-content' ] = new HTMLPurifier_AttrDef_Text ;
// f6 media
//orbit
$def -> info_global_attr [ 'data-orbit' ] = new HTMLPurifier_AttrDef_Text ;
$def -> info_global_attr [ 'data-slide' ] = new HTMLPurifier_AttrDef_Text ;
//tooltip
2015-05-27 13:25:45 +00:00
$def -> info_global_attr [ 'data-tooltip' ] = new HTMLPurifier_AttrDef_Text ;
2016-09-07 10:57:52 +00:00
// f6 plugins
2016-10-01 22:41:25 +00:00
//abide - the use is pointless since we can't do anything with forms
2016-09-07 10:57:52 +00:00
//equalizer
2015-05-27 13:25:45 +00:00
$def -> info_global_attr [ 'data-equalizer' ] = new HTMLPurifier_AttrDef_Text ;
$def -> info_global_attr [ 'data-equalizer-watch' ] = new HTMLPurifier_AttrDef_Text ;
2016-09-07 10:57:52 +00:00
//interchange - potentially dangerous since it can load content
//toggler
$def -> info_global_attr [ 'data-toggler' ] = new HTMLPurifier_AttrDef_Text ;
//sticky
$def -> info_global_attr [ 'data-sticky' ] = new HTMLPurifier_AttrDef_Text ;
$def -> info_global_attr [ 'data-sticky-container' ] = new HTMLPurifier_AttrDef_Text ;
// f6 common
$def -> info_global_attr [ 'data-options' ] = new HTMLPurifier_AttrDef_Text ;
$def -> info_global_attr [ 'data-toggle' ] = new HTMLPurifier_AttrDef_Text ;
$def -> info_global_attr [ 'data-close' ] = new HTMLPurifier_AttrDef_Text ;
$def -> info_global_attr [ 'data-open' ] = new HTMLPurifier_AttrDef_Text ;
2016-09-08 09:22:58 +00:00
$def -> info_global_attr [ 'data-position' ] = new HTMLPurifier_AttrDef_Text ;
2016-09-07 10:57:52 +00:00
2015-05-27 13:25:45 +00:00
//data- attributes used by the bootstrap library
$def -> info_global_attr [ 'data-dismiss' ] = new HTMLPurifier_AttrDef_Text ;
$def -> info_global_attr [ 'data-target' ] = new HTMLPurifier_AttrDef_Text ;
$def -> info_global_attr [ 'data-toggle' ] = new HTMLPurifier_AttrDef_Text ;
$def -> info_global_attr [ 'data-backdrop' ] = new HTMLPurifier_AttrDef_Text ;
$def -> info_global_attr [ 'data-keyboard' ] = new HTMLPurifier_AttrDef_Text ;
$def -> info_global_attr [ 'data-show' ] = new HTMLPurifier_AttrDef_Text ;
$def -> info_global_attr [ 'data-spy' ] = new HTMLPurifier_AttrDef_Text ;
$def -> info_global_attr [ 'data-offset' ] = new HTMLPurifier_AttrDef_Text ;
$def -> info_global_attr [ 'data-animation' ] = new HTMLPurifier_AttrDef_Text ;
$def -> info_global_attr [ 'data-container' ] = new HTMLPurifier_AttrDef_Text ;
$def -> info_global_attr [ 'data-delay' ] = new HTMLPurifier_AttrDef_Text ;
$def -> info_global_attr [ 'data-placement' ] = new HTMLPurifier_AttrDef_Text ;
$def -> info_global_attr [ 'data-title' ] = new HTMLPurifier_AttrDef_Text ;
$def -> info_global_attr [ 'data-trigger' ] = new HTMLPurifier_AttrDef_Text ;
$def -> info_global_attr [ 'data-content' ] = new HTMLPurifier_AttrDef_Text ;
$def -> info_global_attr [ 'data-trigger' ] = new HTMLPurifier_AttrDef_Text ;
$def -> info_global_attr [ 'data-parent' ] = new HTMLPurifier_AttrDef_Text ;
$def -> info_global_attr [ 'data-ride' ] = new HTMLPurifier_AttrDef_Text ;
$def -> info_global_attr [ 'data-slide-to' ] = new HTMLPurifier_AttrDef_Text ;
$def -> info_global_attr [ 'data-slide' ] = new HTMLPurifier_AttrDef_Text ;
$def -> info_global_attr [ 'data-interval' ] = new HTMLPurifier_AttrDef_Text ;
$def -> info_global_attr [ 'data-pause' ] = new HTMLPurifier_AttrDef_Text ;
$def -> info_global_attr [ 'data-wrap' ] = new HTMLPurifier_AttrDef_Text ;
$def -> info_global_attr [ 'data-offset-top' ] = new HTMLPurifier_AttrDef_Text ;
$def -> info_global_attr [ 'data-offset-bottom' ] = new HTMLPurifier_AttrDef_Text ;
//some html5 elements
2016-09-09 12:29:20 +00:00
//Block
2015-05-27 13:25:45 +00:00
$def -> addElement ( 'section' , 'Block' , 'Flow' , 'Common' );
$def -> addElement ( 'nav' , 'Block' , 'Flow' , 'Common' );
$def -> addElement ( 'article' , 'Block' , 'Flow' , 'Common' );
$def -> addElement ( 'aside' , 'Block' , 'Flow' , 'Common' );
$def -> addElement ( 'header' , 'Block' , 'Flow' , 'Common' );
$def -> addElement ( 'footer' , 'Block' , 'Flow' , 'Common' );
2016-09-09 12:29:20 +00:00
//Inline
$def -> addElement ( 'button' , 'Inline' , 'Inline' , 'Common' );
2021-05-19 21:58:18 +00:00
$def -> addElement ( 'mark' , 'Inline' , 'Inline' , 'Common' );
2016-05-02 02:19:17 +00:00
2021-02-04 22:45:07 +00:00
if ( in_array ( 'allow_position' , $opts )) {
2016-05-02 02:19:17 +00:00
$cssDefinition = $config -> getCSSDefinition ();
$cssDefinition -> info [ 'position' ] = new HTMLPurifier_AttrDef_Enum ( array ( 'absolute' , 'fixed' , 'relative' , 'static' , 'inherit' ), false );
$cssDefinition -> info [ 'left' ] = new HTMLPurifier_AttrDef_CSS_Composite ( array (
new HTMLPurifier_AttrDef_CSS_Length (),
new HTMLPurifier_AttrDef_CSS_Percentage ()
));
$cssDefinition -> info [ 'right' ] = new HTMLPurifier_AttrDef_CSS_Composite ( array (
new HTMLPurifier_AttrDef_CSS_Length (),
new HTMLPurifier_AttrDef_CSS_Percentage ()
));
$cssDefinition -> info [ 'top' ] = new HTMLPurifier_AttrDef_CSS_Composite ( array (
new HTMLPurifier_AttrDef_CSS_Length (),
new HTMLPurifier_AttrDef_CSS_Percentage ()
));
$cssDefinition -> info [ 'bottom' ] = new HTMLPurifier_AttrDef_CSS_Composite ( array (
new HTMLPurifier_AttrDef_CSS_Length (),
new HTMLPurifier_AttrDef_CSS_Percentage ()
));
}
2013-05-28 08:40:27 +00:00
$purifier = new HTMLPurifier ( $config );
2015-03-21 23:06:08 +00:00
2013-05-28 08:40:27 +00:00
return $purifier -> purify ( $s );
}
2013-05-08 07:51:38 +00:00
/**
2017-12-23 13:42:23 +00:00
* @ brief Generate a string that ' s random , but usually pronounceable .
2015-03-21 23:06:08 +00:00
*
* Used to generate initial passwords .
*
2017-12-23 13:42:23 +00:00
* @ note In order to create " pronounceable " strings some consonant pairs or
* letters that does not make a very good word ending are chopped off , so that
* the returned string length can be lower than $len .
*
* @ param int $len max length of generated string
* @ return string Genereated random , but usually pronounceable string
2013-05-08 07:51:38 +00:00
*/
2011-08-01 23:51:01 +00:00
function autoname ( $len ) {
2015-03-21 23:06:08 +00:00
if ( $len <= 0 )
2012-04-06 01:44:36 +00:00
return '' ;
2016-10-01 22:41:25 +00:00
$vowels = array ( 'a' , 'a' , 'ai' , 'au' , 'e' , 'e' , 'e' , 'ee' , 'ea' , 'i' , 'ie' , 'o' , 'ou' , 'u' );
2015-03-21 23:06:08 +00:00
if ( mt_rand ( 0 , 5 ) == 4 )
2011-08-01 23:51:01 +00:00
$vowels [] = 'y' ;
$cons = array (
'b' , 'bl' , 'br' ,
'c' , 'ch' , 'cl' , 'cr' ,
'd' , 'dr' ,
'f' , 'fl' , 'fr' ,
'g' , 'gh' , 'gl' , 'gr' ,
'h' ,
'j' ,
'k' , 'kh' , 'kl' , 'kr' ,
'l' ,
'm' ,
'n' ,
'p' , 'ph' , 'pl' , 'pr' ,
'qu' ,
'r' , 'rh' ,
's' , 'sc' , 'sh' , 'sm' , 'sp' , 'st' ,
't' , 'th' , 'tr' ,
'v' ,
'w' , 'wh' ,
'x' ,
'z' , 'zh'
);
$midcons = array ( 'ck' , 'ct' , 'gn' , 'ld' , 'lf' , 'lm' , 'lt' , 'mb' , 'mm' , 'mn' , 'mp' ,
'nd' , 'ng' , 'nk' , 'nt' , 'rn' , 'rp' , 'rt' );
2017-12-23 13:42:23 +00:00
// avoid these consonant pairs at the end of the string
2011-08-01 23:51:01 +00:00
$noend = array ( 'bl' , 'br' , 'cl' , 'cr' , 'dr' , 'fl' , 'fr' , 'gl' , 'gr' ,
'kh' , 'kl' , 'kr' , 'mn' , 'pl' , 'pr' , 'rh' , 'tr' , 'qu' , 'wh' );
2015-03-21 23:06:08 +00:00
$start = mt_rand ( 0 , 2 );
if ( $start == 0 )
2014-12-14 00:22:52 +00:00
$table = $vowels ;
else
$table = $cons ;
2011-08-01 23:51:01 +00:00
$word = '' ;
for ( $x = 0 ; $x < $len ; $x ++ ) {
2017-12-23 13:42:23 +00:00
$r = mt_rand ( 0 , count ( $table ) - 1 );
2014-12-14 00:22:52 +00:00
$word .= $table [ $r ];
2015-03-21 23:06:08 +00:00
if ( $table == $vowels )
$table = array_merge ( $cons , $midcons );
2014-12-14 00:22:52 +00:00
else
$table = $vowels ;
2011-08-01 23:51:01 +00:00
}
2017-12-23 13:42:23 +00:00
$word = substr ( $word , 0 , $len );
2011-08-01 23:51:01 +00:00
2015-03-21 23:06:08 +00:00
foreach ( $noend as $noe ) {
2017-12-23 13:42:23 +00:00
if (( strlen ( $word ) > 2 ) && ( substr ( $word , - 2 ) == $noe )) {
$word = substr ( $word , 0 , - 1 );
2014-12-14 00:22:52 +00:00
break ;
}
2011-08-01 23:51:01 +00:00
}
2017-12-23 13:42:23 +00:00
// avoid the letter 'q' as it does not make a very good word ending
2015-03-21 23:06:08 +00:00
if ( substr ( $word , - 1 ) == 'q' )
$word = substr ( $word , 0 , - 1 );
2011-08-01 23:51:01 +00:00
return $word ;
2013-02-27 02:26:33 +00:00
}
2011-08-01 23:51:01 +00:00
2013-05-08 07:51:38 +00:00
/**
2015-03-21 23:06:08 +00:00
* @ brief escape text ( $str ) for XML transport
*
2013-05-08 07:51:38 +00:00
* @ param string $str
* @ return string Escaped text .
*/
2011-08-01 23:51:01 +00:00
function xmlify ( $str ) {
$buffer = '' ;
2014-12-14 00:22:52 +00:00
2016-05-27 01:45:47 +00:00
if ( is_array ( $str )) {
2016-10-01 22:41:25 +00:00
// allow to fall through so we ge a PHP error, as the log statement will
// probably get lost in the noise unless we're specifically looking for it.
2016-05-27 01:45:47 +00:00
btlogger ( 'xmlify called with array: ' . print_r ( $str , true ), LOGGER_NORMAL , LOG_WARNING );
}
2013-02-06 04:14:19 +00:00
$len = mb_strlen ( $str );
for ( $x = 0 ; $x < $len ; $x ++ ) {
$char = mb_substr ( $str , $x , 1 );
2014-12-14 00:22:52 +00:00
2011-08-01 23:51:01 +00:00
switch ( $char ) {
case " \r " :
break ;
case " & " :
$buffer .= '&' ;
break ;
case " ' " :
$buffer .= ''' ;
break ;
case " \" " :
$buffer .= '"' ;
break ;
case '<' :
$buffer .= '<' ;
break ;
case '>' :
$buffer .= '>' ;
break ;
case " \n " :
$buffer .= " \n " ;
break ;
default :
$buffer .= $char ;
break ;
2015-03-21 23:06:08 +00:00
}
2011-08-01 23:51:01 +00:00
}
$buffer = trim ( $buffer );
2015-03-21 23:06:08 +00:00
2011-08-01 23:51:01 +00:00
return ( $buffer );
2013-02-27 02:26:33 +00:00
}
2011-08-01 23:51:01 +00:00
2016-10-01 22:41:25 +00:00
/**
* @ brief Undo an xmlify .
*
* Pass xml escaped text ( $s ), returns unescaped text .
*
* @ param string $s
*
* @ return string
*/
2011-08-01 23:51:01 +00:00
function unxmlify ( $s ) {
2016-10-01 22:41:25 +00:00
$ret = str_replace ( '&' , '&' , $s );
$ret = str_replace ( array ( '<' , '>' , '"' , ''' ), array ( '<' , '>' , '"' , " ' " ), $ret );
2014-12-14 00:22:52 +00:00
return $ret ;
2013-02-27 02:26:33 +00:00
}
2011-08-01 23:51:01 +00:00
2016-10-01 22:41:25 +00:00
/**
* @ brief Automatic pagination .
*
* To use , get the count of total items .
* Then call App :: set_pager_total ( $number_items );
* Optionally call App :: set_pager_itemspage ( $n ) to the number of items to display on each page
* Then call paginate ( $a ) after the end of the display loop to insert the pager block on the page
* ( assuming there are enough items to paginate ) .
* When using with SQL , the setting LIMIT % d , % d => App :: $pager [ 'start' ], App :: $pager [ 'itemspage' ]
* will limit the results to the correct items for the current page .
* The actual page handling is then accomplished at the application layer .
*
* @ param App & $a
*/
2011-08-01 23:51:01 +00:00
function paginate ( & $a ) {
$o = '' ;
2016-03-31 23:06:03 +00:00
$stripped = preg_replace ( '/(&page=[0-9]*)/' , '' , App :: $query_string );
2012-04-02 07:45:45 +00:00
2012-11-09 03:07:19 +00:00
// $stripped = preg_replace('/&zid=(.*?)([\?&]|$)/ism','',$stripped);
2012-04-02 07:45:45 +00:00
2011-08-01 23:51:01 +00:00
$stripped = str_replace ( 'q=' , '' , $stripped );
$stripped = trim ( $stripped , '/' );
2016-03-31 23:06:03 +00:00
$pagenum = App :: $pager [ 'page' ];
2016-03-31 05:13:24 +00:00
$url = z_root () . '/' . $stripped ;
2011-08-01 23:51:01 +00:00
2016-03-31 23:06:03 +00:00
if ( App :: $pager [ 'total' ] > App :: $pager [ 'itemspage' ]) {
2011-08-01 23:51:01 +00:00
$o .= '<div class="pager">' ;
2016-03-31 23:06:03 +00:00
if ( App :: $pager [ 'page' ] != 1 )
$o .= '<span class="pager_prev">' . " <a href= \" $url " . '&page=' . ( App :: $pager [ 'page' ] - 1 ) . '">' . t ( 'prev' ) . '</a></span> ' ;
2011-08-01 23:51:01 +00:00
$o .= " <span class= \" pager_first \" ><a href= \" $url " . " &page=1 \" > " . t ( 'first' ) . " </a></span> " ;
2016-10-01 22:41:25 +00:00
$numpages = App :: $pager [ 'total' ] / App :: $pager [ 'itemspage' ];
2011-08-01 23:51:01 +00:00
2016-10-01 22:41:25 +00:00
$numstart = 1 ;
$numstop = $numpages ;
2011-08-01 23:51:01 +00:00
2016-10-01 22:41:25 +00:00
if ( $numpages > 14 ) {
$numstart = (( $pagenum > 7 ) ? ( $pagenum - 7 ) : 1 );
$numstop = (( $pagenum > ( $numpages - 7 )) ? $numpages : ( $numstart + 14 ));
}
2014-12-14 00:22:52 +00:00
2011-08-01 23:51:01 +00:00
for ( $i = $numstart ; $i <= $numstop ; $i ++ ){
2016-03-31 23:06:03 +00:00
if ( $i == App :: $pager [ 'page' ])
2011-08-01 23:51:01 +00:00
$o .= '<span class="pager_current">' . (( $i < 10 ) ? ' ' . $i : $i );
else
$o .= " <span class= \" pager_n \" ><a href= \" $url " . " &page= $i\ " > " .(( $i < 10) ? ' '. $i : $i ). " </ a > " ;
$o .= '</span> ' ;
}
2016-03-31 23:06:03 +00:00
if (( App :: $pager [ 'total' ] % App :: $pager [ 'itemspage' ]) != 0 ) {
if ( $i == App :: $pager [ 'page' ])
2011-08-01 23:51:01 +00:00
$o .= '<span class="pager_current">' . (( $i < 10 ) ? ' ' . $i : $i );
else
$o .= " <span class= \" pager_n \" ><a href= \" $url " . " &page= $i\ " > " .(( $i < 10) ? ' '. $i : $i ). " </ a > " ;
$o .= '</span> ' ;
}
$lastpage = (( $numpages > intval ( $numpages )) ? intval ( $numpages ) + 1 : $numpages );
$o .= " <span class= \" pager_last \" ><a href= \" $url " . " &page= $lastpage\ " > " . t('last') . " </ a ></ span > " ;
2016-03-31 23:06:03 +00:00
if (( App :: $pager [ 'total' ] - ( App :: $pager [ 'itemspage' ] * App :: $pager [ 'page' ])) > 0 )
$o .= '<span class="pager_next">' . " <a href= \" $url " . " &page= " . ( App :: $pager [ 'page' ] + 1 ) . '">' . t ( 'next' ) . '</a></span>' ;
2011-08-01 23:51:01 +00:00
$o .= '</div>' . " \r \n " ;
}
2016-10-01 22:41:25 +00:00
2011-08-01 23:51:01 +00:00
return $o ;
2013-02-27 02:26:33 +00:00
}
2011-08-01 23:51:01 +00:00
2018-04-18 06:36:35 +00:00
function alt_pager ( $i , $more = '' , $less = '' ) {
2013-01-19 08:43:05 +00:00
if ( ! $more )
$more = t ( 'older' );
if ( ! $less )
$less = t ( 'newer' );
2016-03-31 23:06:03 +00:00
$stripped = preg_replace ( '/(&page=[0-9]*)/' , '' , App :: $query_string );
2012-07-15 03:39:46 +00:00
$stripped = str_replace ( 'q=' , '' , $stripped );
$stripped = trim ( $stripped , '/' );
2016-03-31 23:06:03 +00:00
//$pagenum = App::$pager['page'];
2016-03-31 05:13:24 +00:00
$url = z_root () . '/' . $stripped ;
2012-07-15 03:39:46 +00:00
2015-03-12 23:16:19 +00:00
return replace_macros ( get_markup_template ( 'alt_pager.tpl' ), array (
2016-03-31 23:06:03 +00:00
'$has_less' => (( App :: $pager [ 'page' ] > 1 ) ? true : false ),
'$has_more' => (( $i > 0 && $i >= App :: $pager [ 'itemspage' ]) ? true : false ),
2013-06-04 01:16:00 +00:00
'$less' => $less ,
'$more' => $more ,
'$url' => $url ,
2016-03-31 23:06:03 +00:00
'$prevpage' => App :: $pager [ 'page' ] - 1 ,
'$nextpage' => App :: $pager [ 'page' ] + 1 ,
2013-06-04 01:16:00 +00:00
));
2012-07-15 03:39:46 +00:00
2013-02-27 02:26:33 +00:00
}
2012-07-15 03:39:46 +00:00
2015-03-21 23:06:08 +00:00
2014-12-14 00:22:52 +00:00
/**
* @ brief Generate a guaranteed unique ( for this domain ) item ID for ATOM .
*
* Safe from birthday paradox .
*
* @ return string a unique id
*/
2012-10-04 05:28:19 +00:00
function item_message_id () {
2018-09-05 03:59:11 +00:00
2018-09-07 04:27:09 +00:00
try {
$hash = Uuid :: uuid4 () -> toString ();
} catch ( UnsatisfiedDependencyException $e ) {
$hash = random_string ( 48 );
}
2018-09-05 03:59:11 +00:00
2018-09-07 04:27:09 +00:00
$mid = z_root () . '/item/' . $hash ;
2014-12-14 00:22:52 +00:00
2013-03-22 01:25:41 +00:00
return $mid ;
2013-02-27 02:26:33 +00:00
}
2011-08-01 23:51:01 +00:00
2014-12-14 00:22:52 +00:00
/**
* @ brief Generate a guaranteed unique photo ID .
*
* Safe from birthday paradox .
*
2018-05-18 10:09:38 +00:00
* @ return string a unique hash
2014-12-14 00:22:52 +00:00
*/
2011-08-01 23:51:01 +00:00
function photo_new_resource () {
2014-12-14 00:22:52 +00:00
2018-09-07 04:27:09 +00:00
try {
$hash = Uuid :: uuid4 () -> toString ();
} catch ( UnsatisfiedDependencyException $e ) {
$hash = random_string ( 48 );
}
2014-12-14 00:22:52 +00:00
2018-09-05 03:59:11 +00:00
return $hash ;
2013-02-27 02:26:33 +00:00
}
2011-08-01 23:51:01 +00:00
2018-10-29 03:39:01 +00:00
2019-10-01 02:25:48 +00:00
// provide psuedo random token (string) consisting entirely of US-ASCII letters/numbers
// and with possibly variable length
function new_token ( $minlen = 36 , $maxlen = 48 ) {
$chars = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890' ;
$str = EMPTY_STR ;
$len = (( $minlen === $maxlen ) ? $minlen : mt_rand ( $minlen , $maxlen ));
for ( $a = 0 ; $a < $len ; $a ++ ) {
$str .= $chars [ mt_rand ( 0 , 62 )];
}
return $str ;
2019-09-27 03:58:29 +00:00
}
2018-10-29 03:39:01 +00:00
/**
* @ brief Generate a unique ID .
*
* @ return string
*/
function new_uuid () {
try {
$hash = Uuid :: uuid4 () -> toString ();
} catch ( UnsatisfiedDependencyException $e ) {
$hash = random_string ( 48 );
}
return $hash ;
}
2016-10-01 22:41:25 +00:00
/**
* @ brief
*
* for html , xml parsing - let 's say you' ve got
* an attribute foobar = " class1 class2 class3 "
* and you want to find out if it contains 'class3' .
* you can ' t use a normal sub string search because you
* might match 'notclass3' and a regex to do the job is
* possible but a bit complicated .
*
* pass the attribute string as $attr and the attribute you
* are looking for as $s - returns true if found , otherwise false
*
* @ param string $attr attribute string
* @ param string $s attribute you are looking for
* @ return boolean true if found
*/
2014-12-14 00:22:52 +00:00
function attribute_contains ( $attr , $s ) {
2017-02-15 19:35:36 +00:00
// remove quotes
$attr = str_replace ([ '"' , " ' " ],[ '' , '' ], $attr );
2011-08-01 23:51:01 +00:00
$a = explode ( ' ' , $attr );
2017-02-15 19:35:36 +00:00
if ( $a && in_array ( $s , $a ))
2011-08-01 23:51:01 +00:00
return true ;
2014-12-14 00:22:52 +00:00
2011-08-01 23:51:01 +00:00
return false ;
2013-02-27 02:26:33 +00:00
}
2014-12-14 00:22:52 +00:00
/**
2015-05-05 10:56:10 +00:00
* @ brief Logging function for Hubzilla .
2014-12-14 00:22:52 +00:00
*
2015-05-05 10:56:10 +00:00
* Logging output is configured through Hubzilla ' s system config . The log file
2014-12-14 00:22:52 +00:00
* is set in system logfile , log level in system loglevel and to enable logging
* set system debugging .
*
* Available constants for log level are LOGGER_NORMAL , LOGGER_TRACE , LOGGER_DEBUG ,
* LOGGER_DATA and LOGGER_ALL .
*
* Since PHP5 . 4 we get the file , function and line automatically where the logger
2015-11-16 03:36:17 +00:00
* was called , so no need to add it to the message anymore .
2014-12-14 00:22:52 +00:00
*
* @ param string $msg Message to log
2016-10-01 22:41:25 +00:00
* @ param int $level A log level
2015-12-31 21:25:23 +00:00
* @ param int $priority - compatible with syslog
2014-12-14 00:22:52 +00:00
*/
2015-12-31 20:26:41 +00:00
function logger ( $msg , $level = LOGGER_NORMAL , $priority = LOG_INFO ) {
2016-04-26 03:12:36 +00:00
2016-05-25 00:54:45 +00:00
if ( App :: $module == 'setup' && is_writable ( 'install.log' )) {
$debugging = true ;
$logfile = 'install.log' ;
$loglevel = LOGGER_ALL ;
}
else {
$debugging = get_config ( 'system' , 'debugging' );
$loglevel = intval ( get_config ( 'system' , 'loglevel' ));
$logfile = get_config ( 'system' , 'logfile' );
}
2011-08-01 23:51:01 +00:00
if (( ! $debugging ) || ( ! $logfile ) || ( $level > $loglevel ))
return ;
2014-09-05 06:13:46 +00:00
$where = '' ;
2016-10-01 22:41:25 +00:00
2017-05-24 04:20:40 +00:00
$stack = debug_backtrace ( DEBUG_BACKTRACE_IGNORE_ARGS , 2 );
$where = basename ( $stack [ 0 ][ 'file' ]) . ':' . $stack [ 0 ][ 'line' ] . ':' . $stack [ 1 ][ 'function' ] . ': ' ;
2014-09-05 06:13:46 +00:00
2018-06-25 20:20:12 +00:00
$s = datetime_convert ( 'UTC' , 'UTC' , 'now' , ATOM_TIME ) . ':' . log_priority_str ( $priority ) . ':' . logid () . ':' . $where . $msg . PHP_EOL ;
2015-12-31 20:26:41 +00:00
$pluginfo = array ( 'filename' => $logfile , 'loglevel' => $level , 'message' => $s , 'priority' => $priority , 'logged' => false );
2015-11-16 03:36:17 +00:00
2016-05-25 00:54:45 +00:00
if ( ! ( App :: $module == 'setup' ))
call_hooks ( 'logger' , $pluginfo );
2015-11-16 03:36:17 +00:00
if ( ! $pluginfo [ 'logged' ])
2015-11-16 03:40:01 +00:00
@ file_put_contents ( $pluginfo [ 'filename' ], $pluginfo [ 'message' ], FILE_APPEND );
2013-02-27 02:26:33 +00:00
}
2011-08-01 23:51:01 +00:00
2018-06-25 20:20:12 +00:00
function logid () {
$x = session_id ();
if ( ! $x )
$x = getmypid ();
2018-06-25 20:33:23 +00:00
return substr ( hash ( 'whirlpool' , $x ), 0 , 10 );
2018-06-25 20:20:12 +00:00
}
2016-10-01 22:41:25 +00:00
/**
* @ brief like logger () but with a function backtrace to pinpoint certain classes
* of problems which show up deep in the calling stack .
*
* @ param string $msg Message to log
* @ param int $level A log level
* @ param int $priority - compatible with syslog
*/
2016-03-30 23:33:23 +00:00
function btlogger ( $msg , $level = LOGGER_NORMAL , $priority = LOG_INFO ) {
2017-01-11 01:37:41 +00:00
if ( ! defined ( 'BTLOGGER_DEBUG_FILE' ))
define ( 'BTLOGGER_DEBUG_FILE' , 'btlogger.out' );
2016-03-30 23:33:23 +00:00
logger ( $msg , $level , $priority );
2016-12-22 07:35:54 +00:00
2017-01-11 01:37:41 +00:00
if ( file_exists ( BTLOGGER_DEBUG_FILE ) && is_writable ( BTLOGGER_DEBUG_FILE )) {
2016-12-22 07:35:54 +00:00
$stack = debug_backtrace ( DEBUG_BACKTRACE_IGNORE_ARGS , 2 );
$where = basename ( $stack [ 0 ][ 'file' ]) . ':' . $stack [ 0 ][ 'line' ] . ':' . $stack [ 1 ][ 'function' ] . ': ' ;
2018-06-25 20:20:12 +00:00
$s = datetime_convert ( 'UTC' , 'UTC' , 'now' , ATOM_TIME ) . ':' . log_priority_str ( $priority ) . ':' . logid () . ':' . $where . $msg . PHP_EOL ;
2017-01-11 01:37:41 +00:00
@ file_put_contents ( BTLOGGER_DEBUG_FILE , $s , FILE_APPEND );
2016-12-22 07:35:54 +00:00
}
2017-05-24 04:20:40 +00:00
$stack = debug_backtrace ( DEBUG_BACKTRACE_IGNORE_ARGS );
if ( $stack ) {
for ( $x = 1 ; $x < count ( $stack ); $x ++ ) {
$s = 'stack: ' . basename ( $stack [ $x ][ 'file' ]) . ':' . $stack [ $x ][ 'line' ] . ':' . $stack [ $x ][ 'function' ] . '()' ;
logger ( $s , $level , $priority );
2016-12-22 07:35:54 +00:00
2017-05-24 04:20:40 +00:00
if ( file_exists ( BTLOGGER_DEBUG_FILE ) && is_writable ( BTLOGGER_DEBUG_FILE )) {
@ file_put_contents ( BTLOGGER_DEBUG_FILE , $s . PHP_EOL , FILE_APPEND );
2016-10-01 22:41:25 +00:00
}
2016-03-30 23:33:23 +00:00
}
}
}
2015-12-31 20:26:41 +00:00
function log_priority_str ( $priority ) {
$parr = array (
LOG_EMERG => 'LOG_EMERG' ,
LOG_ALERT => 'LOG_ALERT' ,
LOG_CRIT => 'LOG_CRIT' ,
LOG_ERR => 'LOG_ERR' ,
LOG_WARNING => 'LOG_WARNING' ,
LOG_NOTICE => 'LOG_NOTICE' ,
LOG_INFO => 'LOG_INFO' ,
LOG_DEBUG => 'LOG_DEBUG'
);
if ( $parr [ $priority ])
return $parr [ $priority ];
return 'LOG_UNDEFINED' ;
}
2014-12-14 00:22:52 +00:00
/**
* @ brief This is a special logging facility for developers .
*
* It allows one to target specific things to trace / debug and is identical to
* logger () with the exception of the log filename . This allows one to isolate
* specific calls while allowing logger () to paint a bigger picture of overall
* activity and capture more detail .
*
* If you find dlogger () calls in checked in code , you are free to remove them -
* so as to provide a noise - free development environment which responds to events
* you are targetting personally .
*
* @ param string $msg Message to log
* @ param int $level A log level .
*/
function dlogger ( $msg , $level = 0 ) {
2016-05-25 03:49:23 +00:00
2016-04-25 23:55:33 +00:00
// turn off logger in install mode
2016-04-26 03:12:36 +00:00
2016-05-25 03:49:23 +00:00
if ( App :: $module == 'setup' )
2014-12-14 00:22:52 +00:00
return ;
2013-02-06 04:39:19 +00:00
$debugging = get_config ( 'system' , 'debugging' );
$loglevel = intval ( get_config ( 'system' , 'loglevel' ));
$logfile = get_config ( 'system' , 'dlogfile' );
if (( ! $debugging ) || ( ! $logfile ) || ( $level > $loglevel ))
return ;
2014-12-14 00:22:52 +00:00
$where = '' ;
2017-05-24 04:20:40 +00:00
$stack = debug_backtrace ( DEBUG_BACKTRACE_IGNORE_ARGS , 2 );
$where = basename ( $stack [ 0 ][ 'file' ]) . ':' . $stack [ 0 ][ 'line' ] . ':' . $stack [ 1 ][ 'function' ] . ': ' ;
2014-12-14 00:22:52 +00:00
2018-06-25 20:20:12 +00:00
@ file_put_contents ( $logfile , datetime_convert ( 'UTC' , 'UTC' , 'now' , ATOM_TIME ) . ':' . logid () . ' ' . $where . $msg . PHP_EOL , FILE_APPEND );
2013-02-27 02:26:33 +00:00
}
2013-02-06 04:39:19 +00:00
2013-02-09 10:46:50 +00:00
function profiler ( $t1 , $t2 , $label ) {
if ( file_exists ( 'profiler.out' ) && $t1 && t2 )
2014-12-14 00:22:52 +00:00
@ file_put_contents ( 'profiler.out' , sprintf ( '%01.4f %s' , $t2 - $t1 , $label ) . PHP_EOL , FILE_APPEND );
2013-02-09 10:46:50 +00:00
}
2013-02-06 04:39:19 +00:00
2011-08-01 23:51:01 +00:00
function activity_match ( $haystack , $needle ) {
2013-05-24 01:50:27 +00:00
2017-09-25 05:41:14 +00:00
if ( ! is_array ( $needle ))
$needle = [ $needle ];
if ( $needle ) {
foreach ( $needle as $n ) {
if (( $haystack === $n ) || ( strtolower ( basename ( $n )) === strtolower ( basename ( $haystack )))) {
return true ;
}
}
}
2011-08-01 23:51:01 +00:00
return false ;
2013-02-27 02:26:33 +00:00
}
2011-08-01 23:51:01 +00:00
2016-10-01 22:41:25 +00:00
/**
2017-05-04 22:23:57 +00:00
* @ brief Pull out all \ #hashtags and \@person tags from $s.
2016-10-01 22:41:25 +00:00
*
2017-05-04 22:23:57 +00:00
* We also get \ @ person\ @ domain . com - which would make
2016-10-01 22:41:25 +00:00
* the regex quite complicated as tags can also
* end a sentence . So we ' ll run through our results
* and strip the period from any tags which end with one .
*
* @ param string $s
* @ return Returns array of tags found , or empty array .
*/
2011-08-01 23:51:01 +00:00
function get_tags ( $s ) {
2021-03-15 05:10:44 +00:00
$ret = [];
$match = [];
2011-08-01 23:51:01 +00:00
2021-05-19 21:58:18 +00:00
// ignore anything in a code or svg block or HTML tag
2011-08-01 23:51:01 +00:00
2016-07-18 11:48:09 +00:00
$s = preg_replace ( '/\[code(.*?)\](.*?)\[\/code\]/sm' , '' , $s );
2021-05-19 21:58:18 +00:00
$s = preg_replace ( '/\<(.*?)\>/sm' , '' , $s );
2019-11-06 05:34:47 +00:00
$s = preg_replace ( '/\[svg(.*?)\](.*?)\[\/svg\]/sm' , '' , $s );
2011-08-01 23:51:01 +00:00
2014-02-05 13:34:25 +00:00
// ignore anything in [style= ]
$s = preg_replace ( '/\[style=(.*?)\]/sm' , '' , $s );
2015-01-16 18:10:34 +00:00
// ignore anything in [color= ], because it may contain color codes which are mistaken for tags
$s = preg_replace ( '/\[color=(.*?)\]/sm' , '' , $s );
2019-01-23 03:11:53 +00:00
// skip anchors in URL
$s = preg_replace ( '/\[url=(.*?)\]/sm' , '' , $s );
2014-04-12 23:58:19 +00:00
// match any double quoted tags
2018-05-10 00:09:38 +00:00
if ( preg_match_all ( '/([@#\!]\"\;.*?\"\;)/' , $s , $match )) {
2014-04-12 23:58:19 +00:00
foreach ( $match [ 1 ] as $mtch ) {
$ret [] = $mtch ;
}
}
2020-07-02 05:21:30 +00:00
// match any unescaped double quoted tags (rare)
2020-05-10 23:19:01 +00:00
if ( preg_match_all ( '/([@#\!]\".*?\")/' , $s , $match )) {
foreach ( $match [ 1 ] as $mtch ) {
$ret [] = $mtch ;
}
}
2018-04-24 22:32:24 +00:00
// match bracket mentions
2018-05-15 00:20:25 +00:00
if ( preg_match_all ( '/([@!]\!?\{.*?\})/' , $s , $match )) {
2018-04-24 22:32:24 +00:00
foreach ( $match [ 1 ] as $mtch ) {
$ret [] = $mtch ;
}
}
2018-05-04 03:14:58 +00:00
// Pull out single word tags. These can be @nickname, @first_last
2011-08-01 23:51:01 +00:00
// and #hash tags.
2019-02-13 23:33:45 +00:00
if ( preg_match_all ( '/(?<![a-zA-Z0-9=\pL\/\?\;])([@#]\!?[^ \x0D\x0A,;:\?\[\{\&]+)/u' , $s , $match )) {
2011-08-01 23:51:01 +00:00
foreach ( $match [ 1 ] as $mtch ) {
2018-05-15 00:20:25 +00:00
// Cleanup/ignore false positives
// Just ignore these rather than try and adjust the regex to deal with them
if ( in_array ( $mtch ,[ '@!' , '!!' ]))
continue ;
// likewise for trailing period. Strip it off rather than complicate the regex further.
2011-09-10 00:35:26 +00:00
if ( substr ( $mtch , - 1 , 1 ) === '.' )
$mtch = substr ( $mtch , 0 , - 1 );
2014-10-16 00:55:20 +00:00
// ignore strictly numeric tags like #1 or #^ bookmarks or ## double hash
2018-05-15 00:20:25 +00:00
if (( strpos ( $mtch , '#' ) === 0 ) && ( ctype_digit ( substr ( $mtch , 1 )) || in_array ( substr ( $mtch , 1 , 1 ), [ '^' , '#' ])))
2011-08-01 23:51:01 +00:00
continue ;
2014-04-13 00:04:54 +00:00
// or quote remnants from the quoted strings we already picked out earlier
2021-02-08 00:24:41 +00:00
if (( strpos ( $mtch , '"' )) || strpos ( $mtch , " \" " ))
2014-04-13 00:04:54 +00:00
continue ;
2011-09-10 00:35:26 +00:00
$ret [] = $mtch ;
2011-08-01 23:51:01 +00:00
}
}
2014-02-04 03:38:15 +00:00
2014-03-31 03:53:59 +00:00
// make sure the longer tags are returned first so that if two or more have common substrings
// we'll replace the longest ones first. Otherwise the common substring would be found in
2016-10-01 22:41:25 +00:00
// both strings and the string replacement would link both to the shorter strings and
2015-05-05 10:56:10 +00:00
// fail to link the longer string. Hubzilla github issue #378
2016-10-01 22:41:25 +00:00
2014-03-31 03:53:59 +00:00
usort ( $ret , 'tag_sort_length' );
2014-02-04 03:38:15 +00:00
2018-05-15 00:20:25 +00:00
// logger('get_tags: ' . print_r($ret,true));
2014-02-04 03:38:15 +00:00
2011-08-01 23:51:01 +00:00
return $ret ;
2013-02-27 02:26:33 +00:00
}
2011-08-01 23:51:01 +00:00
2014-03-31 03:53:59 +00:00
function tag_sort_length ( $a , $b ) {
if ( mb_strlen ( $a ) == mb_strlen ( $b ))
return 0 ;
2014-12-14 00:22:52 +00:00
2014-03-31 03:53:59 +00:00
return (( mb_strlen ( $b ) < mb_strlen ( $a )) ? ( - 1 ) : 1 );
}
2017-03-03 01:32:43 +00:00
function total_sort ( $a , $b ) {
if ( $a [ 'total' ] == $b [ 'total' ])
return 0 ;
2017-03-03 07:02:44 +00:00
return (( $b [ 'total' ] > $a [ 'total' ]) ? 1 : ( - 1 ));
2017-03-03 01:32:43 +00:00
}
2014-03-31 03:53:59 +00:00
2016-10-01 22:41:25 +00:00
/**
* @ brief Quick and dirty quoted_printable encoding .
*
* @ param string $s
* @ return string
*/
2011-08-01 23:51:01 +00:00
function qp ( $s ) {
2016-10-01 22:41:25 +00:00
return str_replace ( " % " , " = " , rawurlencode ( $s ));
}
2013-02-27 02:26:33 +00:00
2012-12-07 02:17:43 +00:00
function chanlink_hash ( $s ) {
return z_root () . '/chanview?f=&hash=' . urlencode ( $s );
}
function chanlink_url ( $s ) {
return z_root () . '/chanview?f=&url=' . urlencode ( $s );
}
function chanlink_cid ( $d ) {
return z_root () . '/chanview?f=&cid=' . intval ( $d );
}
2013-01-25 12:30:03 +00:00
function magiclink_url ( $observer , $myaddr , $url ) {
2016-10-01 22:41:25 +00:00
return (( $observer )
2018-07-19 00:05:38 +00:00
? z_root () . '/magic?f=&owa=1&bdest=' . bin2hex ( $url ) . '&addr=' . $myaddr
2013-01-25 12:30:03 +00:00
: $url
);
}
2012-12-07 02:17:43 +00:00
2013-02-27 02:26:33 +00:00
2011-08-01 23:51:01 +00:00
2011-09-05 00:35:06 +00:00
function search ( $s , $id = 'search-box' , $url = '/search' , $save = false ) {
2016-05-25 03:49:23 +00:00
2014-10-08 10:36:26 +00:00
return replace_macros ( get_markup_template ( 'searchbox.tpl' ), array (
'$s' => $s ,
'$id' => $id ,
2016-03-31 05:13:24 +00:00
'$action_url' => z_root () . $url ,
2014-10-08 10:36:26 +00:00
'$search_label' => t ( 'Search' ),
'$save_label' => t ( 'Save' ),
2015-01-29 04:56:04 +00:00
'$savedsearch' => feature_enabled ( local_channel (), 'savedsearch' )
2014-10-08 10:36:26 +00:00
));
2013-02-27 02:26:33 +00:00
}
2011-08-01 23:51:01 +00:00
2013-12-10 05:20:55 +00:00
function searchbox ( $s , $id = 'search-box' , $url = '/search' , $save = false ) {
2014-10-08 10:36:26 +00:00
return replace_macros ( get_markup_template ( 'searchbox.tpl' ), array (
'$s' => $s ,
'$id' => $id ,
'$action_url' => z_root () . '/' . $url ,
'$search_label' => t ( 'Search' ),
'$save_label' => t ( 'Save' ),
2016-09-01 04:57:08 +00:00
'$savedsearch' => ( $save && feature_enabled ( local_channel (), 'savedsearch' ))
2014-10-08 10:36:26 +00:00
));
2013-12-10 05:20:55 +00:00
}
2011-08-01 23:51:01 +00:00
/**
2015-03-21 23:06:08 +00:00
* @ brief Replace naked text hyperlink with HTML formatted hyperlink .
2011-08-01 23:51:01 +00:00
*
2015-03-21 23:06:08 +00:00
* @ param string $s
* @ param boolean $me ( optional ) default false
* @ return string
2011-08-01 23:51:01 +00:00
*/
2015-03-21 23:06:08 +00:00
function linkify ( $s , $me = false ) {
2019-08-26 02:17:35 +00:00
$rel = 'nofollow noopener' ;
if ( $me ) {
$rel .= ' me' ;
}
$s = preg_replace ( " /(https? \ : \ / \ /[a-zA-Z0-9 \ pL \ : \ / \ - \ ? \ & \ ; \ . \ = \ _ \ @ \ ~ \ # \ ' \ % \$ \ ! \ + \ , \ @]*)/u " , '<a href="$1" rel="' . $rel . '" >$1</a>' , $s );
2011-09-15 03:47:49 +00:00
$s = preg_replace ( " / \ <(.*?)(src|href)=(.*?) \ & \ ;(.*?) \ >/ism " , '<$1$2=$3&$4>' , $s );
2015-03-21 23:06:08 +00:00
2011-08-01 23:51:01 +00:00
return ( $s );
2013-02-27 02:26:33 +00:00
}
2011-08-01 23:51:01 +00:00
2013-12-25 10:45:22 +00:00
/**
2020-03-05 04:07:26 +00:00
* @ brief implement image caching
2013-12-25 10:45:22 +00:00
*
2020-03-05 04:51:20 +00:00
* Note : This is named sslify because the original behaviour was only to proxy image fetches to
* non - SSL resources . Now all images can be cached . If this is disabled , we ' ll fall back to only caching
* the http : images
2013-12-25 10:45:22 +00:00
*
2015-03-21 23:06:08 +00:00
* @ param string $s
2013-12-25 10:45:22 +00:00
* @ returns string
*/
2020-08-17 04:55:59 +00:00
function sslify ( $s , $cache_enable = true ) {
2016-10-01 22:41:25 +00:00
2021-04-21 02:33:06 +00:00
if ( ! $cache_enable ) {
// we're fetching an old item and we are no longer
// caching photos for it. Remove any existing cached photos.
// Cron_weekly tasks will also remove these, but if the cache
// entry was updated recently they might not get removed for
// another couple of months.
uncache ( $s );
}
2020-08-17 04:55:59 +00:00
if (( ! $cache_enable ) || ( ! intval ( get_config ( 'system' , 'cache_images' , 1 )))) {
// if caching is prevented for whatever reason, proxy any non-SSL photos
2020-03-05 04:07:26 +00:00
if ( strpos ( z_root (), 'https:' ) === false ) {
return $s ;
}
// we'll only sslify img tags because media files will probably choke.
$pattern = " / \ <img(.*?)src= \" (http \ :.*?) \" (.*?) \ >/ " ;
$matches = null ;
$cnt = preg_match_all ( $pattern , $s , $matches , PREG_SET_ORDER );
if ( $cnt ) {
foreach ( $matches as $match ) {
$filename = basename ( parse_url ( $match [ 2 ], PHP_URL_PATH ) );
$s = str_replace ( $match [ 2 ], z_root () . '/sslify/' . $filename . '?f=&url=' . urlencode ( $match [ 2 ]), $s );
}
}
return $s ;
}
2020-03-05 02:55:25 +00:00
$pattern = " / \ <img(.*?)src= \" (https? \ :.*?) \" (.*?) \ >/ism " ;
2020-03-05 19:50:28 +00:00
2013-12-25 10:45:22 +00:00
$matches = null ;
2015-10-28 23:58:13 +00:00
$cnt = preg_match_all ( $pattern , $s , $matches , PREG_SET_ORDER );
2015-03-21 23:06:08 +00:00
if ( $cnt ) {
foreach ( $matches as $match ) {
2020-03-05 23:48:18 +00:00
// For access controlled photos using OpenWebAuth, remove any zid attributes.
// This will cache a publicly available image but will not cache a protected one.
$clean = strip_zids ( strip_query_param ( $match [ 2 ], 'f' ));
$cached = Img_cache :: check ( $clean , 'cache/img' );
2020-03-05 02:55:25 +00:00
if ( $cached ) {
2020-04-30 00:35:55 +00:00
// $file = Img_cache::get_filename($clean,'cache/img');
// @fixme getimagesize and replace height/width/alt in image tag
2020-03-05 23:48:18 +00:00
$s = str_replace ( $match [ 2 ], z_root () . '/ca/' . basename ( Img_cache :: get_filename ( $clean , 'cache/img' )) . '?url=' . urlencode ( $clean ), $s );
2020-03-05 02:55:25 +00:00
}
2013-12-25 10:45:22 +00:00
}
}
2015-03-21 23:06:08 +00:00
2013-12-25 10:45:22 +00:00
return $s ;
}
2021-04-21 02:33:06 +00:00
// clean out the image cache
function uncache ( $s ) {
$pattern = " / \ <img(.*?)src= \" (https? \ :.*?) \" (.*?) \ >/ism " ;
$matches = null ;
$cnt = preg_match_all ( $pattern , $s , $matches , PREG_SET_ORDER );
if ( $cnt ) {
foreach ( $matches as $match ) {
// repeat the filename generation procedure we used when creating the cache entry
$clean = strip_zids ( strip_query_param ( $match [ 2 ], 'f' ));
$file = Img_cache :: get_filename ( $clean , 'cache/img' );
if ( file_exists ( $file )) {
unlink ( $file );
}
}
}
return $s ;
}
2017-12-23 13:42:23 +00:00
/**
* @ brief Get an array of poke verbs .
*
* @ return array
* * \e index is present tense verb
* * \e value is array containing past tense verb , translation of present , translation of past
*/
2012-07-20 01:53:26 +00:00
function get_poke_verbs () {
2017-12-23 13:42:23 +00:00
if ( get_config ( 'system' , 'poke_basic' )) {
2016-02-04 19:58:56 +00:00
$arr = array (
2017-12-23 13:42:23 +00:00
'poke' => array ( 'poked' , t ( 'poke' ), t ( 'poked' )),
2016-02-04 19:58:56 +00:00
);
2017-12-23 13:42:23 +00:00
} else {
2016-02-04 19:58:56 +00:00
$arr = array (
'poke' => array ( 'poked' , t ( 'poke' ), t ( 'poked' )),
'ping' => array ( 'pinged' , t ( 'ping' ), t ( 'pinged' )),
'prod' => array ( 'prodded' , t ( 'prod' ), t ( 'prodded' )),
'slap' => array ( 'slapped' , t ( 'slap' ), t ( 'slapped' )),
'finger' => array ( 'fingered' , t ( 'finger' ), t ( 'fingered' )),
'rebuff' => array ( 'rebuffed' , t ( 'rebuff' ), t ( 'rebuffed' )),
);
2017-12-23 13:42:23 +00:00
/**
* @ hooks poke_verbs
* * \e array associative array with another array as value
*/
2016-02-04 19:58:56 +00:00
call_hooks ( 'poke_verbs' , $arr );
}
2014-12-14 00:22:52 +00:00
2012-07-20 01:53:26 +00:00
return $arr ;
}
2011-08-01 23:51:01 +00:00
2017-12-23 13:42:23 +00:00
/**
* @ brief Get an array of mood verbs .
*
* @ return array
* * \e index is the verb
* * \e value is the translated verb
*/
2012-08-24 03:00:10 +00:00
function get_mood_verbs () {
2014-12-14 00:22:52 +00:00
2017-12-23 13:42:23 +00:00
$arr = [
2012-08-24 03:00:10 +00:00
'happy' => t ( 'happy' ),
'sad' => t ( 'sad' ),
'mellow' => t ( 'mellow' ),
'tired' => t ( 'tired' ),
'perky' => t ( 'perky' ),
'angry' => t ( 'angry' ),
2015-12-25 22:56:06 +00:00
'stupefied' => t ( 'stupefied' ),
2012-08-24 03:00:10 +00:00
'puzzled' => t ( 'puzzled' ),
'interested' => t ( 'interested' ),
'bitter' => t ( 'bitter' ),
'cheerful' => t ( 'cheerful' ),
'alive' => t ( 'alive' ),
'annoyed' => t ( 'annoyed' ),
'anxious' => t ( 'anxious' ),
'cranky' => t ( 'cranky' ),
'disturbed' => t ( 'disturbed' ),
'frustrated' => t ( 'frustrated' ),
2014-04-27 02:33:39 +00:00
'depressed' => t ( 'depressed' ),
2012-08-24 03:00:10 +00:00
'motivated' => t ( 'motivated' ),
'relaxed' => t ( 'relaxed' ),
'surprised' => t ( 'surprised' ),
2017-12-23 13:42:23 +00:00
];
2012-08-24 03:00:10 +00:00
2017-12-23 13:42:23 +00:00
/**
* @ hooks mood_verbs
* * \e array associative array with mood verbs
*/
2012-08-24 03:00:10 +00:00
call_hooks ( 'mood_verbs' , $arr );
2017-12-23 13:42:23 +00:00
2012-08-24 03:00:10 +00:00
return $arr ;
}
2016-10-01 22:41:25 +00:00
/**
* @ brief Function to list all smilies , both internal and from addons .
*
* @ return Returns array with keys 'texts' and 'icons'
*/
2017-04-25 23:36:37 +00:00
function list_smilies ( $default_only = false ) {
2016-05-25 03:49:23 +00:00
2016-10-01 22:41:25 +00:00
$texts = array (
'<3' ,
'</3' ,
':-)' ,
';-)' ,
':-(' ,
':-P' ,
':-p' ,
':-"' ,
':-"' ,
':-x' ,
':-X' ,
':-D' ,
'8-|' ,
'8-O' ,
':-O' ,
'\\o/' ,
'o.O' ,
'O.o' ,
'o_O' ,
'O_o' ,
" :'( " ,
" :-! " ,
" :-/ " ,
" :-[ " ,
2012-02-14 23:31:08 +00:00
" 8-) " ,
2016-10-01 22:41:25 +00:00
':beer' ,
':homebrew' ,
':coffee' ,
2012-02-16 23:15:28 +00:00
':facepalm' ,
2012-05-31 00:22:51 +00:00
':like' ,
2017-03-09 22:31:54 +00:00
':dislike'
2012-02-14 23:31:08 +00:00
);
$icons = array (
2016-11-07 04:31:37 +00:00
'<img class="smiley" src="' . z_root () . '/images/emoticons/smiley-heart.gif" alt="<3" />' ,
'<img class="smiley" src="' . z_root () . '/images/emoticons/smiley-brokenheart.gif" alt="</3" />' ,
'<img class="smiley" src="' . z_root () . '/images/emoticons/smiley-smile.gif" alt=":-)" />' ,
'<img class="smiley" src="' . z_root () . '/images/emoticons/smiley-wink.gif" alt=";-)" />' ,
'<img class="smiley" src="' . z_root () . '/images/emoticons/smiley-frown.gif" alt=":-(" />' ,
'<img class="smiley" src="' . z_root () . '/images/emoticons/smiley-tongue-out.gif" alt=":-P" />' ,
'<img class="smiley" src="' . z_root () . '/images/emoticons/smiley-tongue-out.gif" alt=":-p" />' ,
'<img class="smiley" src="' . z_root () . '/images/emoticons/smiley-kiss.gif" alt=":-\"" />' ,
'<img class="smiley" src="' . z_root () . '/images/emoticons/smiley-kiss.gif" alt=":-\"" />' ,
'<img class="smiley" src="' . z_root () . '/images/emoticons/smiley-kiss.gif" alt=":-x" />' ,
'<img class="smiley" src="' . z_root () . '/images/emoticons/smiley-kiss.gif" alt=":-X" />' ,
'<img class="smiley" src="' . z_root () . '/images/emoticons/smiley-laughing.gif" alt=":-D" />' ,
'<img class="smiley" src="' . z_root () . '/images/emoticons/smiley-surprised.gif" alt="8-|" />' ,
'<img class="smiley" src="' . z_root () . '/images/emoticons/smiley-surprised.gif" alt="8-O" />' ,
'<img class="smiley" src="' . z_root () . '/images/emoticons/smiley-surprised.gif" alt=":-O" />' ,
'<img class="smiley" src="' . z_root () . '/images/emoticons/smiley-thumbsup.gif" alt="\\o/" />' ,
'<img class="smiley" src="' . z_root () . '/images/emoticons/smiley-Oo.gif" alt="o.O" />' ,
'<img class="smiley" src="' . z_root () . '/images/emoticons/smiley-Oo.gif" alt="O.o" />' ,
'<img class="smiley" src="' . z_root () . '/images/emoticons/smiley-Oo.gif" alt="o_O" />' ,
'<img class="smiley" src="' . z_root () . '/images/emoticons/smiley-Oo.gif" alt="O_o" />' ,
'<img class="smiley" src="' . z_root () . '/images/emoticons/smiley-cry.gif" alt=":\'(" />' ,
'<img class="smiley" src="' . z_root () . '/images/emoticons/smiley-foot-in-mouth.gif" alt=":-!" />' ,
'<img class="smiley" src="' . z_root () . '/images/emoticons/smiley-undecided.gif" alt=":-/" />' ,
'<img class="smiley" src="' . z_root () . '/images/emoticons/smiley-embarassed.gif" alt=":-[" />' ,
'<img class="smiley" src="' . z_root () . '/images/emoticons/smiley-cool.gif" alt="8-)" />' ,
'<img class="smiley" src="' . z_root () . '/images/emoticons/beer_mug.gif" alt=":beer" />' ,
'<img class="smiley" src="' . z_root () . '/images/emoticons/beer_mug.gif" alt=":homebrew" />' ,
'<img class="smiley" src="' . z_root () . '/images/emoticons/coffee.gif" alt=":coffee" />' ,
'<img class="smiley" src="' . z_root () . '/images/emoticons/smiley-facepalm.gif" alt=":facepalm" />' ,
'<img class="smiley" src="' . z_root () . '/images/emoticons/like.gif" alt=":like" />' ,
2017-03-09 22:31:54 +00:00
'<img class="smiley" src="' . z_root () . '/images/emoticons/dislike.gif" alt=":dislike" />'
2013-12-09 22:05:52 +00:00
2012-02-14 23:31:08 +00:00
);
2014-12-20 16:33:35 +00:00
$params = array ( 'texts' => $texts , 'icons' => $icons );
2017-04-25 23:36:37 +00:00
if ( $default_only )
return $params ;
2012-02-14 23:31:08 +00:00
call_hooks ( 'smilie' , $params );
2015-03-21 23:06:08 +00:00
2014-12-20 16:33:35 +00:00
return $params ;
}
2017-04-25 23:36:37 +00:00
2014-12-20 16:33:35 +00:00
/**
2015-03-21 23:06:08 +00:00
* @ brief Replaces text emoticons with graphical images .
2014-12-20 16:33:35 +00:00
*
* It is expected that this function will be called using HTML text .
* We will escape text between HTML pre and code blocks , and HTML attributes
* ( such as urls ) from being processed .
2015-03-21 23:06:08 +00:00
*
2016-10-01 22:41:25 +00:00
* At a higher level , the bbcode [ nosmile ] tag can be used to prevent this
2014-12-20 16:33:35 +00:00
* function from being executed by the prepare_text () routine when preparing
2015-03-21 23:06:08 +00:00
* bbcode source for HTML display .
2014-12-20 16:33:35 +00:00
*
2015-03-21 23:06:08 +00:00
* @ param string $s
* @ param boolean $sample ( optional ) default false
* @ return string
2014-12-20 16:33:35 +00:00
*/
function smilies ( $s , $sample = false ) {
2016-10-01 22:41:25 +00:00
if ( intval ( get_config ( 'system' , 'no_smilies' ))
2015-03-21 23:06:08 +00:00
|| ( local_channel () && intval ( get_pconfig ( local_channel (), 'system' , 'no_smilies' ))))
2014-12-20 16:33:35 +00:00
return $s ;
2015-03-21 23:06:08 +00:00
$s = preg_replace_callback ( '{<(pre|code)>.*?</\1>}ism' , 'smile_shield' , $s );
$s = preg_replace_callback ( '/<[a-z]+ .*?>/ism' , 'smile_shield' , $s );
2014-12-20 16:33:35 +00:00
2016-08-09 23:59:35 +00:00
2014-12-20 16:33:35 +00:00
$params = list_smilies ();
$params [ 'string' ] = $s ;
2011-09-12 10:21:39 +00:00
2015-03-21 23:06:08 +00:00
if ( $sample ) {
2012-02-14 23:31:08 +00:00
$s = '<div class="smiley-sample">' ;
2015-03-21 23:06:08 +00:00
for ( $x = 0 ; $x < count ( $params [ 'texts' ]); $x ++ ) {
2012-02-14 23:31:08 +00:00
$s .= '<dl><dt>' . $params [ 'texts' ][ $x ] . '</dt><dd>' . $params [ 'icons' ][ $x ] . '</dd></dl>' ;
}
2015-03-21 23:06:08 +00:00
} else {
2012-03-06 20:50:38 +00:00
$params [ 'string' ] = preg_replace_callback ( '/<(3+)/' , 'preg_heart' , $params [ 'string' ]);
2012-02-14 23:31:08 +00:00
$s = str_replace ( $params [ 'texts' ], $params [ 'icons' ], $params [ 'string' ]);
}
2012-02-21 02:06:43 +00:00
2016-08-09 23:59:35 +00:00
2014-02-02 13:52:00 +00:00
$s = preg_replace_callback ( '/<!--base64:(.*?)-->/ism' , 'smile_unshield' , $s );
2012-02-22 07:13:03 +00:00
2011-09-12 10:21:39 +00:00
return $s ;
2013-02-27 02:26:33 +00:00
}
2011-08-01 23:51:01 +00:00
2015-03-21 23:06:08 +00:00
/**
* @ brief
*
* @ param array $m
* @ return string
*/
2014-02-02 13:52:00 +00:00
function smile_shield ( $m ) {
2016-08-09 23:59:35 +00:00
return '<!--base64:' . base64special_encode ( $m [ 0 ]) . '-->' ;
2014-02-02 13:52:00 +00:00
}
2012-02-22 07:13:03 +00:00
2016-10-01 22:41:25 +00:00
function smile_unshield ( $m ) {
return base64special_decode ( $m [ 1 ]);
2012-02-22 07:13:03 +00:00
}
2015-03-21 23:06:08 +00:00
/**
* @ brief Expand < 3333 to the correct number of hearts .
*
* @ param array $x
*/
2012-03-06 20:50:38 +00:00
function preg_heart ( $x ) {
2016-05-25 03:49:23 +00:00
2015-03-21 23:06:08 +00:00
if ( strlen ( $x [ 1 ]) == 1 )
2012-03-06 20:50:38 +00:00
return $x [ 0 ];
2015-03-21 23:06:08 +00:00
2012-03-06 20:50:38 +00:00
$t = '' ;
for ( $cnt = 0 ; $cnt < strlen ( $x [ 1 ]); $cnt ++ )
2018-09-10 01:28:13 +00:00
$t .= '<img class="smiley" src="' . z_root () . '/images/emoticons/smiley-heart.gif" alt="<​3" />' ;
2015-03-21 23:06:08 +00:00
2012-03-06 20:50:38 +00:00
$r = str_replace ( $x [ 0 ], $t , $x [ 0 ]);
2015-03-21 23:06:08 +00:00
2012-03-06 20:50:38 +00:00
return $r ;
}
2012-02-22 07:13:03 +00:00
2013-02-27 02:26:33 +00:00
2011-08-01 23:51:01 +00:00
function day_translate ( $s ) {
$ret = str_replace ( array ( 'Monday' , 'Tuesday' , 'Wednesday' , 'Thursday' , 'Friday' , 'Saturday' , 'Sunday' ),
array ( t ( 'Monday' ), t ( 'Tuesday' ), t ( 'Wednesday' ), t ( 'Thursday' ), t ( 'Friday' ), t ( 'Saturday' ), t ( 'Sunday' )),
$s );
$ret = str_replace ( array ( 'January' , 'February' , 'March' , 'April' , 'May' , 'June' , 'July' , 'August' , 'September' , 'October' , 'November' , 'December' ),
array ( t ( 'January' ), t ( 'February' ), t ( 'March' ), t ( 'April' ), t ( 'May' ), t ( 'June' ), t ( 'July' ), t ( 'August' ), t ( 'September' ), t ( 'October' ), t ( 'November' ), t ( 'December' )),
$ret );
return $ret ;
2013-02-27 02:26:33 +00:00
}
2015-03-21 23:06:08 +00:00
/**
* @ brief normalises a string .
*
* @ param string $url
* @ return string
*/
2011-08-01 23:51:01 +00:00
function normalise_link ( $url ) {
2015-03-21 23:06:08 +00:00
$ret = str_replace ( array ( 'https:' , '//www.' ), array ( 'http:' , '//' ), $url );
return ( rtrim ( $ret , '/' ));
2013-02-27 02:26:33 +00:00
}
2011-08-01 23:51:01 +00:00
/**
2015-03-21 23:06:08 +00:00
* @ brief Compare two URLs to see if they are the same .
2011-08-01 23:51:01 +00:00
*
2015-03-21 23:06:08 +00:00
* But ignore slight but hopefully insignificant differences such as if one
* is https and the other isn ' t , or if one is www . something and the other
* isn ' t - and also ignore case differences .
2011-08-01 23:51:01 +00:00
*
2016-06-23 12:18:58 +00:00
* @ see normalise_link ()
2011-08-01 23:51:01 +00:00
*
2015-03-21 23:06:08 +00:00
* @ param string $a
* @ param string $b
* @ return true if the URLs match , otherwise false
2011-08-01 23:51:01 +00:00
*/
2015-03-21 23:06:08 +00:00
function link_compare ( $a , $b ) {
if ( strcasecmp ( normalise_link ( $a ), normalise_link ( $b )) === 0 )
2011-08-01 23:51:01 +00:00
return true ;
2014-12-14 00:22:52 +00:00
2011-08-01 23:51:01 +00:00
return false ;
2013-02-27 02:26:33 +00:00
}
2011-08-01 23:51:01 +00:00
2011-08-04 04:05:39 +00:00
// Given an item array, convert the body element from bbcode to html and add smilie icons.
// If attach is true, also add icons for item attachments
2011-08-01 23:51:01 +00:00
2013-09-17 05:51:39 +00:00
function unobscure ( & $item ) {
2017-04-21 03:19:15 +00:00
return ;
2013-09-17 05:51:39 +00:00
}
2015-04-19 20:41:12 +00:00
function unobscure_mail ( & $item ) {
2015-06-24 04:01:59 +00:00
if ( array_key_exists ( 'mail_obscured' , $item ) && intval ( $item [ 'mail_obscured' ])) {
2015-04-19 20:41:12 +00:00
if ( $item [ 'title' ])
2015-05-20 04:51:48 +00:00
$item [ 'title' ] = base64url_decode ( str_rot47 ( $item [ 'title' ]));
2015-04-19 20:41:12 +00:00
if ( $item [ 'body' ])
2015-05-20 04:51:48 +00:00
$item [ 'body' ] = base64url_decode ( str_rot47 ( $item [ 'body' ]));
2015-04-19 20:41:12 +00:00
}
}
2013-10-14 04:14:04 +00:00
function theme_attachments ( & $item ) {
2013-07-29 04:04:03 +00:00
2021-03-12 00:03:45 +00:00
$s = EMPTY_STR ;
2016-07-14 05:11:06 +00:00
$arr = json_decode ( $item [ 'attach' ], true );
2018-05-19 09:04:34 +00:00
2020-02-21 03:56:37 +00:00
if ( is_array ( $arr ) && count ( $arr )) {
2021-03-15 05:10:44 +00:00
$attaches = [];
2020-02-21 03:56:37 +00:00
foreach ( $arr as $r ) {
2013-02-01 08:49:07 +00:00
2020-02-21 03:56:37 +00:00
$label = EMPTY_STR ;
2015-10-14 20:14:19 +00:00
$icon = getIconFromType ( $r [ 'type' ]);
2018-05-19 09:04:34 +00:00
2021-03-11 23:05:16 +00:00
if ( isset ( $r [ 'title' ]) && $r [ 'title' ]) {
2018-05-19 09:04:34 +00:00
$label = urldecode ( htmlspecialchars ( $r [ 'title' ], ENT_COMPAT , 'UTF-8' ));
2020-02-21 03:56:37 +00:00
}
2018-05-19 09:04:34 +00:00
2021-04-06 23:20:10 +00:00
if ( isset ( $r [ 'name' ]) && $r [ 'name' ]) {
$label = urldecode ( htmlspecialchars ( $r [ 'name' ], ENT_COMPAT , 'UTF-8' ));
}
2020-02-21 03:56:37 +00:00
if ( ! $label ) {
2021-04-06 23:20:10 +00:00
if ( isset ( $r [ 'href' ]) && $r [ 'href' ]) {
2020-02-21 03:56:37 +00:00
$m = parse_url ( $r [ 'href' ]);
if ( $m && $m [ 'path' ]) {
$label = basename ( $m [ 'path' ]);
}
}
}
2016-10-01 22:41:25 +00:00
2020-02-21 03:56:37 +00:00
// some feeds provide an attachment where title is an empty space
if ( ! trim ( $label )) {
2015-10-15 14:07:13 +00:00
$label = t ( 'Unknown Attachment' );
2020-02-21 03:56:37 +00:00
}
2016-10-01 22:41:25 +00:00
2021-03-11 23:05:16 +00:00
$title = t ( 'Size' ) . ' ' . (( isset ( $r [ 'length' ]) && $r [ 'length' ]) ? userReadableSize ( $r [ 'length' ]) : t ( 'unknown' ));
2013-02-01 08:49:07 +00:00
2021-04-06 23:20:10 +00:00
if ( ! ( isset ( $r [ 'href' ]))) {
continue ;
}
2020-02-21 03:56:37 +00:00
if ( is_foreigner ( $item [ 'author_xchan' ])) {
2014-09-23 06:49:12 +00:00
$url = $r [ 'href' ];
2020-02-21 03:56:37 +00:00
}
else {
2021-03-11 23:05:16 +00:00
$url = z_root () . '/magic?f=&owa=1&hash=' . $item [ 'author_xchan' ] . '&bdest=' . bin2hex ( $r [ 'href' ] . (( isset ( $r [ 'revision' ]) ? '/' . $r [ 'revision' ] : '' )));
2020-02-21 03:56:37 +00:00
}
$attaches [] = [
'label' => $label ,
'url' => $url ,
'icon' => $icon ,
'title' => $title
];
2011-08-01 23:51:01 +00:00
}
2013-10-14 04:14:04 +00:00
2020-02-21 03:56:37 +00:00
$s = replace_macros ( get_markup_template ( 'item_attach.tpl' ), [
'$attaches' => $attaches
]);
2015-10-14 20:14:19 +00:00
}
2013-10-14 04:14:04 +00:00
return $s ;
}
2013-10-14 11:49:28 +00:00
function format_categories ( & $item , $writeable ) {
2021-03-12 00:03:45 +00:00
$s = EMPTY_STR ;
if ( ! ( isset ( $item [ 'term' ]) && $item [ 'term' ])) {
return $s ;
}
2014-12-14 00:22:52 +00:00
2013-10-14 11:49:28 +00:00
$terms = get_terms_oftype ( $item [ 'term' ], TERM_CATEGORY );
if ( $terms ) {
2021-03-15 05:10:44 +00:00
$categories = [];
2013-10-14 11:49:28 +00:00
foreach ( $terms as $t ) {
2013-12-13 20:30:44 +00:00
$term = htmlspecialchars ( $t [ 'term' ], ENT_COMPAT , 'UTF-8' , false ) ;
2013-10-14 22:34:47 +00:00
if ( ! trim ( $term ))
continue ;
2013-10-14 11:49:28 +00:00
$removelink = (( $writeable ) ? z_root () . '/filerm/' . $item [ 'id' ] . '?f=&cat=' . urlencode ( $t [ 'term' ]) : '' );
2013-12-02 23:15:02 +00:00
$categories [] = array ( 'term' => $term , 'writeable' => $writeable , 'removelink' => $removelink , 'url' => zid ( $t [ 'url' ]));
2013-10-14 11:49:28 +00:00
}
2015-10-14 20:14:19 +00:00
$s = replace_macros ( get_markup_template ( 'item_categories.tpl' ), array (
'$remove' => t ( 'remove category' ),
'$categories' => $categories
));
2013-10-14 11:49:28 +00:00
}
2014-12-14 00:22:52 +00:00
2013-10-14 11:49:28 +00:00
return $s ;
}
2015-04-06 21:51:30 +00:00
/**
* @ brief Add any hashtags which weren ' t mentioned in the message body , e . g . community tags
*
* @ param [ in ] array & $item
* @ return string HTML link of hashtag
*/
2015-10-14 20:14:19 +00:00
2014-04-01 00:03:07 +00:00
function format_hashtags ( & $item ) {
$s = '' ;
2015-04-06 21:51:30 +00:00
2021-03-11 23:05:16 +00:00
if ( ! isset ( $item [ 'term' ])) {
return $s ;
}
2015-11-20 08:15:48 +00:00
$terms = get_terms_oftype ( $item [ 'term' ], array ( TERM_HASHTAG , TERM_COMMUNITYTAG ));
2014-04-01 00:03:07 +00:00
if ( $terms ) {
foreach ( $terms as $t ) {
2015-04-06 21:51:30 +00:00
$term = htmlspecialchars ( $t [ 'term' ], ENT_COMPAT , 'UTF-8' , false ) ;
2014-04-01 00:03:07 +00:00
if ( ! trim ( $term ))
continue ;
2020-11-04 23:02:01 +00:00
// Pleroma uses example.com/tags/xxx in the taglist but example.com/tag/xxx in the body. Possibly a bug because one of these leads to
// an error page, but it messes up our detection of whether the tag was already present in the body.
if ( $t [ 'url' ] && (( stripos ( $item [ 'body' ], $t [ 'url' ]) !== false ) || ( stripos ( $item [ 'body' ], str_replace ( '/tags/' , '/tag/' , $t [ 'url' ]))))) {
2014-04-01 00:03:07 +00:00
continue ;
2020-11-04 23:02:01 +00:00
}
2014-04-01 00:03:07 +00:00
if ( $s )
2017-03-15 20:22:16 +00:00
$s .= ' ' ;
2014-04-01 00:03:07 +00:00
2017-03-15 20:22:16 +00:00
$s .= '<span class="badge badge-pill badge-info"><i class="fa fa-hashtag"></i> <a class="text-white" href="' . zid ( $t [ 'url' ]) . '" >' . $term . '</a></span>' ;
2014-04-01 00:03:07 +00:00
}
}
2015-04-06 21:51:30 +00:00
2014-04-01 00:03:07 +00:00
return $s ;
}
2014-07-01 05:46:17 +00:00
function format_mentions ( & $item ) {
2021-03-12 00:03:45 +00:00
$s = EMPTY_STR ;
2014-12-14 00:22:52 +00:00
2020-11-04 23:02:01 +00:00
$pref = intval ( PConfig :: Get ( $item [ 'uid' ], 'system' , 'tag_username' , Config :: Get ( 'system' , 'tag_username' , false )));
// hide "auto mentions" by default - this hidden pref let's you display them.
$show = intval ( PConfig :: Get ( $item [ 'uid' ], 'system' , 'show_auto_mentions' , false ));
if (( ! $show ) && ( ! $item [ 'resource_type' ])) {
2021-03-12 00:03:45 +00:00
return $s ;
2020-11-04 23:02:01 +00:00
}
if ( $pref === 127 ) {
2021-03-12 00:03:45 +00:00
return $s ;
2020-11-04 23:02:01 +00:00
}
2021-03-12 00:03:45 +00:00
if ( ! ( isset ( $item [ 'term' ]) && is_array ( $item [ 'term' ]) && $item [ 'term' ])) {
return $s ;
}
2014-07-01 05:46:17 +00:00
$terms = get_terms_oftype ( $item [ 'term' ], TERM_MENTION );
if ( $terms ) {
foreach ( $terms as $t ) {
2020-11-04 23:02:01 +00:00
2014-07-01 05:46:17 +00:00
$term = htmlspecialchars ( $t [ 'term' ], ENT_COMPAT , 'UTF-8' , false ) ;
if ( ! trim ( $term ))
continue ;
2020-11-04 23:02:01 +00:00
if ( $t [ 'url' ] && stripos ( $item [ 'body' ], $t [ 'url' ]) !== false )
2014-07-01 05:46:17 +00:00
continue ;
2020-11-04 23:02:01 +00:00
// some platforms put the identity url into href rather than the profile url. Accept either form.
$x = q ( " select * from xchan where xchan_url = '%s' or xchan_hash = '%s' limit 1 " ,
dbesc ( $t [ 'url' ]),
dbesc ( $t [ 'url' ])
);
if ( $x ) {
switch ( $pref ) {
case 0 :
$txt = $x [ 0 ][ 'xchan_name' ];
break ;
case 1 :
$txt = (( $x [ 0 ][ 'xchan_addr' ]) ? $x [ 0 ][ 'xchan_addr' ] : $x [ 0 ][ 'xchan_name' ]);
break ;
case 2 :
default ;
if ( $x [ 0 ][ 'xchan_addr' ]) {
$txt = sprintf ( t ( '%1$s (%2$s)' ), $x [ 0 ][ 'xchan_name' ], $x [ 0 ][ 'xchan_addr' ]);
}
else {
$txt = $x [ 0 ][ 'xchan_name' ];
}
break ;
}
}
2021-02-05 00:09:59 +00:00
if ( $s ) {
2017-03-15 20:22:16 +00:00
$s .= ' ' ;
2021-02-05 00:09:59 +00:00
}
2020-11-04 23:02:01 +00:00
$s .= '<span class="badge badge-pill badge-success"><i class="fa fa-at"></i> <a class="text-white" href="' . zid ( chanlink_url ( $t [ 'url' ])) . '" >' . $txt . '</a></span>' ;
2014-07-01 05:46:17 +00:00
}
}
2015-04-06 21:51:30 +00:00
2014-07-01 05:46:17 +00:00
return $s ;
}
2014-04-01 00:03:07 +00:00
2013-10-14 11:49:28 +00:00
function format_filer ( & $item ) {
2021-03-12 00:03:45 +00:00
$s = EMPTY_STR ;
if ( ! ( isset ( $item [ 'term' ]) && $item [ 'term' ])) {
return $s ;
}
2014-12-14 00:22:52 +00:00
2013-10-14 11:49:28 +00:00
$terms = get_terms_oftype ( $item [ 'term' ], TERM_FILE );
if ( $terms ) {
2021-03-15 05:10:44 +00:00
$categories = [];
2013-10-14 11:49:28 +00:00
foreach ( $terms as $t ) {
2013-12-13 20:30:44 +00:00
$term = htmlspecialchars ( $t [ 'term' ], ENT_COMPAT , 'UTF-8' , false ) ;
2013-10-14 22:34:47 +00:00
if ( ! trim ( $term ))
continue ;
2013-10-14 11:49:28 +00:00
$removelink = z_root () . '/filerm/' . $item [ 'id' ] . '?f=&term=' . urlencode ( $t [ 'term' ]);
$categories [] = array ( 'term' => $term , 'removelink' => $removelink );
}
2015-10-14 20:14:19 +00:00
$s = replace_macros ( get_markup_template ( 'item_filer.tpl' ), array (
'$remove' => t ( 'remove from file' ),
'$categories' => $categories
));
2013-10-14 11:49:28 +00:00
}
2014-12-14 00:22:52 +00:00
2013-10-14 11:49:28 +00:00
return $s ;
}
2014-12-16 23:50:20 +00:00
function generate_map ( $coord ) {
2020-09-23 01:08:50 +00:00
$coord = str_replace ( array ( ',' , '/' , ' ' ), array ( ' ' , ' ' , ' ' ), trim ( $coord ));
2021-04-01 21:39:18 +00:00
$zoom = (( strpos ( $coord , '?z=' ) !== false ) ? substr ( $coord , strpos ( $coord , '?z=' ) + 3 ) : 0 );
2020-09-23 01:08:50 +00:00
if ( $zoom ) {
$coord = substr ( $coord , 0 , strpos ( $coord , '?' ));
}
2021-04-01 21:39:18 +00:00
else {
$zoom = 16 ;
}
2017-12-23 13:42:23 +00:00
$arr = [
2019-07-23 01:38:22 +00:00
'lat' => trim ( substr ( $coord , 0 , strpos ( $coord , ' ' ))),
'lon' => trim ( substr ( $coord , strpos ( $coord , ' ' ) + 1 )),
2020-09-23 01:08:50 +00:00
'zoom' => $zoom ,
2019-07-23 01:38:22 +00:00
'html' => ''
2017-12-23 13:42:23 +00:00
];
/**
* @ hooks generate_map
* * \e string \b lat
* * \e string \b lon
* * \e string \b html the parsed HTML to return
*/
call_hooks ( 'generate_map' , $arr );
2015-03-25 22:32:49 +00:00
return (( $arr [ 'html' ]) ? $arr [ 'html' ] : $coord );
2014-12-16 23:50:20 +00:00
}
2014-12-17 22:12:19 +00:00
function generate_named_map ( $location ) {
2017-12-23 13:42:23 +00:00
$arr = [
2019-07-23 01:38:22 +00:00
'location' => $location ,
'html' => ''
2017-12-23 13:42:23 +00:00
];
/**
* @ hooks generate_named_map
* * \e string \b location
* * \e string \b html the parsed HTML to return
*/
call_hooks ( 'generate_named_map' , $arr );
2015-03-25 22:32:49 +00:00
return (( $arr [ 'html' ]) ? $arr [ 'html' ] : $location );
2014-12-17 22:12:19 +00:00
}
2013-10-14 11:49:28 +00:00
2018-04-04 23:33:11 +00:00
function prepare_body ( & $item , $attach = false , $opts = false ) {
2013-10-14 04:14:04 +00:00
2016-10-01 22:41:25 +00:00
call_hooks ( 'prepare_body_init' , $item );
2013-10-14 04:14:04 +00:00
2019-10-18 01:09:40 +00:00
$censored = ((( $item [ 'author' ][ 'abook_censor' ] || $item [ 'owner' ][ 'abook_censor' ] || $item [ 'author' ][ 'xchan_selfcensored' ] || $item [ 'owner' ][ 'xchan_selfcensored' ] || $item [ 'author' ][ 'xchan_censored' ] || $item [ 'owner' ][ 'xchan_censored' ] || intval ( $item [ 'item_nsfw' ])) && ( get_safemode ()))
2019-08-01 04:46:19 +00:00
? true
: false
2019-07-31 00:56:35 +00:00
);
2019-08-01 01:15:38 +00:00
if ( $censored ) {
if ( ! $opts ) {
$opts = [];
}
$opts [ 'censored' ] = true ;
}
2019-07-31 00:56:35 +00:00
2016-02-26 14:21:14 +00:00
$s = '' ;
2015-10-22 09:37:34 +00:00
$photo = '' ;
2019-07-31 00:56:35 +00:00
2015-12-15 23:01:54 +00:00
$is_photo = ((( $item [ 'verb' ] === ACTIVITY_POST ) && ( $item [ 'obj_type' ] === ACTIVITY_OBJ_PHOTO )) ? true : false );
2015-10-22 09:37:34 +00:00
2019-08-26 00:35:14 +00:00
if ( $is_photo && ! $censored ) {
2015-12-15 23:01:54 +00:00
2016-06-03 22:09:58 +00:00
$object = json_decode ( $item [ 'obj' ], true );
2019-08-26 00:35:14 +00:00
$ptr = null ;
2021-06-07 21:09:30 +00:00
if ( is_array ( $object ) && array_key_exists ( 'url' , $object ) && is_array ( $object [ 'url' ])) {
2019-08-26 00:35:14 +00:00
if ( array_key_exists ( 0 , $object [ 'url' ])) {
foreach ( $object [ 'url' ] as $link ) {
if ( array_key_exists ( 'width' , $link ) && $link [ 'width' ] >= 640 && $link [ 'width' ] <= 1024 ) {
$ptr = $link ;
}
}
if ( ! $ptr ) {
$ptr = $object [ 'url' ][ 0 ];
}
2018-10-29 04:01:58 +00:00
}
2019-08-26 00:35:14 +00:00
else {
$ptr = $object [ 'url' ];
2019-08-01 05:51:33 +00:00
}
2019-08-26 00:35:14 +00:00
// if original photo width is > 640px make it a cover photo
if ( $ptr ) {
2021-06-22 05:03:11 +00:00
$alt_text = ' alt="' . (( isset ( $ptr [ 'summary' ]) && $ptr [ 'summary' ]) ? htmlspecialchars ( $ptr [ 'summary' ], ENT_QUOTES , 'UTF-8' ) : t ( 'Image/photo' )) . '"' ;
$title_text = ' title="' . (( isset ( $ptr [ 'summary' ]) && $ptr [ 'summary' ]) ? htmlspecialchars ( $ptr [ 'summary' ], ENT_QUOTES , 'UTF-8' ) : t ( 'Image/photo' )) . '"' ;
2019-08-26 00:35:14 +00:00
if ( array_key_exists ( 'width' , $ptr ) && $ptr [ 'width' ] > 640 ) {
2021-06-22 05:03:11 +00:00
$photo = '<a href="' . zid ( rawurldecode ( $object [ 'id' ])) . '"' . $title_text . ' target="_blank" rel="nofollow noopener"><img style="max-width:' . $ptr [ 'width' ] . 'px; width:100%; height:auto;" src="' . zid ( rawurldecode ( $ptr [ 'href' ])) . '"' . $alt_text . '></a>' ;
2019-08-26 00:35:14 +00:00
}
else {
2021-06-22 05:03:11 +00:00
$item [ 'body' ] = '[zmg' . $alt_text . ']' . $ptr [ 'href' ] . '[/zmg]' . " \n \n " . $item [ 'body' ];
2019-08-26 00:35:14 +00:00
}
}
2015-10-25 17:01:44 +00:00
}
2015-10-22 08:52:10 +00:00
}
2017-04-19 04:18:49 +00:00
if ( $item [ 'item_obscured' ]) {
$s .= prepare_binary ( $item );
}
else {
2018-08-16 01:56:18 +00:00
if ( $item [ 'summary' ]) {
2020-10-22 22:28:13 +00:00
// 8203 is a zero-width space so as not to trigger a markdown link if the summary starts with parentheses
2020-11-23 23:09:50 +00:00
$s .= prepare_text ( '[summary]​' . $item [ 'summary' ] . '[/summary]​' . $item [ 'body' ], $item [ 'mimetype' ], $opts );
2018-08-16 01:56:18 +00:00
}
else {
2020-03-25 20:05:56 +00:00
if ( $item [ 'html' ]) {
$s .= smilies ( $item [ 'html' ]);
}
else {
$s .= prepare_text ( $item [ 'body' ], $item [ 'mimetype' ], $opts );
}
2018-08-16 01:56:18 +00:00
}
2017-04-19 04:18:49 +00:00
}
2015-12-15 23:01:54 +00:00
2020-01-22 04:54:05 +00:00
$poll = (( $item [ 'obj_type' ] === 'Question' && in_array ( $item [ 'verb' ],[ 'Create' , 'Update' ])) ? format_poll ( $item , $s , $opts ) : false );
if ( $poll ) {
$s = $poll ;
}
2019-07-31 00:56:35 +00:00
2020-07-28 03:26:12 +00:00
$e = trim ( $item [ 'body' ]);
$em = Emoji\is_single_emoji ( $e ) || mb_strlen ( $e ) === 1 ;
2020-02-05 01:01:11 +00:00
if ( $em ) {
$s = '<span style="font-size: 2rem;">' . trim ( $item [ 'body' ]) . '</span>' ;
2020-02-04 03:55:52 +00:00
}
2016-06-02 04:48:54 +00:00
$event = (( $item [ 'obj_type' ] === ACTIVITY_OBJ_EVENT ) ? format_event_obj ( $item [ 'obj' ]) : false );
2015-11-26 11:26:27 +00:00
2019-06-13 03:57:28 +00:00
// This is not the most pleasant UI element possible, but this is difficult to add to one of the templates.
// Eventually we may wish to add/remove to/from calendar in the message title area but it will take a chunk
// of code re-factoring to make that happen.
2021-03-11 05:31:13 +00:00
if ( is_array ( $event ) && $event [ 'header' ] && $item [ 'resource_id' ]) {
2019-07-31 00:56:35 +00:00
$event [ 'header' ] .= '<i class="fa fa-asterisk" title="' . t ( 'Added to your calendar' ) . '"></i>' . ' ' . t ( 'Added to your calendar' );
2019-06-12 05:12:25 +00:00
}
2015-10-22 08:52:10 +00:00
$prep_arr = array (
'item' => $item ,
2015-11-26 21:14:20 +00:00
'html' => $event ? $event [ 'content' ] : $s ,
2021-03-11 05:31:13 +00:00
'event' => (( is_array ( $event )) ? $event [ 'header' ] : EMPTY_STR ),
2015-10-22 08:52:10 +00:00
'photo' => $photo
);
2013-10-14 04:14:04 +00:00
call_hooks ( 'prepare_body' , $prep_arr );
2015-10-22 08:52:10 +00:00
2013-10-14 04:14:04 +00:00
$s = $prep_arr [ 'html' ];
2015-10-22 08:52:10 +00:00
$photo = $prep_arr [ 'photo' ];
2015-11-26 11:26:27 +00:00
$event = $prep_arr [ 'event' ];
2013-10-14 04:14:04 +00:00
if ( ! $attach ) {
return $s ;
2011-08-01 23:51:01 +00:00
}
2012-07-10 05:08:25 +00:00
2014-12-16 23:50:20 +00:00
if ( strpos ( $s , '<div class="map">' ) !== false && $item [ 'coord' ]) {
$x = generate_map ( trim ( $item [ 'coord' ]));
if ( $x ) {
$s = preg_replace ( '/\<div class\=\"map\"\>/' , '$0' . $x , $s );
}
2015-10-22 08:52:10 +00:00
}
2014-12-16 23:50:20 +00:00
2015-10-14 20:14:19 +00:00
$attachments = theme_attachments ( $item );
2013-10-14 04:14:04 +00:00
2014-12-14 00:22:52 +00:00
$writeable = (( get_observer_hash () == $item [ 'owner_xchan' ]) ? true : false );
2014-04-01 00:03:07 +00:00
2015-10-14 20:14:19 +00:00
$tags = format_hashtags ( $item );
2014-04-01 00:03:07 +00:00
2020-11-04 23:02:01 +00:00
$mentions = format_mentions ( $item );
2014-07-01 05:46:17 +00:00
2015-10-14 20:14:19 +00:00
$categories = format_categories ( $item , $writeable );
2012-03-13 11:04:26 +00:00
2015-01-29 04:56:04 +00:00
if ( local_channel () == $item [ 'uid' ])
2015-10-14 20:14:19 +00:00
$filer = format_filer ( $item );
2011-10-24 22:47:17 +00:00
2020-08-17 04:55:59 +00:00
// Caching photos can use absurd amounts of space.
// Don't cache photos if somebody is just browsing the stream to the
// beginning of time. This optimises performance for viewing things created
// recently. Also catch an explicit expiration of 0 or "no cache".
$cache_expire = intval ( get_config ( 'system' , 'default_expire_days' ));
if ( $cache_expire <= 0 ) {
$cache_expire = 60 ;
}
$cache_enable = ((( $cache_expire ) && ( $item [ 'created' ] < datetime_convert ( 'UTC' , 'UTC' , 'now - ' . $cache_expire . ' days' ))) ? false : true );
2021-06-19 23:04:32 +00:00
// disable Unicode RTL over-ride since it can destroy presentation in some cases, use HTML or CSS instead
$s = str_replace ([ '‮' , '‮' , html_entity_decode ( '‮' , ENT_QUOTES , 'UTF-8' ) ],[ '' , '' , '' ], $s );
2021-04-21 02:33:06 +00:00
2019-01-14 00:08:26 +00:00
if ( $s )
2020-08-17 04:55:59 +00:00
$s = sslify ( $s , $cache_enable );
2019-01-14 00:08:26 +00:00
if ( $photo )
2020-08-17 04:55:59 +00:00
$photo = sslify ( $photo , $cache_enable );
2019-01-14 00:08:26 +00:00
if ( $event )
2020-08-17 04:55:59 +00:00
$event = sslify ( $event , $cache_enable );
2019-01-14 00:08:26 +00:00
2015-10-14 20:14:19 +00:00
$prep_arr = array (
2015-10-22 08:52:10 +00:00
'item' => $item ,
'photo' => $photo ,
'html' => $s ,
2015-11-26 11:26:27 +00:00
'event' => $event ,
2015-10-22 08:52:10 +00:00
'categories' => $categories ,
'folders' => $filer ,
'tags' => $tags ,
'mentions' => $mentions ,
'attachments' => $attachments
);
2015-10-14 20:14:19 +00:00
2011-10-24 22:47:17 +00:00
call_hooks ( 'prepare_body_final' , $prep_arr );
2015-10-14 20:14:19 +00:00
2015-10-22 08:52:10 +00:00
unset ( $prep_arr [ 'item' ]);
2015-10-14 20:14:19 +00:00
return $prep_arr ;
2013-02-27 02:26:33 +00:00
}
2011-08-01 23:51:01 +00:00
2019-08-01 01:15:38 +00:00
function separate_img_links ( $s ) {
$x = preg_replace ( '/\<a (.*?)\>\<img(.*?)\>\<\/a\>/ism' ,
2019-09-03 03:47:34 +00:00
'<img$2><br><a $1>' . t ( 'Link' ) . '</a><br>' , $s );
2019-09-21 01:00:29 +00:00
2019-08-01 01:15:38 +00:00
return $x ;
}
2020-01-22 04:54:05 +00:00
function format_poll ( $item , $s , $opts ) {
if ( ! is_array ( $item [ 'obj' ])) {
$act = json_decode ( $item [ 'obj' ], true );
}
else {
$act = $item [ 'obj' ];
}
2020-01-29 04:13:08 +00:00
if ( ! is_array ( $act )) {
return EMPTY_STR ;
}
2020-01-22 04:54:05 +00:00
$commentable = can_comment_on_post ((( local_channel ()) ? get_observer_hash () : EMPTY_STR ), $item );
//logger('format_poll: ' . print_r($item,true));
$activated = (( local_channel () && local_channel () == $item [ 'uid' ]) ? true : false );
$output = $s . EOL . EOL ;
2020-02-10 05:39:26 +00:00
$closed = false ;
$closing = false ;
if ( $item [ 'comments_closed' ] > NULL_DATE ) {
$closing = true ;
$t = datetime_convert ( 'UTC' , date_default_timezone_get (), $item [ 'comments_closed' ], 'Y-m-d H:i' );
$closed = (( datetime_convert () > $item [ 'comments_closed' ]) ? true : false );
if ( $closed ) {
$commentable = false ;
}
}
2020-01-22 04:54:05 +00:00
if ( $act [ 'type' ] === 'Question' ) {
if ( $activated and $commentable ) {
2020-01-27 23:54:43 +00:00
$output .= '<form id="question-form-' . $item [ 'id' ] . '" >' ;
2020-01-22 04:54:05 +00:00
}
2020-01-29 04:13:08 +00:00
if ( array_key_exists ( 'anyOf' , $act ) && is_array ( $act [ 'anyOf' ])) {
2020-01-22 04:54:05 +00:00
foreach ( $act [ 'anyOf' ] as $poll ) {
if ( array_key_exists ( 'name' , $poll ) && $poll [ 'name' ]) {
$text = html2plain ( purify_html ( $poll [ 'name' ]), 256 );
if ( array_path_exists ( 'replies/totalItems' , $poll )) {
$total = $poll [ 'replies' ][ 'totalItems' ];
}
else {
$total = 0 ;
}
if ( $activated && $commentable ) {
2020-01-27 23:54:43 +00:00
$output .= '<input type="checkbox" name="answer[]" value="' . htmlspecialchars ( $text ) . '"> ' . $text . '</input>' . ' (' . $total . ')' . EOL ;
2020-01-22 04:54:05 +00:00
}
else {
2020-10-20 23:13:30 +00:00
$output .= $text . ' (' . $total . ')' . EOL ;
2020-01-22 04:54:05 +00:00
}
}
}
}
2020-01-29 04:13:08 +00:00
if ( array_key_exists ( 'oneOf' , $act ) && is_array ( $act [ 'oneOf' ])) {
2020-09-25 07:22:20 +00:00
$totalResponses = 0 ;
foreach ( $act [ 'oneOf' ] as $poll ) {
if ( array_path_exists ( 'replies/totalItems' , $poll )) {
$totalResponses += intval ( $poll [ 'replies' ][ 'totalItems' ]);
}
}
2020-01-22 04:54:05 +00:00
foreach ( $act [ 'oneOf' ] as $poll ) {
2020-02-02 23:12:20 +00:00
if ( is_array ( $poll ) && array_key_exists ( 'name' , $poll ) && $poll [ 'name' ]) {
2020-01-22 04:54:05 +00:00
$text = html2plain ( purify_html ( $poll [ 'name' ]), 256 );
if ( array_path_exists ( 'replies/totalItems' , $poll )) {
$total = $poll [ 'replies' ][ 'totalItems' ];
}
else {
$total = 0 ;
}
if ( $activated && $commentable ) {
2020-09-25 07:22:20 +00:00
$output .= '<input type="radio" name="answer" value="' . htmlspecialchars ( $text ) . '"> ' . $text . '</input>' . ' (' . $total . ')' . (( $totalResponses ) ? ' ' . intval ( $total / $totalResponses * 100 ) . '%' : '' ) . EOL ;
2020-01-22 04:54:05 +00:00
}
else {
2020-10-20 23:13:30 +00:00
$output .= $text . ' (' . $total . ')' . (( $totalResponses ) ? ' ' . intval ( $total / $totalResponses * 100 ) . '%' : '' ) . EOL ;
2020-01-22 04:54:05 +00:00
}
2020-09-25 07:22:20 +00:00
2020-01-22 04:54:05 +00:00
}
}
}
2020-02-10 05:39:26 +00:00
if ( $closed ) {
$message = t ( 'Poll has ended.' );
}
elseif ( $closing ) {
2020-10-20 23:13:30 +00:00
$message = sprintf ( t ( 'Poll ends: %1$s (%2$s)' ), relative_date ( $t ), $t );
2020-02-10 05:39:26 +00:00
}
$output .= EOL . '<div>' . $message . '</div>' ;
2020-01-22 04:54:05 +00:00
if ( $activated and $commentable ) {
2020-03-10 05:08:11 +00:00
$output .= EOL . '<input type="button" class="btn btn-std btn-success" name="vote" value="' . t ( 'vote' ) . '" onclick="submitPoll(' . $item [ 'id' ] . '); return false;">' . '</form>' ;
2020-01-22 04:54:05 +00:00
}
2020-02-07 03:57:27 +00:00
2020-01-22 04:54:05 +00:00
}
return $output ;
}
2017-04-19 04:18:49 +00:00
function prepare_binary ( $item ) {
return replace_macros ( get_markup_template ( 'item_binary.tpl' ), [
'$download' => t ( 'Download binary/encrypted content' ),
'$url' => z_root () . '/viewsrc/' . $item [ 'id' ] . '/download'
]);
}
2015-03-21 23:06:08 +00:00
/**
* @ brief Given a text string , convert from bbcode to html and add smilie icons .
*
* @ param string $text
2017-12-23 13:42:23 +00:00
* @ param string $content_type ( optional ) default text / bbcode
2016-10-01 22:41:25 +00:00
* @ param boolean $cache ( optional ) default false
*
2015-03-21 23:06:08 +00:00
* @ return string
*/
2021-03-22 04:56:18 +00:00
function prepare_text ( $text , $content_type = 'text/x-multicode' , $opts = false ) {
2018-04-04 23:33:11 +00:00
2011-08-01 23:51:01 +00:00
2013-03-21 23:14:08 +00:00
switch ( $content_type ) {
case 'text/plain' :
$s = escape_tags ( $text );
break ;
case 'text/html' :
$s = $text ;
break ;
case 'text/markdown' :
2018-07-03 23:40:54 +00:00
$text = MarkdownSoap :: unescape ( $text );
2017-02-25 18:12:41 +00:00
$s = MarkdownExtra :: defaultTransform ( $text );
2013-03-21 23:14:08 +00:00
break ;
2015-11-13 01:47:38 +00:00
case 'application/x-pdl' ;
$s = escape_tags ( $text );
break ;
2016-10-01 22:41:25 +00:00
// No security checking is done here at display time - so we need to verify
// that the author is allowed to use PHP before storing. We also cannot allow
// importation of PHP text bodies from other sites. Therefore this content
2013-08-11 23:56:06 +00:00
// type is only valid for web pages (and profile details).
2016-10-01 22:41:25 +00:00
// It may be possible to provide a PHP message body which is evaluated on the
// sender's site before sending it elsewhere. In that case we will have a
// different content-type here.
2013-08-11 23:56:06 +00:00
case 'application/x-php' :
ob_start ();
eval ( $text );
$s = ob_get_contents ();
ob_end_clean ();
break ;
2013-03-21 23:14:08 +00:00
case 'text/bbcode' :
2021-03-08 05:32:28 +00:00
case 'text/x-multicode' :
2013-03-21 23:14:08 +00:00
case '' :
default :
require_once ( 'include/bbcode.php' );
if ( stristr ( $text , '[nosmile]' ))
2017-11-23 23:21:50 +00:00
$s = bbcode ( $text , [ 'cache' => $cache ]);
2013-03-21 23:14:08 +00:00
else
2018-04-04 23:33:11 +00:00
$s = smilies ( bbcode ( $text , (( is_array ( $opts )) ? $opts : [] )));
2016-08-09 23:59:35 +00:00
2013-04-15 03:41:58 +00:00
$s = zidify_links ( $s );
2016-08-09 23:59:35 +00:00
2013-03-21 23:14:08 +00:00
break ;
}
2013-09-02 23:37:54 +00:00
//logger('prepare_text: ' . $s);
2011-08-01 23:51:01 +00:00
return $s ;
2013-02-27 02:26:33 +00:00
}
2011-08-01 23:51:01 +00:00
2015-12-15 23:01:54 +00:00
function create_export_photo_body ( & $item ) {
if (( $item [ 'verb' ] === ACTIVITY_POST ) && ( $item [ 'obj_type' ] === ACTIVITY_OBJ_PHOTO )) {
2016-06-23 12:18:58 +00:00
$j = json_decode ( $item [ 'obj' ], true );
2015-12-15 23:01:54 +00:00
if ( $j ) {
2018-10-29 04:01:58 +00:00
$item [ 'body' ] .= " \n \n " . (( $j [ 'source' ][ 'content' ]) ? $j [ 'source' ][ 'content' ] : $item [ 'content' ]);
2015-12-15 23:01:54 +00:00
$item [ 'sig' ] = '' ;
}
}
}
2011-08-01 23:51:01 +00:00
2014-01-10 00:23:58 +00:00
function get_plink ( $item , $conversation_mode = true ) {
if ( $conversation_mode )
2013-10-21 03:29:52 +00:00
$key = 'plink' ;
else
$key = 'llink' ;
2014-12-14 00:22:52 +00:00
2017-12-16 23:14:28 +00:00
$zidify = true ;
2017-12-16 23:10:43 +00:00
2018-09-14 05:39:05 +00:00
if ( array_key_exists ( 'author' , $item ) && $item [ 'author' ][ 'xchan_network' ] !== 'zot6' )
2017-12-16 23:14:28 +00:00
$zidify = false ;
2017-12-16 23:10:43 +00:00
2013-11-10 22:15:57 +00:00
if ( x ( $item , $key )) {
2019-07-23 01:38:22 +00:00
return [
2017-12-16 23:10:43 +00:00
'href' => (( $zidify ) ? zid ( $item [ $key ]) : $item [ $key ]),
2014-05-30 04:34:08 +00:00
'title' => t ( 'Link to Source' ),
2019-07-23 01:38:22 +00:00
];
2014-12-14 00:22:52 +00:00
}
2012-06-29 00:43:29 +00:00
else {
2011-09-16 10:51:14 +00:00
return false ;
}
2013-02-27 02:26:33 +00:00
}
2011-08-01 23:51:01 +00:00
2013-09-03 03:25:33 +00:00
function layout_select ( $channel_id , $current = '' ) {
2016-10-01 22:41:25 +00:00
$r = q ( " select mid, v from item left join iconfig on iconfig.iid = item.id
2016-06-14 04:16:36 +00:00
where iconfig . cat = 'system' and iconfig . k = 'PDL' and item . uid = % d and item_type = % d " ,
2013-09-03 03:25:33 +00:00
intval ( $channel_id ),
2015-01-29 22:51:41 +00:00
intval ( ITEM_TYPE_PDL )
2013-09-03 03:25:33 +00:00
);
2015-04-14 09:50:21 +00:00
2013-09-03 03:25:33 +00:00
if ( $r ) {
2015-04-14 09:50:21 +00:00
$empty_selected = (( $current === false ) ? ' selected="selected" ' : '' );
$options .= '<option value="" ' . $empty_selected . '>' . t ( 'default' ) . '</option>' ;
2013-09-03 03:25:33 +00:00
foreach ( $r as $rr ) {
$selected = (( $rr [ 'mid' ] == $current ) ? ' selected="selected" ' : '' );
2016-06-14 02:58:24 +00:00
$options .= '<option value="' . $rr [ 'mid' ] . '"' . $selected . '>' . $rr [ 'v' ] . '</option>' ;
2013-09-03 03:25:33 +00:00
}
}
2015-04-14 09:50:21 +00:00
$o = replace_macros ( get_markup_template ( 'field_select_raw.tpl' ), array (
'$field' => array ( 'layout_mid' , t ( 'Page layout' ), $selected , t ( 'You can create your own with the layouts tool' ), $options )
));
2013-09-03 03:25:33 +00:00
return $o ;
}
2021-03-22 04:56:18 +00:00
function mimetype_select ( $channel_id , $current = 'text/x-multicode' , $choices = null , $element = 'mimetype' ) {
2013-09-02 08:38:17 +00:00
2017-09-13 05:32:31 +00:00
$x = (( $choices ) ? $choices : [
2017-09-20 06:30:52 +00:00
'text/bbcode' => t ( 'BBcode' ),
2021-03-22 04:56:18 +00:00
'text/x-multicode' => t ( 'Multicode' ),
2017-09-20 06:30:52 +00:00
'text/html' => t ( 'HTML' ),
'text/markdown' => t ( 'Markdown' ),
'text/plain' => t ( 'Text' ),
'application/x-pdl' => t ( 'Comanche Layout' )
2017-09-13 05:32:31 +00:00
]);
2013-09-02 08:38:17 +00:00
2016-05-25 03:49:23 +00:00
2017-03-13 23:19:47 +00:00
if (( App :: $is_sys ) || ( channel_codeallowed ( $channel_id ) && $channel_id == local_channel ())){
2017-09-20 06:30:52 +00:00
$x [ 'application/x-php' ] = t ( 'PHP' );
2015-04-09 06:20:28 +00:00
}
2013-09-02 08:38:17 +00:00
2017-09-20 06:30:52 +00:00
foreach ( $x as $y => $z ) {
2015-04-14 09:50:21 +00:00
$selected = (( $y == $current ) ? ' selected="selected" ' : '' );
2017-09-20 06:30:52 +00:00
$options .= '<option value="' . $y . '"' . $selected . '>' . $z . '</option>' ;
2013-09-02 08:38:17 +00:00
}
2015-04-14 09:50:21 +00:00
$o = replace_macros ( get_markup_template ( 'field_select_raw.tpl' ), array (
2017-09-13 06:25:19 +00:00
'$field' => array ( $element , t ( 'Page content type' ), $selected , '' , $options )
2015-04-14 09:50:21 +00:00
));
2013-09-02 08:38:17 +00:00
return $o ;
}
2011-08-01 23:51:01 +00:00
2016-04-29 04:02:27 +00:00
function engr_units_to_bytes ( $size_str ) {
2016-04-30 06:47:13 +00:00
if ( ! $size_str )
return $size_str ;
switch ( substr ( trim ( $size_str ), - 1 )) {
2014-12-14 00:22:52 +00:00
case 'M' : case 'm' : return ( int ) $size_str * 1048576 ;
case 'K' : case 'k' : return ( int ) $size_str * 1024 ;
case 'G' : case 'g' : return ( int ) $size_str * 1073741824 ;
default : return $size_str ;
}
2013-02-27 02:26:33 +00:00
}
2011-08-01 23:51:01 +00:00
2012-08-27 06:05:00 +00:00
function base64url_encode ( $s , $strip_padding = true ) {
2011-08-01 23:51:01 +00:00
$s = strtr ( base64_encode ( $s ), '+/' , '-_' );
if ( $strip_padding )
$s = str_replace ( '=' , '' , $s );
return $s ;
}
function base64url_decode ( $s ) {
2012-01-25 00:45:58 +00:00
if ( is_array ( $s )) {
logger ( 'base64url_decode: illegal input: ' . print_r ( debug_backtrace (), true ));
return $s ;
}
2011-08-01 23:51:01 +00:00
return base64_decode ( strtr ( $s , '-_' , '+/' ));
}
2011-08-17 03:05:02 +00:00
2016-08-09 23:59:35 +00:00
function base64special_encode ( $s , $strip_padding = true ) {
$s = strtr ( base64_encode ( $s ), '+/' , ',.' );
if ( $strip_padding )
$s = str_replace ( '=' , '' , $s );
return $s ;
}
function base64special_decode ( $s ) {
if ( is_array ( $s )) {
logger ( 'base64url_decode: illegal input: ' . print_r ( debug_backtrace (), true ));
return $s ;
}
return base64_decode ( strtr ( $s , ',.' , '+/' ));
}
2014-12-14 00:22:52 +00:00
/**
2016-10-01 22:41:25 +00:00
* @ brief Return a div to clear floats .
2014-12-14 00:22:52 +00:00
*
* @ return string
*/
2011-10-12 01:24:37 +00:00
function cleardiv () {
return '<div class="clear"></div>' ;
}
function bb_translate_video ( $s ) {
2016-05-09 02:12:52 +00:00
$arr = array ( 'string' => $s );
call_hooks ( 'bb_translate_video' , $arr );
return $arr [ 'string' ];
2011-10-12 01:24:37 +00:00
}
function html2bb_video ( $s ) {
2016-05-09 02:12:52 +00:00
$arr = array ( 'string' => $s );
call_hooks ( 'html2bb_video' , $arr );
return $arr [ 'string' ];
2011-10-27 08:54:52 +00:00
}
/**
* apply xmlify () to all values of array $val , recursively
*/
2014-12-14 00:22:52 +00:00
function array_xmlify ( $val ) {
2011-10-27 08:54:52 +00:00
if ( is_bool ( $val )) return $val ? " true " : " false " ;
if ( is_array ( $val )) return array_map ( 'array_xmlify' , $val );
return xmlify (( string ) $val );
}
2012-01-18 00:30:32 +00:00
2014-12-14 00:22:52 +00:00
function reltoabs ( $text , $base ) {
if ( empty ( $base ))
return $text ;
2012-01-18 00:30:32 +00:00
2014-12-14 00:22:52 +00:00
$base = rtrim ( $base , '/' );
2012-01-18 00:30:32 +00:00
2014-12-14 00:22:52 +00:00
$base2 = $base . " / " ;
2012-01-18 00:30:32 +00:00
2014-12-14 00:22:52 +00:00
// Replace links
$pattern = " /<a([^>]*) href= \" (?!http|https| \ /)([^ \" ]*) \" / " ;
$replace = " <a \$ { 1} href= \" " . $base2 . " \$ { 2} \" " ;
$text = preg_replace ( $pattern , $replace , $text );
2012-01-18 00:30:32 +00:00
2014-12-14 00:22:52 +00:00
$pattern = " /<a([^>]*) href= \" (?!http|https)([^ \" ]*) \" / " ;
$replace = " <a \$ { 1} href= \" " . $base . " \$ { 2} \" " ;
$text = preg_replace ( $pattern , $replace , $text );
2012-01-18 00:30:32 +00:00
2014-12-14 00:22:52 +00:00
// Replace images
$pattern = " /<img([^>]*) src= \" (?!http|https| \ /)([^ \" ]*) \" / " ;
$replace = " <img \$ { 1} src= \" " . $base2 . " \$ { 2} \" " ;
$text = preg_replace ( $pattern , $replace , $text );
2012-01-18 00:30:32 +00:00
2014-12-14 00:22:52 +00:00
$pattern = " /<img([^>]*) src= \" (?!http|https)([^ \" ]*) \" / " ;
$replace = " <img \$ { 1} src= \" " . $base . " \$ { 2} \" " ;
$text = preg_replace ( $pattern , $replace , $text );
2012-01-18 00:30:32 +00:00
2014-12-14 00:22:52 +00:00
// Done
return $text ;
2012-01-18 00:30:32 +00:00
}
2012-03-06 20:50:38 +00:00
function item_post_type ( $item ) {
2021-06-25 22:40:15 +00:00
switch ( $item [ 'resource_type' ]) {
2014-12-14 00:22:52 +00:00
case 'photo' :
$post_type = t ( 'photo' );
break ;
case 'event' :
$post_type = t ( 'event' );
break ;
default :
2021-06-25 22:40:15 +00:00
$post_type = t ( 'post' );
if ( $item [ 'mid' ] !== $item [ 'parent_mid' ])
2014-12-14 00:22:52 +00:00
$post_type = t ( 'comment' );
break ;
}
2012-07-10 05:08:25 +00:00
2021-06-25 22:40:15 +00:00
if ( strlen ( $item [ 'verb' ]) && ( ! activity_match ( $item [ 'verb' ], ACTIVITY_POST )))
2013-06-20 04:50:14 +00:00
$post_type = t ( 'activity' );
2012-07-10 05:08:25 +00:00
2013-06-20 04:50:14 +00:00
return $post_type ;
2012-03-12 04:32:11 +00:00
}
2018-02-26 23:46:29 +00:00
// This needs to be fixed to use quoted tag strings
2012-03-06 20:50:38 +00:00
2012-03-22 23:17:10 +00:00
function undo_post_tagging ( $s ) {
2018-02-26 23:46:29 +00:00
2012-03-22 23:17:10 +00:00
$matches = null ;
2018-04-25 09:26:37 +00:00
$x = null ;
2018-02-26 23:46:29 +00:00
// undo tags and mentions
2014-02-04 03:54:32 +00:00
$cnt = preg_match_all ( '/([@#])(\!*)\[zrl=(.*?)\](.*?)\[\/zrl\]/ism' , $s , $matches , PREG_SET_ORDER );
2012-03-22 23:17:10 +00:00
if ( $cnt ) {
foreach ( $matches as $mtch ) {
2018-08-18 04:21:02 +00:00
$x = false ;
2018-04-25 09:26:37 +00:00
if ( $mtch [ 1 ] === '@' ) {
$x = q ( " select xchan_addr, xchan_url from xchan where xchan_url = '%s' limit 1 " ,
dbesc ( $mtch [ 3 ])
);
}
2018-04-24 22:32:24 +00:00
if ( $x ) {
$s = str_replace ( $mtch [ 0 ], $mtch [ 1 ] . $mtch [ 2 ] . '{' . (( $x [ 0 ][ 'xchan_addr' ]) ? $x [ 0 ][ 'xchan_addr' ] : $x [ 0 ][ 'xchan_url' ]) . '}' , $s );
}
else {
$s = str_replace ( $mtch [ 0 ], $mtch [ 1 ] . $mtch [ 2 ] . quote_tag ( $mtch [ 4 ]), $s );
}
2012-03-22 23:17:10 +00:00
}
}
2019-10-22 05:47:31 +00:00
$matches = null ;
$x = null ;
$cnt = preg_match_all ( '/([@#])(\!*)\[url=(.*?)\](.*?)\[\/url\]/ism' , $s , $matches , PREG_SET_ORDER );
if ( $cnt ) {
foreach ( $matches as $mtch ) {
$x = false ;
if ( $mtch [ 1 ] === '@' ) {
$x = q ( " select xchan_addr, xchan_url from xchan where xchan_url = '%s' limit 1 " ,
dbesc ( $mtch [ 3 ])
);
}
if ( $x ) {
$s = str_replace ( $mtch [ 0 ], $mtch [ 1 ] . $mtch [ 2 ] . '{' . (( $x [ 0 ][ 'xchan_addr' ]) ? $x [ 0 ][ 'xchan_addr' ] : $x [ 0 ][ 'xchan_url' ]) . '}' , $s );
}
else {
$s = str_replace ( $mtch [ 0 ], $mtch [ 1 ] . $mtch [ 2 ] . quote_tag ( $mtch [ 4 ]), $s );
}
}
}
2012-03-22 23:17:10 +00:00
return $s ;
}
2018-02-27 04:30:36 +00:00
function quote_tag ( $s ) {
if ( strpos ( $s , ' ' ) !== false )
return '"' . $s . '"' ;
return $s ;
}
2012-04-10 23:31:49 +00:00
function fix_mce_lf ( $s ) {
$s = str_replace ( " \r \n " , " \n " , $s );
2012-08-01 12:02:43 +00:00
// $s = str_replace("\n\n","\n",$s);
2012-04-10 23:31:49 +00:00
return $s ;
2012-04-13 09:56:21 +00:00
}
2012-05-09 05:46:40 +00:00
function protect_sprintf ( $s ) {
return ( str_replace ( '%' , '%%' , $s ));
}
2012-06-12 02:36:04 +00:00
function is_a_date_arg ( $s ) {
$i = intval ( $s );
if ( $i > 1900 ) {
$y = date ( 'Y' );
if ( $i <= $y + 1 && strpos ( $s , '-' ) == 4 ) {
$m = intval ( substr ( $s , 5 ));
if ( $m > 0 && $m <= 12 )
return true ;
}
}
2014-12-14 00:22:52 +00:00
2012-06-12 02:36:04 +00:00
return false ;
}
2012-07-31 04:51:25 +00:00
function legal_webbie ( $s ) {
2017-09-05 23:38:55 +00:00
if ( ! $s )
2012-07-31 04:51:25 +00:00
return '' ;
2017-09-05 23:38:55 +00:00
// WARNING: This regex may not work in a federated environment.
2017-04-06 02:08:43 +00:00
// You will probably want something like
// preg_replace('/([^a-z0-9\_])/','',strtolower($s));
2017-04-04 05:13:12 +00:00
2017-09-05 23:38:55 +00:00
$r = preg_replace ( '/([^a-z0-9\-\_])/' , '' , strtolower ( $s ));
2017-04-04 05:13:12 +00:00
2017-04-06 02:08:43 +00:00
$x = [ 'input' => $s , 'output' => $r ];
call_hooks ( 'legal_webbie' , $x );
return $x [ 'output' ];
2012-07-31 04:51:25 +00:00
2017-04-06 02:08:43 +00:00
}
function legal_webbie_text () {
// WARNING: This will not work in a federated environment.
2017-09-05 23:38:55 +00:00
$s = t ( 'a-z, 0-9, -, and _ only' );
2017-04-06 02:08:43 +00:00
$x = [ 'text' => $s ];
call_hooks ( 'legal_webbie_text' , $x );
return $x [ 'text' ];
2017-04-04 05:13:12 +00:00
2012-07-31 04:51:25 +00:00
}
2017-04-06 02:08:43 +00:00
2012-07-31 04:51:25 +00:00
function check_webbie ( $arr ) {
2017-04-04 05:13:12 +00:00
// These names conflict with the CalDAV server
$taken = [ 'principals' , 'addressbooks' , 'calendars' ];
2014-11-21 23:35:59 +00:00
$reservechan = get_config ( 'system' , 'reserved_channels' );
2017-04-04 05:13:12 +00:00
if ( strlen ( $reservechan )) {
$taken = array_merge ( $taken , explode ( ',' , $reservechan ));
}
2014-12-14 00:22:52 +00:00
2012-07-31 04:51:25 +00:00
$str = '' ;
if ( count ( $arr )) {
foreach ( $arr as $x ) {
$y = legal_webbie ( $x );
if ( strlen ( $y )) {
if ( $str )
$str .= ',' ;
$str .= " ' " . dbesc ( $y ) . " ' " ;
}
}
2014-04-07 02:59:00 +00:00
2012-07-31 04:51:25 +00:00
if ( strlen ( $str )) {
2012-09-26 00:57:20 +00:00
$r = q ( " select channel_address from channel where channel_address in ( $str ) " );
2012-07-31 04:51:25 +00:00
if ( count ( $r )) {
foreach ( $r as $rr ) {
2012-09-26 00:57:20 +00:00
$taken [] = $rr [ 'channel_address' ];
2012-07-31 04:51:25 +00:00
}
}
foreach ( $arr as $x ) {
2014-04-07 02:59:00 +00:00
$y = legal_webbie ( $x );
if ( ! in_array ( $y , $taken )) {
return $y ;
2012-07-31 04:51:25 +00:00
}
}
}
}
2014-12-14 00:22:52 +00:00
2012-07-31 04:51:25 +00:00
return '' ;
}
2014-12-14 00:22:52 +00:00
2016-05-12 00:18:17 +00:00
function ids_to_array ( $arr , $idx = 'id' ) {
2021-03-15 05:10:44 +00:00
$t = [];
2016-05-12 00:18:17 +00:00
if ( $arr ) {
foreach ( $arr as $x ) {
2017-02-25 18:12:41 +00:00
if ( array_key_exists ( $idx , $x ) && strlen ( $x [ $idx ]) && ( ! in_array ( $x [ $idx ], $t ))) {
2016-05-12 00:18:17 +00:00
$t [] = $x [ $idx ];
}
}
}
return ( $t );
}
2012-08-30 06:03:03 +00:00
2016-12-02 20:15:18 +00:00
function ids_to_querystr ( $arr , $idx = 'id' , $quote = false ) {
2021-03-15 05:10:44 +00:00
$t = [];
2015-03-24 02:56:10 +00:00
if ( $arr ) {
foreach ( $arr as $x ) {
if ( ! in_array ( $x [ $idx ], $t )) {
2017-02-25 18:12:41 +00:00
if ( $quote )
2016-12-02 20:15:18 +00:00
$t [] = " ' " . dbesc ( $x [ $idx ]) . " ' " ;
else
$t [] = $x [ $idx ];
2015-03-24 02:56:10 +00:00
}
}
}
2012-08-30 06:03:03 +00:00
return ( implode ( ',' , $t ));
2012-10-08 04:44:11 +00:00
}
2018-02-05 01:01:59 +00:00
/**
* @ brief array_elm_to_str ( $arr , $elm , $delim = ',' ) extract unique individual elements from an array of arrays and return them as a string separated by a delimiter
* similar to ids_to_querystr , but allows a different delimiter instead of a db - quote option
* empty elements ( evaluated after trim ()) are ignored .
* @ param $arr array
* @ param $elm array key to extract from sub - array
* @ param $delim string default ','
2018-04-26 06:10:08 +00:00
* @ param $each filter function to apply to each element before evaluation , default is 'trim' .
2018-02-05 01:01:59 +00:00
* @ returns string
*/
2018-03-29 09:26:25 +00:00
function array_elm_to_str ( $arr , $elm , $delim = ',' , $each = 'trim' ) {
2018-02-05 01:01:59 +00:00
$tmp = [];
if ( $arr && is_array ( $arr )) {
foreach ( $arr as $x ) {
if ( is_array ( $x ) && array_key_exists ( $elm , $x )) {
2018-03-29 09:26:25 +00:00
$z = $each ( $x [ $elm ]);
2018-02-05 01:01:59 +00:00
if (( $z ) && ( ! in_array ( $z , $tmp ))) {
$tmp [] = $z ;
}
}
}
}
return implode ( $delim , $tmp );
}
2018-03-29 09:26:25 +00:00
function trim_and_unpunify ( $s ) {
return unpunify ( trim ( $s ));
}
2018-02-05 01:01:59 +00:00
2019-09-10 04:03:33 +00:00
2016-10-01 22:41:25 +00:00
/**
* @ brief Fetches xchan and hubloc data for an array of items with only an
* author_xchan and owner_xchan .
*
* If $abook is true also include the abook info . This is needed in the API to
* save extra per item lookups there .
*
2017-05-04 22:23:57 +00:00
* @ param [ in , out ] array & $items
2016-10-01 22:41:25 +00:00
* @ param boolean $abook If true also include the abook info
* @ param number $effective_uid
*/
function xchan_query ( & $items , $abook = true , $effective_uid = 0 ) {
2021-03-15 05:10:44 +00:00
$arr = [];
2019-08-05 00:30:07 +00:00
2012-10-08 04:44:11 +00:00
if ( $items && count ( $items )) {
2014-09-23 05:03:19 +00:00
if ( $effective_uid ) {
for ( $x = 0 ; $x < count ( $items ); $x ++ ) {
$items [ $x ][ 'real_uid' ] = $items [ $x ][ 'uid' ];
$items [ $x ][ 'uid' ] = $effective_uid ;
}
}
2012-10-08 04:44:11 +00:00
foreach ( $items as $item ) {
2016-06-23 02:22:59 +00:00
if ( $item [ 'owner_xchan' ] && ( ! in_array ( " ' " . dbesc ( $item [ 'owner_xchan' ]) . " ' " , $arr )))
2012-10-08 04:44:11 +00:00
$arr [] = " ' " . dbesc ( $item [ 'owner_xchan' ]) . " ' " ;
2016-06-23 02:22:59 +00:00
if ( $item [ 'author_xchan' ] && ( ! in_array ( " ' " . dbesc ( $item [ 'author_xchan' ]) . " ' " , $arr )))
2012-10-08 04:44:11 +00:00
$arr [] = " ' " . dbesc ( $item [ 'author_xchan' ]) . " ' " ;
}
}
if ( count ( $arr )) {
2013-01-20 06:21:00 +00:00
if ( $abook ) {
2013-06-20 22:55:20 +00:00
$chans = q ( " select * from xchan left join hubloc on hubloc_hash = xchan_hash left join abook on abook_xchan = xchan_hash and abook_channel = %d
2019-07-30 02:33:36 +00:00
where xchan_hash in ( " . protect_sprintf(implode(',', $arr )) . " ) order by hubloc_primary desc " ,
2013-06-20 09:03:14 +00:00
intval ( $item [ 'uid' ])
);
2013-01-20 06:21:00 +00:00
}
else {
$chans = q ( " select xchan.*,hubloc.* from xchan left join hubloc on hubloc_hash = xchan_hash
2019-07-30 02:33:36 +00:00
where xchan_hash in ( " . protect_sprintf(implode(',', $arr )) . " ) order by hubloc_primary desc " );
2013-01-20 06:21:00 +00:00
}
2018-04-09 12:28:41 +00:00
$xchans = q ( " select * from xchan where xchan_hash in ( " . protect_sprintf ( implode ( ',' , $arr )) . " ) and xchan_network in ('rss','unknown', 'anon') " );
2014-09-01 03:51:05 +00:00
if ( ! $chans )
$chans = $xchans ;
else
2016-10-01 22:41:25 +00:00
$chans = array_merge ( $xchans , $chans );
2012-10-08 04:44:11 +00:00
}
2019-08-05 00:30:07 +00:00
2012-10-08 04:44:11 +00:00
if ( $items && count ( $items ) && $chans && count ( $chans )) {
for ( $x = 0 ; $x < count ( $items ); $x ++ ) {
$items [ $x ][ 'owner' ] = find_xchan_in_array ( $items [ $x ][ 'owner_xchan' ], $chans );
$items [ $x ][ 'author' ] = find_xchan_in_array ( $items [ $x ][ 'author_xchan' ], $chans );
}
}
}
2012-12-06 00:44:07 +00:00
function xchan_mail_query ( & $item ) {
2021-03-15 05:10:44 +00:00
$arr = [];
2012-12-06 00:44:07 +00:00
$chans = null ;
if ( $item ) {
2016-06-23 02:22:59 +00:00
if ( $item [ 'from_xchan' ] && ( ! in_array ( " ' " . dbesc ( $item [ 'from_xchan' ]) . " ' " , $arr )))
2012-12-06 00:44:07 +00:00
$arr [] = " ' " . dbesc ( $item [ 'from_xchan' ]) . " ' " ;
2016-06-23 02:22:59 +00:00
if ( $item [ 'to_xchan' ] && ( ! in_array ( " ' " . dbesc ( $item [ 'to_xchan' ]) . " ' " , $arr )))
2012-12-06 00:44:07 +00:00
$arr [] = " ' " . dbesc ( $item [ 'to_xchan' ]) . " ' " ;
}
if ( count ( $arr )) {
$chans = q ( " select xchan.*,hubloc.* from xchan left join hubloc on hubloc_hash = xchan_hash
2017-11-02 07:44:46 +00:00
where xchan_hash in ( " . protect_sprintf(implode(',', $arr )) . " ) and hubloc_primary = 1 " );
2012-12-06 00:44:07 +00:00
}
if ( $chans ) {
$item [ 'from' ] = find_xchan_in_array ( $item [ 'from_xchan' ], $chans );
$item [ 'to' ] = find_xchan_in_array ( $item [ 'to_xchan' ], $chans );
}
}
2012-10-08 04:44:11 +00:00
function find_xchan_in_array ( $xchan , $arr ) {
if ( count ( $arr )) {
foreach ( $arr as $x ) {
if ( $x [ 'xchan_hash' ] === $xchan ) {
return $x ;
}
}
}
2021-03-15 05:10:44 +00:00
return [];
2012-11-07 00:16:26 +00:00
}
2012-11-14 03:32:59 +00:00
function get_rel_link ( $j , $rel ) {
2015-02-04 00:03:05 +00:00
if ( is_array ( $j ) && ( $j ))
2012-11-07 00:16:26 +00:00
foreach ( $j as $l )
2020-03-13 00:08:44 +00:00
if ( is_array ( $l ) && array_key_exists ( 'rel' , $l ) && $l [ 'rel' ] === $rel && array_key_exists ( 'href' , $l ))
2012-11-14 03:32:59 +00:00
return $l [ 'href' ];
2014-12-14 00:22:52 +00:00
2012-11-07 00:16:26 +00:00
return '' ;
}
// Lots of code to write here
function magic_link ( $s ) {
return $s ;
}
2014-12-14 00:22:52 +00:00
2016-10-01 22:41:25 +00:00
/**
2017-05-04 22:23:57 +00:00
* @ brief If $escape is true , dbesc () each element before adding quotes .
2016-10-01 22:41:25 +00:00
*
2017-05-04 22:23:57 +00:00
* @ param [ in , out ] array & $arr
* @ param boolean $escape ( optional ) default false
2016-10-01 22:41:25 +00:00
*/
function stringify_array_elms ( & $arr , $escape = false ) {
2012-11-15 01:02:30 +00:00
for ( $x = 0 ; $x < count ( $arr ); $x ++ )
2013-01-21 02:05:29 +00:00
$arr [ $x ] = " ' " . (( $escape ) ? dbesc ( $arr [ $x ]) : $arr [ $x ]) . " ' " ;
2012-11-15 01:02:30 +00:00
}
2012-12-29 08:33:04 +00:00
2018-04-18 05:23:28 +00:00
/**
* @ brief Similar to stringify_array_elms but returns a string . If $escape is true , dbesc () each element before adding quotes .
*
* @ param array $arr
* @ param boolean $escape ( optional ) default false
* @ return string
*/
function stringify_array ( $arr , $escape = false ) {
if ( $arr ) {
2019-10-03 01:07:13 +00:00
stringify_array_elms ( $arr , $escape );
2018-04-18 05:23:28 +00:00
return ( implode ( ',' , $arr ));
}
return EMPTY_STR ;
}
2012-12-29 08:33:04 +00:00
/**
2016-10-01 22:41:25 +00:00
* @ brief Indents a flat JSON string to make it more human - readable .
2012-12-29 08:33:04 +00:00
*
* @ param string $json The original JSON string to process .
* @ return string Indented version of the original JSON string .
*/
function jindent ( $json ) {
2014-12-14 00:22:52 +00:00
$result = '' ;
$pos = 0 ;
$strLen = strlen ( $json );
$indentStr = ' ' ;
$newLine = " \n " ;
$prevChar = '' ;
2013-02-27 02:26:33 +00:00
$outOfQuotes = true ;
2012-12-29 08:33:04 +00:00
2019-10-04 23:18:35 +00:00
if ( is_array ( $json )) {
btlogger ( 'is an array' , LOGGER_DATA );
$json = json_encode ( $json , JSON_UNESCAPED_SLASHES );
}
2019-09-30 06:26:59 +00:00
for ( $i = 0 ; $i <= $strLen ; $i ++ ) {
2013-02-27 02:26:33 +00:00
// Grab the next character in the string.
$char = substr ( $json , $i , 1 );
2012-12-29 08:33:04 +00:00
2013-02-27 02:26:33 +00:00
// Are we inside a quoted string?
if ( $char == '"' && $prevChar != '\\' ) {
$outOfQuotes = ! $outOfQuotes ;
2019-09-30 06:26:59 +00:00
}
2016-10-01 22:41:25 +00:00
// If this character is the end of an element,
2013-02-27 02:26:33 +00:00
// output a new line and indent the next line.
2019-09-30 06:26:59 +00:00
elseif (( $char == '}' || $char == ']' ) && $outOfQuotes ) {
2013-02-27 02:26:33 +00:00
$result .= $newLine ;
$pos -- ;
2019-09-30 06:26:59 +00:00
for ( $j = 0 ; $j < $pos ; $j ++ ) {
2013-02-27 02:26:33 +00:00
$result .= $indentStr ;
}
}
2014-12-14 00:22:52 +00:00
2013-02-27 02:26:33 +00:00
// Add the character to the result string.
$result .= $char ;
2016-10-01 22:41:25 +00:00
// If the last character was the beginning of an element,
2013-02-27 02:26:33 +00:00
// output a new line and indent the next line.
if (( $char == ',' || $char == '{' || $char == '[' ) && $outOfQuotes ) {
$result .= $newLine ;
if ( $char == '{' || $char == '[' ) {
$pos ++ ;
}
2014-12-14 00:22:52 +00:00
2013-02-27 02:26:33 +00:00
for ( $j = 0 ; $j < $pos ; $j ++ ) {
$result .= $indentStr ;
}
}
$prevChar = $char ;
}
2012-12-29 08:33:04 +00:00
2013-02-27 02:26:33 +00:00
return $result ;
2012-12-29 08:33:04 +00:00
}
2013-01-05 06:04:57 +00:00
2015-04-06 21:51:30 +00:00
/**
* @ brief Creates navigation menu for webpage , layout , blocks , menu sites .
*
2016-10-01 22:41:25 +00:00
* @ return string with parsed HTML
2015-04-06 21:51:30 +00:00
*/
2013-09-04 02:55:26 +00:00
function design_tools () {
2014-11-12 02:05:50 +00:00
2018-04-19 00:26:05 +00:00
$channel = channelx_by_n ( App :: $profile [ 'profile_uid' ]);
2014-11-12 04:44:43 +00:00
$sys = false ;
2014-11-12 02:05:50 +00:00
2016-03-31 23:06:03 +00:00
if ( App :: $is_sys && is_site_admin ()) {
2016-05-22 23:54:30 +00:00
require_once ( 'include/channel.php' );
2014-11-12 02:05:50 +00:00
$channel = get_sys_channel ();
2014-11-12 04:44:43 +00:00
$sys = true ;
2014-11-12 02:05:50 +00:00
}
2013-12-19 10:16:14 +00:00
$who = $channel [ 'channel_address' ];
return replace_macros ( get_markup_template ( 'design_tools.tpl' ), array (
2017-04-04 05:13:12 +00:00
'$title' => t ( 'Design Tools' ),
'$who' => $who ,
'$sys' => $sys ,
2013-12-19 10:16:14 +00:00
'$blocks' => t ( 'Blocks' ),
2017-04-04 05:13:12 +00:00
'$menus' => t ( 'Menus' ),
2013-12-19 10:16:14 +00:00
'$layout' => t ( 'Layouts' ),
2017-04-04 05:13:12 +00:00
'$pages' => t ( 'Pages' )
2013-12-19 10:16:14 +00:00
));
2013-09-04 02:55:26 +00:00
}
2016-07-10 10:58:20 +00:00
/**
2016-08-18 01:25:50 +00:00
* @ brief Creates website portation tools menu
2016-07-10 10:58:20 +00:00
*
* @ return string
*/
2016-08-18 01:25:50 +00:00
function website_portation_tools () {
2016-07-10 10:58:20 +00:00
$channel = App :: get_channel ();
$sys = false ;
if ( App :: $is_sys && is_site_admin ()) {
require_once ( 'include/channel.php' );
$channel = get_sys_channel ();
$sys = true ;
}
2016-08-18 01:25:50 +00:00
return replace_macros ( get_markup_template ( 'website_portation_tools.tpl' ), array (
2017-04-04 05:13:12 +00:00
'$title' => t ( 'Import' ),
'$import_label' => t ( 'Import website...' ),
'$import_placeholder' => t ( 'Select folder to import' ),
'$file_upload_text' => t ( 'Import from a zipped folder:' ),
'$file_import_text' => t ( 'Import from cloud files:' ),
'$desc' => t ( '/cloud/channel/path/to/folder' ),
'$hint' => t ( 'Enter path to website files' ),
'$select' => t ( 'Select folder' ),
'$export_label' => t ( 'Export website...' ),
'$file_download_text' => t ( 'Export to a zip file' ),
'$filename_desc' => t ( 'website.zip' ),
'$filename_hint' => t ( 'Enter a name for the zip file.' ),
'$cloud_export_text' => t ( 'Export to cloud files' ),
'$cloud_export_desc' => t ( '/path/to/export/folder' ),
'$cloud_export_hint' => t ( 'Enter a path to a cloud files destination.' ),
2016-10-01 22:41:25 +00:00
'$cloud_export_select' => t ( 'Specify folder' ),
2016-08-17 22:19:36 +00:00
));
}
2016-10-01 22:41:25 +00:00
/**
* @ brief case insensitive in_array ()
*
* @ param string $needle
* @ param array $haystack
* @ return boolean
*/
2013-09-20 02:50:13 +00:00
function in_arrayi ( $needle , $haystack ) {
return in_array ( strtolower ( $needle ), array_map ( 'strtolower' , $haystack ));
}
2014-02-18 03:48:05 +00:00
function normalise_openid ( $s ) {
return trim ( str_replace ( array ( 'http://' , 'https://' ), array ( '' , '' ), $s ), '/' );
}
2016-10-01 22:41:25 +00:00
/**
* Used in ajax endless scroll request to find out all the args that the master page was viewing .
* This was using $_REQUEST , but $_REQUEST also contains all your cookies . So we ' re restricting it
* to $_GET and $_POST .
*
* @ return string with additional URL parameters
*/
2014-09-06 07:37:15 +00:00
function extra_query_args () {
$s = '' ;
2014-09-06 10:11:07 +00:00
if ( count ( $_GET )) {
foreach ( $_GET as $k => $v ) {
2014-09-06 07:37:15 +00:00
// these are request vars we don't want to duplicate
2018-08-27 06:00:31 +00:00
if ( ! in_array ( $k , array ( 'req' , 'f' , 'zid' , 'page' , 'PHPSESSID' ))) {
2014-11-12 00:09:45 +00:00
$s .= '&' . $k . '=' . urlencode ( $v );
2014-09-06 07:37:15 +00:00
}
}
}
2014-11-12 00:06:16 +00:00
if ( count ( $_POST )) {
foreach ( $_POST as $k => $v ) {
// these are request vars we don't want to duplicate
2018-08-27 06:00:31 +00:00
if ( ! in_array ( $k , array ( 'req' , 'f' , 'zid' , 'page' , 'PHPSESSID' ))) {
2014-11-12 00:09:45 +00:00
$s .= '&' . $k . '=' . urlencode ( $v );
2014-09-06 07:37:15 +00:00
}
}
}
2016-10-01 22:41:25 +00:00
2014-09-06 07:37:15 +00:00
return $s ;
2014-10-08 10:36:26 +00:00
}
2014-12-07 15:17:45 +00:00
/**
2015-03-21 23:06:08 +00:00
* @ brief This function removes the tag $tag from the text $body and replaces it
* with the appropiate link .
2014-12-07 15:17:45 +00:00
*
2015-03-21 23:06:08 +00:00
* @ param App $a
* @ param [ in , out ] string & $body the text to replace the tag in
* @ param [ in , out ] string & $access_tag used to return tag ACL exclusions e . g . @! foo
* @ param [ in , out ] string & $str_tags string to add the tag to
* @ param int $profile_uid
* @ param string $tag the tag to replace
2018-05-04 03:14:58 +00:00
* @ param boolean $in_network default true
2014-12-07 15:17:45 +00:00
* @ return boolean true if replaced , false if not replaced
*/
2019-02-04 00:57:07 +00:00
function handle_tag ( & $body , & $str_tags , $profile_uid , $tag , $in_network = true ) {
2014-12-07 15:17:45 +00:00
2019-02-04 00:57:07 +00:00
$channel = App :: get_channel ();
2014-12-07 15:17:45 +00:00
$replaced = false ;
$r = null ;
2021-03-15 05:10:44 +00:00
$match = [];
2014-12-07 15:17:45 +00:00
2017-09-25 02:45:19 +00:00
$termtype = (( strpos ( $tag , '#' ) === 0 ) ? TERM_HASHTAG : TERM_UNKNOWN );
$termtype = (( strpos ( $tag , '@' ) === 0 ) ? TERM_MENTION : $termtype );
2014-12-07 15:17:45 +00:00
2018-05-15 00:20:25 +00:00
// Is it a hashtag of some kind?
2019-02-13 23:33:45 +00:00
if ( in_array ( $termtype , [ TERM_HASHTAG ] )) {
2014-12-07 15:17:45 +00:00
// if the tag is already replaced...
2018-07-09 05:28:15 +00:00
if (( strpos ( $tag , '[zrl=' )) || ( strpos ( $tag , '[url=' ))) {
2018-05-15 00:20:25 +00:00
// ...do nothing
2014-12-07 15:17:45 +00:00
return $replaced ;
}
2018-05-15 00:20:25 +00:00
2014-12-07 15:17:45 +00:00
if ( ! $replaced ) {
2018-05-15 00:20:25 +00:00
// double-quoted hashtags: base tag has the htmlentity name only
2014-12-07 15:17:45 +00:00
if (( substr ( $tag , 0 , 7 ) === '#"' ) && ( substr ( $tag , - 6 , 6 ) === '"' )) {
$basetag = substr ( $tag , 7 );
$basetag = substr ( $basetag , 0 , - 6 );
}
2020-05-10 23:19:01 +00:00
elseif (( substr ( $tag , 0 , 2 ) === '#"' ) && ( substr ( $tag , - 1 , 1 ) === '"' )) {
$basetag = substr ( $tag , 2 );
$basetag = substr ( $basetag , 0 , - 1 );
}
2018-05-04 11:54:12 +00:00
else
$basetag = substr ( $tag , 1 );
2014-12-07 15:17:45 +00:00
2018-05-15 00:20:25 +00:00
// create text for link
2018-05-04 03:14:58 +00:00
2016-03-31 05:13:24 +00:00
$url = z_root () . '/search?tag=' . rawurlencode ( $basetag );
$newtag = '#[zrl=' . z_root () . '/search?tag=' . rawurlencode ( $basetag ) . ']' . $basetag . '[/zrl]' ;
2018-05-04 03:14:58 +00:00
2018-05-15 00:20:25 +00:00
// replace tag by the link. Make sure to not replace something in the middle of a word
2015-05-12 05:57:12 +00:00
$body = preg_replace ( '/(?<![a-zA-Z0-9=])' . preg_quote ( $tag , '/' ) . '/' , $newtag , $body );
2014-12-07 15:17:45 +00:00
$replaced = true ;
}
2018-05-15 00:20:25 +00:00
// is the link already in str_tags?
2014-12-07 15:17:45 +00:00
if ( ! stristr ( $str_tags , $newtag )) {
2018-05-15 00:20:25 +00:00
// append or set str_tags
2014-12-07 15:17:45 +00:00
if ( strlen ( $str_tags ))
$str_tags .= ',' ;
2014-12-14 00:22:52 +00:00
2014-12-07 15:17:45 +00:00
$str_tags .= $newtag ;
}
2019-02-04 00:57:07 +00:00
return [ [
'replaced' => $replaced ,
'termtype' => $termtype ,
'term' => $basetag ,
'url' => $url ,
'contact' => [],
'access_tag' => '' ,
]];
2014-12-07 15:17:45 +00:00
}
2018-05-15 00:20:25 +00:00
// END hashtags
2014-12-07 15:17:45 +00:00
2018-05-15 00:20:25 +00:00
// BEGIN mentions
2017-09-18 06:28:58 +00:00
2019-02-13 23:33:45 +00:00
if ( in_array ( $termtype , [ TERM_MENTION ] )) {
2017-09-18 06:28:58 +00:00
2019-02-13 23:33:45 +00:00
// The @! tag will alter permissions
2014-12-07 15:17:45 +00:00
2018-05-15 00:20:25 +00:00
// $in_network is set to false to avoid false positives on posts originating
// on a network which does not implement privacy tags or implements them differently.
2018-05-15 01:27:12 +00:00
$exclusive = ((( strpos ( substr ( $tag , 1 ), '!' ) === 0 ) && $in_network ) ? true : false );
2014-12-07 15:17:45 +00:00
2019-02-13 23:33:45 +00:00
// is it already replaced?
2019-02-04 00:57:07 +00:00
if ( strpos ( $tag , " [zrl= " ) || strpos ( $tag , " [url= " ))
2014-12-07 15:17:45 +00:00
return $replaced ;
2018-05-15 00:20:25 +00:00
// get the channel name
// First extract the name or name fragment we are going to replace
2014-12-07 15:17:45 +00:00
2018-05-15 00:20:25 +00:00
$name = substr ( $tag ,(( $exclusive ) ? 2 : 1 ));
$newname = $name ; // make a copy that we can mess with
2014-12-07 15:17:45 +00:00
$tagcid = 0 ;
$r = null ;
2018-05-15 00:20:25 +00:00
// is it some generated (autocompleted) name?
2014-12-07 15:17:45 +00:00
2018-04-24 22:32:24 +00:00
if ( substr ( $name , 0 , 1 ) === '{' && substr ( $name , - 1 , 1 ) === '}' ) {
$newname = substr ( $name , 1 );
2014-12-07 15:17:45 +00:00
$newname = substr ( $newname , 0 , - 1 );
2018-04-24 22:32:24 +00:00
2019-11-25 03:59:12 +00:00
$r = q ( " select * from xchan where xchan_addr = '%s' or xchan_hash = '%s' or xchan_url = '%s' " ,
dbesc ( $newname ),
2018-04-24 22:32:24 +00:00
dbesc ( $newname ),
dbesc ( $newname )
);
2014-12-07 15:17:45 +00:00
}
if ( ! $r ) {
// look for matching names in the address book
2018-05-15 00:20:25 +00:00
// Double quote the entire mentioned term to include special characters
// such as spaces and some punctuation.
// We see this after input filtering so quotes have been html entity encoded
2014-12-07 15:17:45 +00:00
if (( substr ( $name , 0 , 6 ) === '"' ) && ( substr ( $name , - 6 , 6 ) === '"' )) {
$newname = substr ( $name , 6 );
$newname = substr ( $newname , 0 , - 6 );
}
2020-05-10 23:19:01 +00:00
elseif (( substr ( $name , 0 , 1 ) === '"' ) && ( substr ( $name , - 1 , 1 ) === '"' )) {
$newname = substr ( $name , 1 );
$newname = substr ( $newname , 0 , - 1 );
}
2014-12-07 15:17:45 +00:00
2018-05-15 00:20:25 +00:00
// select someone from this user's contacts by name
2018-05-04 03:14:58 +00:00
2016-10-01 22:41:25 +00:00
$r = q ( " SELECT * FROM abook left join xchan on abook_xchan = xchan_hash
2019-02-04 00:57:07 +00:00
WHERE xchan_name = '%s' AND abook_channel = % d " ,
2014-12-07 15:17:45 +00:00
dbesc ( $newname ),
intval ( $profile_uid )
);
2018-05-04 03:14:58 +00:00
// select anybody by full hubloc_addr
if (( ! $r ) && strpos ( $newname , '@' )) {
$r = q ( " SELECT * FROM xchan left join hubloc on xchan_hash = hubloc_hash
2019-02-04 00:57:07 +00:00
WHERE hubloc_addr = '%s' " ,
2018-05-04 03:14:58 +00:00
dbesc ( $newname )
2014-12-07 15:17:45 +00:00
);
}
2018-05-15 00:20:25 +00:00
// select someone by attag or nick and the name passed in
2014-12-07 15:17:45 +00:00
2018-05-04 03:14:58 +00:00
if ( ! $r ) {
2019-11-13 04:29:08 +00:00
// strip user-supplied wildcards before running a wildcard search
$newname = str_replace ( '%' , '' , $newname );
2016-10-01 22:41:25 +00:00
$r = q ( " SELECT * FROM abook left join xchan on abook_xchan = xchan_hash
2019-02-04 00:57:07 +00:00
WHERE xchan_addr like ( '%s' ) AND abook_channel = % d " ,
2018-05-04 03:14:58 +00:00
dbesc ((( strpos ( $newname , '@' )) ? $newname : $newname . '@%' )),
2014-12-07 15:17:45 +00:00
intval ( $profile_uid )
);
}
2018-05-04 03:14:58 +00:00
2014-12-07 15:17:45 +00:00
}
2015-02-02 22:59:01 +00:00
2019-02-04 00:57:07 +00:00
$fn_results = [];
$access_tag = EMPTY_STR ;
2020-06-01 00:24:09 +00:00
// some platforms prefer to mention people by username rather than display name.
// make this a personal choice by the publisher
2020-06-02 05:36:55 +00:00
$tagpref = intval ( PConfig :: Get ( $profile_uid , 'system' , 'tag_username' , Config :: Get ( 'system' , 'tag_username' , false )));
2020-06-01 00:24:09 +00:00
2019-02-04 00:57:07 +00:00
// $r is set if we found something
2020-08-01 20:48:57 +00:00
if ( $r ) {
2020-09-06 09:50:11 +00:00
if ( array_key_exists ( 'hubloc_network' , $r )) {
$r = [ Libzot :: zot_record_preferred ( $r ) ];
}
else {
$r = [ Libzot :: zot_record_preferred ( $r , 'xchan_network' ) ];
}
2020-08-01 20:48:57 +00:00
}
2020-06-01 03:42:30 +00:00
if ( $r ) {
foreach ( $r as $xc ) {
2019-02-04 00:57:07 +00:00
$profile = $xc [ 'xchan_url' ];
2020-06-02 05:36:55 +00:00
2020-06-03 03:36:21 +00:00
// $tagpref
// 0 use display name
// 1 use username@host
// 2 use 'display name (username@host)'
// 127 use display name outbound and don't change inbound
2020-06-02 05:36:55 +00:00
2020-06-03 03:36:21 +00:00
$newname = $xc [ 'xchan_name' ];
2020-06-02 05:36:55 +00:00
if ( $tagpref === 1 && $xc [ 'xchan_addr' ]) {
$newname = $xc [ 'xchan_addr' ];
}
if ( $tagpref === 2 && $xc [ 'xchan_addr' ]) {
2020-06-01 01:01:17 +00:00
$newname = sprintf ( t ( '%1$s (%2$s)' ), $xc [ 'xchan_name' ], $newname );
}
2019-02-04 00:57:07 +00:00
// add the channel's xchan_hash to $access_tag if exclusive
2020-06-02 05:36:55 +00:00
if ( $exclusive ) {
2019-02-04 00:57:07 +00:00
$access_tag = 'cid:' . $xc [ 'xchan_hash' ];
}
// if there is a url for this channel
if ( isset ( $profile )) {
$replaced = true ;
//create profile link
$profile = str_replace ( ',' , '%2c' , $profile );
$url = $profile ;
2019-10-22 05:47:31 +00:00
$zrl = (( $xc [ 'xchan_network' ] === 'zot6' ) ? 'zrl' : 'url' );
$newtag = '@' . (( $exclusive ) ? '!' : '' ) . '[' . $zrl . '=' . $profile . ']' . $newname . '[/' . $zrl . ']' ;
2020-06-24 00:45:27 +00:00
2019-02-13 23:33:45 +00:00
$body = str_replace ( '@' . (( $exclusive ) ? '!' : '' ) . $name , $newtag , $body );
2019-02-04 00:57:07 +00:00
// append tag to str_tags
if ( ! stristr ( $str_tags , $newtag )) {
if ( strlen ( $str_tags ))
$str_tags .= ',' ;
$str_tags .= $newtag ;
}
}
$fn_results [] = [
'replaced' => $replaced ,
'termtype' => $termtype ,
'term' => $newname ,
'url' => $url ,
'access_tag' => $access_tag ,
'contact' => (( $r ) ? $xc : []),
];
}
2014-12-07 15:17:45 +00:00
2019-02-04 00:57:07 +00:00
}
else {
2014-12-07 15:17:45 +00:00
2019-02-04 00:57:07 +00:00
// check for a group/collection exclusion tag
2014-12-07 15:17:45 +00:00
2019-02-04 00:57:07 +00:00
// note that we aren't setting $replaced even though we're replacing text.
// This tag isn't going to get a term attached to it. It's only used for
2020-06-01 03:42:30 +00:00
// access control.
2014-12-07 15:17:45 +00:00
2019-02-04 00:57:07 +00:00
if ( local_channel () && local_channel () == $profile_uid ) {
2020-06-01 03:42:30 +00:00
$grp = AccessList :: byname ( $profile_uid , $name );
2019-02-04 00:57:07 +00:00
if ( $grp ) {
2019-10-23 23:07:12 +00:00
$g = q ( " select * from pgrp where id = %d and visible = 1 limit 1 " ,
2019-10-24 22:53:44 +00:00
intval ( $grp )
2019-02-04 00:57:07 +00:00
);
2019-10-23 23:07:12 +00:00
if ( $g && $exclusive ) {
2019-02-04 00:57:07 +00:00
$access_tag .= 'gid:' . $g [ 0 ][ 'hash' ];
}
$channel = App :: get_channel ();
if ( $channel ) {
2019-10-23 23:07:12 +00:00
$replaced = true ;
2019-10-24 22:53:44 +00:00
$newname = $channel [ 'channel_name' ] . ' (' . $g [ 0 ][ 'gname' ] . ')' ;
2019-10-23 23:07:12 +00:00
$newtag = '@' . (( $exclusive ) ? '!' : '' ) . '[zrl=' . z_root () . '/lists/view/' . $g [ 0 ][ 'hash' ] . ']' . $newname . '[/zrl]' ;
2019-02-04 00:57:07 +00:00
$body = str_replace ( '@' . (( $exclusive ) ? '!' : '' ) . $name , $newtag , $body );
}
}
}
// if there is a url for this channel
if ( isset ( $profile )) {
$replaced = true ;
//create profile link
$profile = str_replace ( ',' , '%2c' , $profile );
$url = $profile ;
2019-02-13 23:33:45 +00:00
$newtag = '@' . (( $exclusive ) ? '!' : '' ) . '[zrl=' . $profile . ']' . $newname . '[/zrl]' ;
$body = str_replace ( '@' . (( $exclusive ) ? '!' : '' ) . $name , $newtag , $body );
2019-02-04 00:57:07 +00:00
// append tag to str_tags
if ( ! stristr ( $str_tags , $newtag )) {
if ( strlen ( $str_tags ))
$str_tags .= ',' ;
$str_tags .= $newtag ;
}
}
$fn_results [] = [
'replaced' => $replaced ,
'termtype' => $termtype ,
'term' => $newname ,
'url' => $url ,
'access_tag' => $access_tag ,
'contact' => [],
];
}
}
2017-09-25 02:45:19 +00:00
2019-02-04 00:57:07 +00:00
return $fn_results ;
2014-12-07 15:17:45 +00:00
}
2015-01-12 19:01:07 +00:00
2019-02-04 00:57:07 +00:00
function linkify_tags ( & $body , $uid , $in_network = true ) {
2018-05-15 00:20:25 +00:00
$str_tags = EMPTY_STR ;
$results = [];
2015-01-12 19:01:07 +00:00
$tags = get_tags ( $body );
2015-02-13 03:22:07 +00:00
2021-04-08 00:27:50 +00:00
if ( is_array ( $tags ) && count ( $tags )) {
2015-01-12 19:01:07 +00:00
foreach ( $tags as $tag ) {
2015-02-02 22:59:01 +00:00
2019-02-04 00:57:07 +00:00
$success = handle_tag ( $body , $str_tags , ( $uid ) ? $uid : App :: $profile_uid , $tag , $in_network );
2018-04-05 01:53:06 +00:00
2019-02-04 00:57:07 +00:00
foreach ( $success as $handled_tag ) {
$results [] = [ 'success' => $handled_tag ];
}
2015-01-12 19:01:07 +00:00
}
}
2015-03-12 23:16:19 +00:00
2015-01-12 19:01:07 +00:00
return $results ;
}
2015-01-27 18:00:16 +00:00
/**
2015-03-12 23:16:19 +00:00
* @ brief returns icon name for use with e . g . font - awesome based on mime - type .
*
* These are the the font - awesome names of version 3.2 . 1. The newer font - awesome
* 4 has different names .
2015-01-27 18:00:16 +00:00
*
2015-03-12 23:16:19 +00:00
* @ param string $type mime type
2015-01-27 18:00:16 +00:00
* @ return string
2015-10-14 20:14:19 +00:00
* @ todo rename to get_icon_from_type ()
2015-01-27 18:00:16 +00:00
*/
function getIconFromType ( $type ) {
$iconMap = array (
//Folder
2017-11-20 05:51:21 +00:00
t ( 'Collection' ) => 'fa-folder-o' ,
'multipart/mixed' => 'fa-folder-o' , //dirs in attach use this mime type
2015-01-27 18:00:16 +00:00
//Common file
2016-04-30 18:39:57 +00:00
'application/octet-stream' => 'fa-file-o' ,
2015-01-27 18:00:16 +00:00
//Text
2016-04-30 18:39:57 +00:00
'text/plain' => 'fa-file-text-o' ,
2017-11-17 03:58:09 +00:00
'text/markdown' => 'fa-file-text-o' ,
'text/bbcode' => 'fa-file-text-o' ,
2021-03-08 05:32:28 +00:00
'text/x-multicode' => 'fa-file-text-o' ,
2017-11-17 03:58:09 +00:00
'text/html' => 'fa-file-text-o' ,
2016-07-28 08:28:48 +00:00
'application/msword' => 'fa-file-word-o' ,
'application/pdf' => 'fa-file-pdf-o' ,
'application/vnd.oasis.opendocument.text' => 'fa-file-word-o' ,
2016-04-30 18:39:57 +00:00
'application/epub+zip' => 'fa-book' ,
2015-01-27 18:00:16 +00:00
//Spreadsheet
2016-07-28 08:28:48 +00:00
'application/vnd.oasis.opendocument.spreadsheet' => 'fa-file-excel-o' ,
'application/vnd.ms-excel' => 'fa-file-excel-o' ,
2015-01-27 18:00:16 +00:00
//Image
2016-04-30 18:39:57 +00:00
'image/jpeg' => 'fa-picture-o' ,
'image/png' => 'fa-picture-o' ,
'image/gif' => 'fa-picture-o' ,
'image/svg+xml' => 'fa-picture-o' ,
2015-01-27 18:00:16 +00:00
//Archive
2016-07-28 08:28:48 +00:00
'application/zip' => 'fa-file-archive-o' ,
'application/x-rar-compressed' => 'fa-file-archive-o' ,
2015-01-27 18:00:16 +00:00
//Audio
2016-07-28 08:28:48 +00:00
'audio/mpeg' => 'fa-file-audio-o' ,
'audio/wav' => 'fa-file-audio-o' ,
'application/ogg' => 'fa-file-audio-o' ,
'audio/ogg' => 'fa-file-audio-o' ,
'audio/webm' => 'fa-file-audio-o' ,
'audio/mp4' => 'fa-file-audio-o' ,
2015-01-27 18:00:16 +00:00
//Video
2016-07-28 08:28:48 +00:00
'video/quicktime' => 'fa-file-video-o' ,
'video/webm' => 'fa-file-video-o' ,
'video/mp4' => 'fa-file-video-o' ,
'video/x-matroska' => 'fa-file-video-o'
2015-01-27 18:00:16 +00:00
);
2017-11-17 03:58:09 +00:00
$catMap = [
'application' => 'fa-file-code-o' ,
'multipart' => 'fa-folder' ,
'audio' => 'fa-file-audio-o' ,
'video' => 'fa-file-video-o' ,
'text' => 'fa-file-text-o' ,
'image' => 'fa=file-picture-o' ,
'message' => 'fa-file-text-o'
];
$iconFromType = '' ;
2015-01-27 18:00:16 +00:00
if ( array_key_exists ( $type , $iconMap )) {
$iconFromType = $iconMap [ $type ];
}
2017-11-17 03:58:09 +00:00
else {
$parts = explode ( '/' , $type );
if ( $parts [ 0 ] && $catMap [ $parts [ 0 ]]) {
$iconFromType = $catMap [ $parts [ 0 ]];
}
}
if ( ! $iconFromType ) {
$iconFromType = 'fa-file-o' ;
}
2015-01-27 18:00:16 +00:00
return $iconFromType ;
}
/**
* @ brief Returns a human readable formatted string for filesizes .
*
* @ param int $size filesize in bytes
2015-03-12 23:16:19 +00:00
* @ return string human readable formatted filesize
2015-10-14 20:14:19 +00:00
* @ todo rename to user_readable_size ()
2015-01-27 18:00:16 +00:00
*/
function userReadableSize ( $size ) {
2015-03-12 23:16:19 +00:00
$ret = '' ;
2015-01-27 18:00:16 +00:00
if ( is_numeric ( $size )) {
$incr = 0 ;
$k = 1024 ;
$unit = array ( 'bytes' , 'KB' , 'MB' , 'GB' , 'TB' , 'PB' );
while (( $size / $k ) >= 1 ){
$incr ++ ;
$size = round ( $size / $k , 2 );
}
2015-03-12 23:16:19 +00:00
$ret = $size . ' ' . $unit [ $incr ];
2015-01-27 18:00:16 +00:00
}
2015-03-12 23:16:19 +00:00
2015-01-27 18:00:16 +00:00
return $ret ;
}
2015-05-20 04:51:48 +00:00
function str_rot47 ( $str ) {
return strtr ( $str ,
'!"#$%&\'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~' ,
'PQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~!"#$%&\'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNO' );
}
2015-10-07 03:30:49 +00:00
function string_replace ( $old , $new , & $s ) {
$x = str_replace ( $old , $new , $s );
$replaced = false ;
if ( $x !== $s ) {
$replaced = true ;
}
$s = $x ;
return $replaced ;
}
function json_url_replace ( $old , $new , & $s ) {
$old = str_replace ( '/' , '\\/' , $old );
$new = str_replace ( '/' , '\\/' , $new );
$x = str_replace ( $old , $new , $s );
$replaced = false ;
if ( $x !== $s ) {
$replaced = true ;
}
$s = $x ;
return $replaced ;
}
2016-10-01 22:41:25 +00:00
2015-10-07 03:30:49 +00:00
2016-04-07 01:07:29 +00:00
function item_url_replace ( $channel , & $item , $old , $new , $oldnick = '' ) {
2016-10-01 22:41:25 +00:00
2016-04-07 01:07:29 +00:00
if ( $item [ 'attach' ]) {
2015-10-07 03:30:49 +00:00
json_url_replace ( $old , $new , $item [ 'attach' ]);
2016-04-07 01:07:29 +00:00
if ( $oldnick )
json_url_replace ( '/' . $oldnick . '/' , '/' . $channel [ 'channel_address' ] . '/' , $item [ 'attach' ]);
}
if ( $item [ 'object' ]) {
2015-10-07 03:30:49 +00:00
json_url_replace ( $old , $new , $item [ 'object' ]);
2016-04-07 01:07:29 +00:00
if ( $oldnick )
json_url_replace ( '/' . $oldnick . '/' , '/' . $channel [ 'channel_address' ] . '/' , $item [ 'object' ]);
}
if ( $item [ 'target' ]) {
2015-10-07 03:30:49 +00:00
json_url_replace ( $old , $new , $item [ 'target' ]);
2016-04-07 01:07:29 +00:00
if ( $oldnick )
json_url_replace ( '/' . $oldnick . '/' , '/' . $channel [ 'channel_address' ] . '/' , $item [ 'target' ]);
}
2015-10-07 03:30:49 +00:00
if ( string_replace ( $old , $new , $item [ 'body' ])) {
2018-07-23 05:18:58 +00:00
$item [ 'sig' ] = Libzot :: sign ( $item [ 'body' ], $channel [ 'channel_prvkey' ]);
2015-10-07 03:30:49 +00:00
$item [ 'item_verified' ] = 1 ;
}
2016-10-01 22:41:25 +00:00
2016-04-07 02:56:38 +00:00
$item [ 'plink' ] = str_replace ( $old , $new , $item [ 'plink' ]);
2016-04-07 01:07:29 +00:00
if ( $oldnick )
2016-04-07 02:56:38 +00:00
$item [ 'plink' ] = str_replace ( '/' . $oldnick . '/' , '/' . $channel [ 'channel_address' ] . '/' , $item [ 'plink' ]);
2016-04-07 01:07:29 +00:00
2016-04-07 02:56:38 +00:00
$item [ 'llink' ] = str_replace ( $old , $new , $item [ 'llink' ]);
2016-04-07 01:07:29 +00:00
if ( $oldnick )
2016-04-07 02:56:38 +00:00
$item [ 'llink' ] = str_replace ( '/' . $oldnick . '/' , '/' . $channel [ 'channel_address' ] . '/' , $item [ 'llink' ]);
2016-10-01 22:41:25 +00:00
2019-07-29 02:34:42 +00:00
if ( $item [ 'term' ]) {
for ( $x = 0 ; $x < count ( $item [ 'term' ]); $x ++ ) {
2019-07-29 03:19:16 +00:00
$item [ 'term' ][ $x ][ 'url' ] = str_replace ( $old , $new , $item [ 'term' ][ $x ][ 'url' ]);
if ( $oldnick ) {
$item [ 'term' ][ $x ][ 'url' ] = str_replace ( '/' . $oldnick . '/' , '/' . $channel [ 'channel_address' ] . '/' , $item [ 'term' ][ $x ][ 'url' ]);
}
2019-07-29 02:34:42 +00:00
}
}
2015-10-14 20:14:19 +00:00
}
2016-02-22 00:49:49 +00:00
/**
* @ brief Used to wrap ACL elements in angle brackets for storage .
*
* @ param [ in , out ] array & $item
*/
function sanitise_acl ( & $item ) {
if ( strlen ( $item ))
2017-10-24 00:52:17 +00:00
$item = '<' . notags ( trim ( urldecode ( $item ))) . '>' ;
2016-02-22 00:49:49 +00:00
else
unset ( $item );
}
/**
* @ brief Convert an ACL array to a storable string .
*
* @ param array $p
* @ return array
*/
function perms2str ( $p ) {
$ret = '' ;
if ( is_array ( $p ))
$tmp = $p ;
else
$tmp = explode ( ',' , $p );
if ( is_array ( $tmp )) {
array_walk ( $tmp , 'sanitise_acl' );
$ret = implode ( '' , $tmp );
}
return $ret ;
}
/**
* @ brief Turn user / group ACLs stored as angle bracketed text into arrays .
*
* turn string array of angle - bracketed elements into string array
2020-02-02 23:12:20 +00:00
* e . g . " <123xyz><246qyo><sxo33e> " => [ '123xyz' , '246qyo' , 'sxo33e' ];
2016-02-22 00:49:49 +00:00
*
* @ param string $s
* @ return array
*/
function expand_acl ( $s ) {
2021-03-15 05:10:44 +00:00
$ret = [];
2016-02-22 00:49:49 +00:00
if ( strlen ( $s )) {
$t = str_replace ( '<' , '' , $s );
$a = explode ( '>' , $t );
foreach ( $a as $aa ) {
if ( $aa )
$ret [] = $aa ;
}
}
return $ret ;
}
2016-05-06 06:07:35 +00:00
2016-08-03 19:16:57 +00:00
function acl2json ( $s ) {
$s = expand_acl ( $s );
$s = json_encode ( $s );
2016-10-01 22:41:25 +00:00
2016-08-03 19:16:57 +00:00
return $s ;
}
2016-10-01 22:41:25 +00:00
/**
* @ brief When editing a webpage - a dropdown is needed to select a page layout
*
* On submit , the pdl_select value ( which is the mid of an item with item_type = ITEM_TYPE_PDL )
* is stored in the webpage 's resource_id, with resource_type ' pdl ' .
*
* Then when displaying a webpage , we can see if it has a pdl attached . If not we ' ll
* use the default site / page layout .
*
* If it has a pdl we ' ll load it as we know the mid and pass the body through comanche_parser () which will generate the
* page layout from the given description
*
* @ FIXME - there is apparently a very similar function called layout_select ; this one should probably take precedence
* and the other should be checked for compatibility and removed
*
* @ param int $uid
* @ param string $current
* @ return string HTML code for dropdown
*/
function pdl_selector ( $uid , $current = '' ) {
2016-05-06 06:07:35 +00:00
$o = '' ;
$sql_extra = item_permissions_sql ( $uid );
2017-04-24 03:28:04 +00:00
$r = q ( " select iconfig.*, mid from iconfig left join item on iconfig.iid = item.id
2016-06-14 04:16:36 +00:00
where item . uid = % d and iconfig . cat = 'system' and iconfig . k = 'PDL' $sql_extra order by v asc " ,
2016-05-06 06:07:35 +00:00
intval ( $uid )
);
$arr = array ( 'channel_id' => $uid , 'current' => $current , 'entries' => $r );
2016-10-01 22:41:25 +00:00
call_hooks ( 'pdl_selector' , $arr );
2016-05-06 06:07:35 +00:00
$entries = $arr [ 'entries' ];
$current = $arr [ 'current' ];
$o .= '<select name="pdl_select" id="pdl_select" size="1">' ;
$entries [] = array ( 'title' => t ( 'Default' ), 'mid' => '' );
foreach ( $entries as $selection ) {
$selected = (( $selection == $current ) ? ' selected="selected" ' : '' );
2016-06-14 04:16:36 +00:00
$o .= " <option value= \" { $selection [ 'mid' ] } \" $selected > { $selection [ 'v' ] } </option> " ;
2016-05-06 06:07:35 +00:00
}
$o .= '</select>' ;
return $o ;
}
2016-10-01 22:41:25 +00:00
/**
* @ brief returns a one - dimensional array from a multi - dimensional array
2016-05-21 00:44:26 +00:00
* empty values are discarded
2016-10-01 22:41:25 +00:00
*
2016-05-21 00:44:26 +00:00
* example : print_r ( flatten_array_recursive ( array ( 'foo' , 'bar' , array ( 'baz' , 'blip' , array ( 'zob' , 'glob' )), '' , 'grip' )));
*
2016-10-01 22:41:25 +00:00
* Array ( [ 0 ] => foo [ 1 ] => bar [ 2 ] => baz [ 3 ] => blip [ 4 ] => zob [ 5 ] => glob [ 6 ] => grip )
2016-05-21 00:44:26 +00:00
*
2016-10-01 22:41:25 +00:00
* @ param array $arr multi - dimensional array
* @ return one - dimensional array
2016-05-21 00:44:26 +00:00
*/
function flatten_array_recursive ( $arr ) {
2018-12-29 01:54:11 +00:00
$ret = [];
if ( ! ( $arr && is_array ( $arr ))) {
2016-05-21 00:44:26 +00:00
return $ret ;
2018-12-29 01:54:11 +00:00
}
2016-05-21 00:44:26 +00:00
foreach ( $arr as $a ) {
if ( is_array ( $a )) {
$tmp = flatten_array_recursive ( $a );
if ( $tmp ) {
2016-10-01 22:41:25 +00:00
$ret = array_merge ( $ret , $tmp );
2016-05-21 00:44:26 +00:00
}
}
2019-02-25 05:36:06 +00:00
elseif ( isset ( $a )) {
2016-05-21 00:44:26 +00:00
$ret [] = $a ;
}
}
2016-10-01 22:41:25 +00:00
2016-05-21 00:44:26 +00:00
return ( $ret );
2016-10-01 22:41:25 +00:00
}
2016-06-16 02:44:15 +00:00
2016-10-01 22:41:25 +00:00
/**
* @ brief Highlight Text .
*
* @ param string $s Text to highlight
* @ param string $lang Which language should be highlighted
* @ return string
2017-08-30 03:47:49 +00:00
* Important : The returned text has the text pattern 'http' translated to '%eY9-!' which should be converted back
* after further processing . This was done to prevent oembed links from occurring inside code blocks .
* See include / bbcode . php
2016-10-01 22:41:25 +00:00
*/
2018-07-17 01:12:03 +00:00
function text_highlight ( $s , $lang , $options ) {
2016-06-16 02:44:15 +00:00
2016-06-16 03:25:19 +00:00
if ( $lang === 'js' )
$lang = 'javascript' ;
2016-06-17 21:58:03 +00:00
if ( $lang === 'json' ) {
$lang = 'javascript' ;
2016-10-01 22:41:25 +00:00
if ( ! strpos ( trim ( $s ), " \n " ))
2016-06-17 21:58:03 +00:00
$s = jindent ( $s );
}
2017-12-23 13:42:23 +00:00
$arr = [
'text' => $s ,
'language' => $lang ,
2018-07-17 01:12:03 +00:00
'options' => $options ,
'success' => false
2017-12-23 13:42:23 +00:00
];
/**
* @ hooks text_highlight
* * \e string \b text
* * \e string \b language
* * \e boolean \b success default false
*/
call_hooks ( 'text_highlight' , $arr );
2016-06-16 02:44:15 +00:00
2017-05-31 02:50:41 +00:00
if ( $arr [ 'success' ])
$o = $arr [ 'text' ];
else
$o = $s ;
2016-06-16 02:44:15 +00:00
2017-08-30 03:07:26 +00:00
$o = str_replace ( 'http' , '%eY9-!' , $o );
2016-10-01 22:41:25 +00:00
return ( '<code>' . $o . '</code>' );
2016-06-16 02:44:15 +00:00
}
2016-08-12 00:02:52 +00:00
// function to convert multi-dimensional array to xml
// create new instance of simplexml
// $xml = new SimpleXMLElement('<root/>');
// function callback
// array2XML($xml, $my_array);
// save as xml file
// echo (($xml->asXML('data.xml')) ? 'Your XML file has been generated successfully!' : 'Error generating XML file!');
function arrtoxml ( $root_elem , $arr ) {
2016-10-11 23:13:52 +00:00
$xml = new SimpleXMLElement ( '<?xml version="1.0" encoding="UTF-8"?><' . $root_elem . '></' . $root_elem . '>' , null , false );
2016-08-12 00:02:52 +00:00
array2XML ( $xml , $arr );
2016-10-01 22:41:25 +00:00
2016-08-12 00:02:52 +00:00
return $xml -> asXML ();
}
2016-10-01 22:41:25 +00:00
function array2XML ( $obj , $array ) {
foreach ( $array as $key => $value ) {
if ( is_numeric ( $key ))
$key = 'item' . $key ;
2016-08-12 00:02:52 +00:00
2016-10-01 22:41:25 +00:00
if ( is_array ( $value )) {
$node = $obj -> addChild ( $key );
array2XML ( $node , $value );
2017-05-29 02:17:46 +00:00
}
else {
2016-10-01 22:41:25 +00:00
$obj -> addChild ( $key , htmlspecialchars ( $value ));
}
}
2016-08-12 00:02:52 +00:00
}
2016-10-13 05:12:58 +00:00
2017-03-24 22:32:53 +00:00
/**
* @ brief Inserts an array into $table .
*
* @ TODO Why is this function in include / text . php ?
*
* @ param string $table
* @ param array $arr
2018-06-04 23:36:13 +00:00
* @ param array $binary_fields - fields which will be cleansed with dbescbin rather than dbesc ; this is critical for postgres
2017-03-24 22:32:53 +00:00
* @ return boolean | PDOStatement
*/
2018-06-04 23:36:13 +00:00
function create_table_from_array ( $table , $arr , $binary_fields = []) {
2016-10-13 05:12:58 +00:00
if ( ! ( $arr && $table ))
return false ;
2018-07-23 06:06:45 +00:00
$columns = db_columns ( $table );
2018-06-04 23:36:13 +00:00
$clean = [];
foreach ( $arr as $k => $v ) {
2018-07-23 06:06:45 +00:00
if ( ! in_array ( $k , $columns )) {
continue ;
}
2018-06-04 23:36:13 +00:00
$matches = false ;
if ( preg_match ( '/([^a-zA-Z0-9\-\_\.])/' , $k , $matches )) {
return false ;
}
if ( in_array ( $k , $binary_fields )) {
$clean [ $k ] = dbescbin ( $v );
}
else {
$clean [ $k ] = dbesc ( $v );
}
2016-10-13 07:30:41 +00:00
}
2018-06-04 23:36:13 +00:00
$r = dbq ( " INSERT INTO " . TQUOT . $table . TQUOT . " ( " . TQUOT
. implode ( TQUOT . ', ' . TQUOT , array_keys ( $clean ))
. TQUOT . " ) VALUES (' "
. implode ( " ', ' " , array_values ( $clean ))
. " ') "
);
2016-10-13 05:12:58 +00:00
2016-10-01 22:41:25 +00:00
return $r ;
2016-12-14 04:01:38 +00:00
}
2017-05-31 01:36:19 +00:00
function share_shield ( $m ) {
return str_replace ( $m [ 1 ], '!=+=+=!' . base64url_encode ( $m [ 1 ]) . '=+!=+!=' , $m [ 0 ]);
}
function share_unshield ( $m ) {
$x = str_replace ( array ( '!=+=+=!' , '=+!=+!=' ), array ( '' , '' ), $m [ 1 ]);
return str_replace ( $m [ 1 ], base64url_decode ( $x ), $m [ 0 ]);
}
2016-12-14 04:01:38 +00:00
function cleanup_bbcode ( $body ) {
/**
2020-11-22 22:10:58 +00:00
* fix naked links by passing through a callback to see if this is a zot site of some kind
2016-12-14 04:01:38 +00:00
* ( already known to us ) which will get a zrl , otherwise link with url , add bookmark tag to both .
* First protect any url inside certain bbcode tags so we don ' t double link it .
*/
2021-04-13 04:27:33 +00:00
// markdown code blocks are slightly more complicated
$body = preg_replace_callback ( '#(^|\n)([`~]{3,})(?: *\.?([a-zA-Z0-9\-.]+))?\n+([\s\S]+?)\n+\2(\n|$)#' , function ( $match ) {
return $match [ 1 ] . $match [ 2 ] . " \n " . bb_code_protect ( $match [ 4 ]) . " \n " . $match [ 2 ] . (( $match [ 5 ]) ? $match [ 5 ] : " \n " );
}, $body );
2016-12-14 04:01:38 +00:00
$body = preg_replace_callback ( '/\[code(.*?)\[\/(code)\]/ism' , '\red_escape_codeblock' , $body );
$body = preg_replace_callback ( '/\[url(.*?)\[\/(url)\]/ism' , '\red_escape_codeblock' , $body );
$body = preg_replace_callback ( '/\[zrl(.*?)\[\/(zrl)\]/ism' , '\red_escape_codeblock' , $body );
2019-11-06 05:34:47 +00:00
$body = preg_replace_callback ( '/\[svg(.*?)\[\/(svg)\]/ism' , '\red_escape_codeblock' , $body );
2021-04-06 20:31:44 +00:00
$body = preg_replace_callback ( '/\[img(.*?)\[\/(img)\]/ism' , '\red_escape_codeblock' , $body );
$body = preg_replace_callback ( '/\[zmg(.*?)\[\/(zmg)\]/ism' , '\red_escape_codeblock' , $body );
2016-12-14 04:01:38 +00:00
2020-11-22 22:15:17 +00:00
$body = preg_replace_callback ( " /([^ \ ] \ =' " . '"' . " \ ; \ / \ { \ (]|^| \ # \ ^)(https? \ : \ / \ /[a-zA-Z0-9 \ pL \ : \ / \ - \ ? \ & \ ; \ . \ = \ @ \ _ \ ~ \ # \ % \$ \ ! \\ + \ , \ ( \ )]+)/ismu " , '\nakedoembed' , $body );
2018-08-14 06:11:10 +00:00
2020-11-22 22:15:17 +00:00
$body = preg_replace_callback ( " /([^ \ ] \ =' " . '"' . " \ ; \ / \ { \ (]|^| \ # \ ^)(https? \ : \ / \ /[a-zA-Z0-9 \ pL \ : \ / \ - \ ? \ & \ ; \ . \ = \ @ \ _ \ ~ \ # \ % \$ \ ! \\ + \ , \ ( \ )]+)/ismu " , '\red_zrl_callback' , $body );
2016-12-14 04:01:38 +00:00
2018-08-14 06:11:10 +00:00
2016-12-14 04:01:38 +00:00
$body = preg_replace_callback ( '/\[\$b64code(.*?)\[\/(code)\]/ism' , '\red_unescape_codeblock' , $body );
2020-06-27 21:50:15 +00:00
$body = preg_replace_callback ( '/\[\$b64url(.*?)\[\/(url)\]/ism' , '\red_unescape_codeblock' , $body );
$body = preg_replace_callback ( '/\[\$b64zrl(.*?)\[\/(zrl)\]/ism' , '\red_unescape_codeblock' , $body );
2019-11-06 05:34:47 +00:00
$body = preg_replace_callback ( '/\[\$b64svg(.*?)\[\/(svg)\]/ism' , '\red_unescape_codeblock' , $body );
2021-04-06 20:31:44 +00:00
$body = preg_replace_callback ( '/\[\$b64img(.*?)\[\/(img)\]/ism' , '\red_unescape_codeblock' , $body );
$body = preg_replace_callback ( '/\[\$b64zmg(.*?)\[\/(zmg)\]/ism' , '\red_unescape_codeblock' , $body );
2016-12-14 04:01:38 +00:00
2021-04-13 04:27:33 +00:00
$body = bb_code_unprotect ( $body );
2016-12-14 04:01:38 +00:00
// fix any img tags that should be zmg
$body = preg_replace_callback ( '/\[img(.*?)\](.*?)\[\/img\]/ism' , '\red_zrlify_img_callback' , $body );
$body = bb_translate_video ( $body );
/**
* Fold multi - line [ code ] sequences
*/
$body = preg_replace ( '/\[\/code\]\s*\[code\]/ism' , " \n " , $body );
return $body ;
}
2017-01-05 22:17:56 +00:00
2017-01-19 23:37:30 +00:00
function gen_link_id ( $mid ) {
if ( strpbrk ( $mid , ':/&?<>"\'' ) !== false )
return 'b64.' . base64url_encode ( $mid );
return $mid ;
}
2017-01-31 23:28:25 +00:00
2017-01-05 22:17:56 +00:00
// callback for array_walk
function array_trim ( & $v , $k ) {
$v = trim ( $v );
2017-01-16 03:51:14 +00:00
}
function array_escape_tags ( & $v , $k ) {
$v = escape_tags ( $v );
2017-01-19 23:37:30 +00:00
}
2017-03-22 03:11:48 +00:00
function ellipsify ( $s , $maxlen ) {
if ( $maxlen & 1 )
$maxlen -- ;
if ( $maxlen < 4 )
$maxlen = 4 ;
if ( mb_strlen ( $s ) < $maxlen )
return $s ;
return mb_substr ( $s , 0 , $maxlen / 2 ) . '...' . mb_substr ( $s , mb_strlen ( $s ) - ( $maxlen / 2 ));
2017-05-04 22:23:57 +00:00
}
2017-10-09 22:13:25 +00:00
function purify_filename ( $s ) {
if (( $s [ 0 ] === '.' ) || strpos ( $s , '/' ) !== false )
return '' ;
return $s ;
}
2018-02-02 01:17:23 +00:00
2018-03-02 20:41:50 +00:00
// callback for sorting the settings/featured entries.
2018-02-02 01:17:23 +00:00
2018-03-02 20:41:50 +00:00
function featured_sort ( $a , $b ) {
$s1 = substr ( $a , strpos ( $a , 'id=' ), 20 );
$s2 = substr ( $b , strpos ( $b , 'id=' ), 20 );
return ( strcmp ( $s1 , $s2 ));
}
2018-03-13 03:54:55 +00:00
2020-02-17 22:58:21 +00:00
function unpunify ( $s ) {
if ( function_exists ( 'idn_to_utf8' )) {
return idn_to_utf8 ( $s );
}
return $s ;
}
2018-04-24 02:10:35 +00:00
2018-03-13 03:54:55 +00:00
function punify ( $s ) {
2020-02-17 22:58:21 +00:00
if ( function_exists ( 'idn_to_ascii' )) {
return idn_to_ascii ( $s );
}
return $s ;
2018-03-13 03:54:55 +00:00
}
2018-04-26 01:41:19 +00:00
function unique_multidim_array ( $array , $key ) {
2021-03-15 05:10:44 +00:00
$temp_array = [];
2018-04-26 01:41:19 +00:00
$i = 0 ;
2021-03-15 05:10:44 +00:00
$key_array = [];
2018-04-26 01:41:19 +00:00
foreach ( $array as $val ) {
if ( ! in_array ( $val [ $key ], $key_array )) {
$key_array [ $i ] = $val [ $key ];
$temp_array [ $i ] = $val ;
}
$i ++ ;
}
return $temp_array ;
2018-06-04 00:59:41 +00:00
2018-05-04 11:54:12 +00:00
}
2018-05-18 10:09:38 +00:00
2019-04-29 04:17:04 +00:00
// Much prettier formatting than print_r()
2019-05-03 06:42:41 +00:00
// This assumes the output will be a web page and escapes angle-chars appropriately by default.
2018-05-18 10:09:38 +00:00
2019-04-29 04:17:04 +00:00
function print_array ( $arr , $escape = true , $level = 0 ) {
2018-05-18 10:09:38 +00:00
$o = EMPTY_STR ;
$tabs = EMPTY_STR ;
if ( is_array ( $arr )) {
for ( $x = 0 ; $x <= $level ; $x ++ ) {
$tabs .= " \t " ;
}
$o .= '[' . " \n " ;
if ( count ( $arr )) {
foreach ( $arr as $k => $v ) {
if ( is_array ( $v )) {
2019-04-29 04:17:04 +00:00
$o .= $tabs . '[' . (( $escape ) ? escape_tags ( $k ) : $k ) . '] => ' . print_array ( $v , $escape , $level + 1 ) . " \n " ;
2018-05-18 10:09:38 +00:00
}
else {
2019-04-29 04:17:04 +00:00
$o .= $tabs . '[' . (( $escape ) ? escape_tags ( $k ) : $k ) . '] => ' . print_val ( $v , $escape ) . " , \n " ;
2018-05-18 10:09:38 +00:00
}
}
}
$o .= substr ( $tabs , 0 , - 1 ) . ']' . (( $level ) ? ',' : ';' ) . " \n " ;
return $o ;
}
}
2019-04-29 04:17:04 +00:00
function print_val ( $v , $escape = true ) {
2019-05-03 06:42:41 +00:00
if ( is_bool ( $v )) {
if ( $v ) {
return 'true' ;
}
2018-05-18 10:09:38 +00:00
return 'false' ;
}
2019-05-03 06:42:41 +00:00
if ( is_string ( $v )) {
2019-04-29 04:17:04 +00:00
return " ' " . (( $escape ) ? escape_tags ( $v ) : $v ) . " ' " ;
2018-05-18 10:09:38 +00:00
}
return $v ;
2018-05-29 02:42:40 +00:00
}
function array_path_exists ( $str , $arr ) {
2020-01-14 21:25:22 +00:00
if ( ! ( $arr && is_array ( $arr ))) {
2019-05-03 06:42:41 +00:00
return false ;
}
2018-05-29 02:42:40 +00:00
$ptr = $arr ;
$search = explode ( '/' , $str );
2019-05-03 06:42:41 +00:00
if ( $search ) {
foreach ( $search as $s ) {
2020-07-08 00:54:08 +00:00
if ( $ptr && is_array ( $ptr ) && array_key_exists ( $s , $ptr )) {
2018-05-29 02:42:40 +00:00
$ptr = $ptr [ $s ];
}
else {
return false ;
}
}
return true ;
}
return false ;
2018-06-04 00:58:24 +00:00
}
2018-05-30 12:02:58 +00:00
2019-03-05 07:51:47 +00:00
function get_forum_channels ( $uid , $collections = 0 ) {
2018-05-30 12:02:58 +00:00
2019-05-06 04:06:02 +00:00
if ( ! $uid )
2018-06-02 20:11:11 +00:00
return ;
2019-05-06 04:06:02 +00:00
if ( $collections ) {
2019-03-05 07:51:47 +00:00
$pagetype = $collections ;
}
else {
$pagetype = 1 ;
}
2021-04-30 04:24:30 +00:00
$r = q ( " select abook_id, xchan_hash, xchan_network, xchan_name, xchan_url, xchan_photo_s from abook left join xchan on abook_xchan = xchan_hash where xchan_deleted = 0 and abook_channel = %d and abook_pending = 0 and abook_ignored = 0 and abook_blocked = 0 and abook_archived = 0 and xchan_type = %d order by xchan_name " ,
2019-03-05 07:51:47 +00:00
intval ( $uid ),
intval ( $pagetype )
2018-06-02 20:11:11 +00:00
);
return $r ;
2018-05-30 12:02:58 +00:00
}
2018-11-21 02:55:33 +00:00
function serialise ( $x ) {
return (( is_array ( $x )) ? 'json:' . json_encode ( $x ) : $x );
}
function unserialise ( $x ) {
2019-02-15 04:44:34 +00:00
if ( is_array ( $x )) {
return $x ;
}
2018-11-21 05:50:41 +00:00
$y = (( substr ( $x , 0 , 5 ) === 'json:' ) ? json_decode ( substr ( $x , 5 ), true ) : '' );
return (( is_array ( $y )) ? $y : $x );
2019-04-05 02:55:17 +00:00
}
function obscurify ( $s ) {
return str_rot47 ( base64url_encode ( $s ));
}
function unobscurify ( $s ) {
return base64url_decode ( str_rot47 ( $s ));
}
2019-11-06 05:34:47 +00:00
function svg2bb ( $s ) {
$s = preg_replace ( " / \ <text (.*?) \ >(.*?) \ <(.*?) \ < \ /text \ >/ " , '<text $1>$2<$3</text>' , $s );
$s = preg_replace ( " / \ <text (.*?) \ >(.*?) \ >(.*?) \ < \ /text \ >/ " , '<text $1>$2>$3</text>' , $s );
2019-11-06 23:42:27 +00:00
$s = preg_replace ( " / \ <text (.*?) \ >(.*?) \ [(.*?) \ < \ /text \ >/ " , '<text $1>$2[$3</text>' , $s );
$s = preg_replace ( " / \ <text (.*?) \ >(.*?) \ ](.*?) \ < \ /text \ >/ " , '<text $1>$2]$3</text>' , $s );
2019-11-06 10:15:38 +00:00
$s = utf8_encode ( $s );
2019-11-06 05:34:47 +00:00
$purify = new SvgSanitizer ();
if ( $purify -> loadXML ( $s )) {
$purify -> sanitize ();
$output = $purify -> saveSVG ();
$output = preg_replace ( " / \ < \ ?xml(.*?) \ >/ " , '' , $output );
2019-11-06 10:15:38 +00:00
$output = preg_replace ( " / \ < \ ! \ - \ -(.*?) \ - \ - \ >/ " , '' , $output );
2019-11-06 05:34:47 +00:00
$output = str_replace ([ '<' , '>' ],[ '[' , ']' ], $output );
return $output ;
}
2019-11-06 10:15:38 +00:00
return EMPTY_STR ;
}
2020-09-26 00:59:45 +00:00
// Takes something that looks like a phone number and returns a string suitable for tel: protocol or false.
2020-09-26 00:36:55 +00:00
function is_phone_number ( $s ) {
2020-09-26 00:59:45 +00:00
$ext = substr ( $s , strpos ( $s , 'x' ) + 1 );
if ( ! $ext ) {
$ext = substr ( $s , strpos ( $s , 'X' ) + 1 );
}
if ( $ext && ctype_digit ( $ext )) {
$rext = ';ext=' . $ext ;
$s = str_replace ([ 'x' . $ext , 'X' . $ext ],[ '' , '' ], $s );
}
else {
$ext = EMPTY_STR ;
}
2020-09-26 00:36:55 +00:00
$s = str_replace ([ '(' , ')' , ' ' , '-' , '+' ],[ '' , '' , '' , '' , '' ], $s );
2020-09-26 00:59:45 +00:00
return (( ctype_digit ( $s )) ? $s . $rext : false );
2020-09-26 00:36:55 +00:00
}
2021-04-15 04:23:01 +00:00
/**
* fnmatch seems a bit unpredictable , so use this instead .
*/
function wildmat ( $pattern , $string ) {
return preg_match ( " #^ " . strtr ( preg_quote ( $pattern , '#' ), [ '\*' => '.*' , '\?' => '.' , '\[' => '[' , '\]' => ']' ] ) . " $ #i " , $string );
}