EGroupware /
egroupware
| 1 | <?php |
||||
| 2 | /** |
||||
| 3 | * EGroupware - Document merge print |
||||
| 4 | * |
||||
| 5 | * @link http://www.egroupware.org |
||||
| 6 | * @author Ralf Becker <RalfBecker-AT-outdoor-training.de> |
||||
| 7 | * @package api |
||||
| 8 | * @subpackage storage |
||||
| 9 | * @copyright (c) 2007-16 by Ralf Becker <RalfBecker-AT-outdoor-training.de> |
||||
| 10 | * @license http://opensource.org/licenses/gpl-license.php GPL - GNU General Public License |
||||
| 11 | * @version $Id$ |
||||
| 12 | */ |
||||
| 13 | |||||
| 14 | namespace EGroupware\Api\Storage; |
||||
| 15 | |||||
| 16 | use EGroupware\Api; |
||||
| 17 | use EGroupware\Stylite; |
||||
|
0 ignored issues
–
show
|
|||||
| 18 | |||||
| 19 | use DOMDocument; |
||||
| 20 | use XSLTProcessor; |
||||
| 21 | use tidy; |
||||
| 22 | use ZipArchive; |
||||
| 23 | |||||
| 24 | // explicit import old, non-namespaced phpgwapi classes |
||||
| 25 | use uiaccountsel; |
||||
|
0 ignored issues
–
show
The type
uiaccountsel was not found. Maybe you did not declare it correctly or list all dependencies?
The issue could also be caused by a filter entry in the build configuration.
If the path has been excluded in your configuration, e.g. filter:
dependency_paths: ["lib/*"]
For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths Loading history...
|
|||||
| 26 | |||||
| 27 | /** |
||||
| 28 | * Document merge print |
||||
| 29 | * |
||||
| 30 | * @todo move apply_styles call into merge_string to run for each entry merged and not all together to lower memory requirements |
||||
| 31 | */ |
||||
| 32 | abstract class Merge |
||||
| 33 | { |
||||
| 34 | /** |
||||
| 35 | * Instance of the addressbook_bo class |
||||
|
0 ignored issues
–
show
|
|||||
| 36 | * |
||||
| 37 | * @var addressbook_bo |
||||
| 38 | */ |
||||
| 39 | var $contacts; |
||||
| 40 | |||||
| 41 | /** |
||||
| 42 | * Datetime format according to user preferences |
||||
| 43 | * |
||||
| 44 | * @var string |
||||
| 45 | */ |
||||
| 46 | var $datetime_format = 'Y-m-d H:i'; |
||||
| 47 | |||||
| 48 | /** |
||||
| 49 | * Fields that are to be treated as datetimes, when merged into spreadsheets |
||||
| 50 | */ |
||||
| 51 | var $date_fields = array(); |
||||
| 52 | |||||
| 53 | /** |
||||
| 54 | * Mimetype of document processed by merge |
||||
| 55 | * |
||||
| 56 | * @var string |
||||
| 57 | */ |
||||
| 58 | var $mimetype; |
||||
| 59 | |||||
| 60 | /** |
||||
| 61 | * Plugins registered by extending class to create a table with multiple rows |
||||
| 62 | * |
||||
| 63 | * $$table/$plugin$$ ... $$endtable$$ |
||||
| 64 | * |
||||
| 65 | * Callback returns replacements for row $n (stringing with 0) or null if no further rows |
||||
| 66 | * |
||||
| 67 | * @var array $plugin => array callback($plugin,$id,$n) |
||||
| 68 | */ |
||||
| 69 | var $table_plugins = array(); |
||||
| 70 | |||||
| 71 | /** |
||||
| 72 | * Export limit in number of entries or some non-numerical value, if no export allowed at all, empty means no limit |
||||
| 73 | * |
||||
| 74 | * Set by constructor to $GLOBALS[egw_info][server][export_limit] |
||||
| 75 | * |
||||
| 76 | * @var int|string |
||||
| 77 | */ |
||||
| 78 | public $export_limit; |
||||
| 79 | |||||
| 80 | |||||
| 81 | /** |
||||
| 82 | * Configuration for HTML Tidy to clean up any HTML content that is kept |
||||
| 83 | */ |
||||
| 84 | public static $tidy_config = array( |
||||
| 85 | 'output-xml' => true, // Entity encoding |
||||
| 86 | 'show-body-only' => true, |
||||
| 87 | 'output-encoding' => 'utf-8', |
||||
| 88 | 'input-encoding' => 'utf-8', |
||||
| 89 | 'quote-ampersand' => false, // Prevent double encoding |
||||
| 90 | 'quote-nbsp' => true, // XSLT can handle spaces easier |
||||
| 91 | 'preserve-entities' => true, |
||||
| 92 | 'wrap' => 0, // Wrapping can break output |
||||
| 93 | ); |
||||
| 94 | |||||
| 95 | /** |
||||
| 96 | * Parse HTML styles into target document style, if possible |
||||
| 97 | * |
||||
| 98 | * Apps not using html in there own data should set this with Customfields::use_html($app) |
||||
| 99 | * to avoid memory and time consuming html processing. |
||||
| 100 | */ |
||||
| 101 | protected $parse_html_styles = true; |
||||
| 102 | |||||
| 103 | /** |
||||
| 104 | * Enable this to report memory_usage to error_log |
||||
| 105 | * |
||||
| 106 | * @var boolean |
||||
| 107 | */ |
||||
| 108 | public $report_memory_usage = false; |
||||
| 109 | |||||
| 110 | /** |
||||
| 111 | * Save sent emails. Used when merge template is an email. Default is true, |
||||
| 112 | * to save sent emails in your sent folder. |
||||
| 113 | * |
||||
| 114 | * @var boolean |
||||
| 115 | */ |
||||
| 116 | public $keep_emails = true; |
||||
| 117 | |||||
| 118 | /** |
||||
| 119 | * Constructor |
||||
| 120 | */ |
||||
| 121 | function __construct() |
||||
| 122 | { |
||||
| 123 | // Common messages are in preferences |
||||
| 124 | Api\Translation::add_app('preferences'); |
||||
| 125 | // All contact fields are in addressbook |
||||
| 126 | Api\Translation::add_app('addressbook'); |
||||
| 127 | |||||
| 128 | $this->contacts = new Api\Contacts(); |
||||
|
0 ignored issues
–
show
It seems like
new EGroupware\Api\Contacts() of type EGroupware\Api\Contacts is incompatible with the declared type EGroupware\Api\Storage\addressbook_bo of property $contacts.
Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property. Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property.. Loading history...
|
|||||
| 129 | |||||
| 130 | $this->datetime_format = $GLOBALS['egw_info']['user']['preferences']['common']['dateformat'].' '. |
||||
| 131 | ($GLOBALS['egw_info']['user']['preferences']['common']['timeformat']==12 ? 'h:i a' : 'H:i'); |
||||
| 132 | |||||
| 133 | $this->export_limit = self::getExportLimit(); |
||||
|
0 ignored issues
–
show
It seems like
self::getExportLimit() can also be of type false. However, the property $export_limit is declared as type integer|string. Maybe add an additional type check?
Our type inference engine has found a suspicous assignment of a value to a property. This check raises an issue when a value that can be of a mixed type is assigned to a property that is type hinted more strictly. For example, imagine you have a variable Either this assignment is in error or a type check should be added for that assignment. class Id
{
public $id;
public function __construct($id)
{
$this->id = $id;
}
}
class Account
{
/** @var Id $id */
public $id;
}
$account_id = false;
if (starsAreRight()) {
$account_id = new Id(42);
}
$account = new Account();
if ($account instanceof Id)
{
$account->id = $account_id;
}
Loading history...
|
|||||
| 134 | } |
||||
| 135 | |||||
| 136 | /** |
||||
| 137 | * Hook returning options for export_limit_excepted groups |
||||
| 138 | * |
||||
| 139 | * @param array $config |
||||
| 140 | */ |
||||
| 141 | public static function hook_export_limit_excepted($config) |
||||
| 142 | { |
||||
| 143 | $accountsel = new uiaccountsel(); |
||||
| 144 | |||||
| 145 | return '<input type="hidden" value="" name="newsettings[export_limit_excepted]" />'. |
||||
| 146 | $accountsel->selection('newsettings[export_limit_excepted]','export_limit_excepted',$config['export_limit_excepted'],'both',4); |
||||
| 147 | } |
||||
| 148 | |||||
| 149 | /** |
||||
| 150 | * Get all replacements, must be implemented in extending class |
||||
| 151 | * |
||||
| 152 | * Can use eg. the following high level methods: |
||||
| 153 | * - contact_replacements($contact_id,$prefix='') |
||||
| 154 | * - format_datetime($time,$format=null) |
||||
| 155 | * |
||||
| 156 | * @param int $id id of entry |
||||
| 157 | * @param string &$content=null content to create some replacements only if they are use |
||||
| 158 | * @return array|boolean array with replacements or false if entry not found |
||||
| 159 | */ |
||||
| 160 | abstract protected function get_replacements($id,&$content=null); |
||||
| 161 | |||||
| 162 | /** |
||||
| 163 | * Return if merge-print is implemented for given mime-type (and/or extension) |
||||
| 164 | * |
||||
| 165 | * @param string $mimetype eg. text/plain |
||||
| 166 | * @param string $extension only checked for applications/msword and .rtf |
||||
| 167 | */ |
||||
| 168 | static public function is_implemented($mimetype,$extension=null) |
||||
| 169 | { |
||||
| 170 | static $zip_available=null; |
||||
| 171 | if (is_null($zip_available)) |
||||
| 172 | { |
||||
| 173 | $zip_available = check_load_extension('zip') && |
||||
| 174 | class_exists('ZipArchive'); // some PHP has zip extension, but no ZipArchive (eg. RHEL5!) |
||||
| 175 | } |
||||
| 176 | switch ($mimetype) |
||||
| 177 | { |
||||
| 178 | case 'application/msword': |
||||
| 179 | if (strtolower($extension) != '.rtf') break; |
||||
| 180 | case 'application/rtf': |
||||
| 181 | case 'text/rtf': |
||||
| 182 | return true; // rtf files |
||||
| 183 | case 'application/vnd.oasis.opendocument.text': // oo text |
||||
| 184 | case 'application/vnd.oasis.opendocument.spreadsheet': // oo spreadsheet |
||||
| 185 | case 'application/vnd.oasis.opendocument.presentation': |
||||
| 186 | case 'application/vnd.oasis.opendocument.text-template': |
||||
| 187 | case 'application/vnd.oasis.opendocument.spreadsheet-template': |
||||
| 188 | case 'application/vnd.oasis.opendocument.presentation-template': |
||||
| 189 | if (!$zip_available) break; |
||||
| 190 | return true; // open office write xml files |
||||
| 191 | case 'application/vnd.openxmlformats-officedocument.wordprocessingml.document': // ms word 2007 xml format |
||||
| 192 | case 'application/vnd.openxmlformats-officedocument.wordprocessingml.d': // mimetypes in vfs are limited to 64 chars |
||||
| 193 | case 'application/vnd.ms-word.document.macroenabled.12': |
||||
| 194 | case 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet': // ms excel 2007 xml format |
||||
| 195 | case 'application/vnd.openxmlformats-officedocument.spreadsheetml.shee': |
||||
| 196 | case 'application/vnd.ms-excel.sheet.macroenabled.12': |
||||
| 197 | if (!$zip_available) break; |
||||
| 198 | return true; // ms word xml format |
||||
| 199 | case 'application/xml': |
||||
| 200 | return true; // alias for text/xml, eg. ms office 2003 word format |
||||
| 201 | case 'message/rfc822': |
||||
| 202 | return true; // ToDo: check if you are theoretical able to send mail |
||||
| 203 | case 'application/x-yaml': |
||||
| 204 | return true; // yaml file, plain text with marginal syntax support for multiline replacements |
||||
| 205 | default: |
||||
| 206 | if (substr($mimetype,0,5) == 'text/') |
||||
| 207 | { |
||||
| 208 | return true; // text files |
||||
| 209 | } |
||||
| 210 | break; |
||||
| 211 | } |
||||
| 212 | return false; |
||||
| 213 | |||||
| 214 | // As browsers not always return correct mime types, one could use a negative list instead |
||||
| 215 | //return !($mimetype == Api\Vfs::DIR_MIME_TYPE || substr($mimetype,0,6) == 'image/'); |
||||
| 216 | } |
||||
| 217 | |||||
| 218 | /** |
||||
| 219 | * Return replacements for a contact |
||||
| 220 | * |
||||
| 221 | * @param int|string|array $contact contact-array or id |
||||
| 222 | * @param string $prefix ='' prefix like eg. 'user' |
||||
| 223 | * @param boolean $ignore_acl =false true: no acl check |
||||
| 224 | * @return array |
||||
| 225 | */ |
||||
| 226 | public function contact_replacements($contact,$prefix='',$ignore_acl=false, &$content = '') |
||||
| 227 | { |
||||
| 228 | if (!is_array($contact)) |
||||
| 229 | { |
||||
| 230 | $contact = $this->contacts->read($contact, $ignore_acl); |
||||
| 231 | } |
||||
| 232 | if (!is_array($contact)) return array(); |
||||
| 233 | |||||
| 234 | $replacements = array(); |
||||
| 235 | foreach(array_keys($this->contacts->contact_fields) as $name) |
||||
| 236 | { |
||||
| 237 | $value = $contact[$name]; |
||||
| 238 | switch($name) |
||||
| 239 | { |
||||
| 240 | case 'created': case 'modified': |
||||
| 241 | if($value) $value = Api\DateTime::to($value); |
||||
| 242 | break; |
||||
| 243 | case 'bday': |
||||
| 244 | if ($value) |
||||
| 245 | { |
||||
| 246 | try { |
||||
| 247 | $value = Api\DateTime::to($value, true); |
||||
| 248 | } |
||||
| 249 | catch (\Exception $e) { |
||||
| 250 | unset($e); // ignore exception caused by wrongly formatted date |
||||
| 251 | } |
||||
| 252 | } |
||||
| 253 | break; |
||||
| 254 | case 'owner': case 'creator': case 'modifier': |
||||
| 255 | $value = Api\Accounts::username($value); |
||||
| 256 | break; |
||||
| 257 | case 'cat_id': |
||||
| 258 | if ($value) |
||||
| 259 | { |
||||
| 260 | // if cat-tree is displayed, we return a full category path not just the name of the cat |
||||
| 261 | $use = $GLOBALS['egw_info']['server']['cat_tab'] == 'Tree' ? 'path' : 'name'; |
||||
| 262 | $cats = array(); |
||||
| 263 | foreach(is_array($value) ? $value : explode(',',$value) as $cat_id) |
||||
| 264 | { |
||||
| 265 | $cats[] = $GLOBALS['egw']->categories->id2name($cat_id,$use); |
||||
| 266 | } |
||||
| 267 | $value = implode(', ',$cats); |
||||
| 268 | } |
||||
| 269 | break; |
||||
| 270 | case 'jpegphoto': // returning a link might make more sense then the binary photo |
||||
| 271 | if ($contact['photo']) |
||||
| 272 | { |
||||
| 273 | $value = Api\Framework::getUrl(Api\Framework::link('/index.php',$contact['photo'])); |
||||
| 274 | } |
||||
| 275 | break; |
||||
| 276 | case 'tel_prefer': |
||||
| 277 | if ($value && $contact[$value]) |
||||
| 278 | { |
||||
| 279 | $value = $contact[$value]; |
||||
| 280 | } |
||||
| 281 | break; |
||||
| 282 | case 'account_id': |
||||
| 283 | if ($value) |
||||
| 284 | { |
||||
| 285 | $replacements['$$'.($prefix ? $prefix.'/':'').'account_lid$$'] = $GLOBALS['egw']->accounts->id2name($value); |
||||
| 286 | } |
||||
| 287 | break; |
||||
| 288 | } |
||||
| 289 | if ($name != 'photo') $replacements['$$'.($prefix ? $prefix.'/':'').$name.'$$'] = $value; |
||||
| 290 | } |
||||
| 291 | // set custom fields, should probably go to a general method all apps can use |
||||
| 292 | // need to load all cfs for $ignore_acl=true |
||||
| 293 | foreach($ignore_acl ? Customfields::get('addressbook', true) : $this->contacts->customfields as $name => $field) |
||||
| 294 | { |
||||
| 295 | $name = '#'.$name; |
||||
| 296 | if(!$contact[$name]) |
||||
| 297 | { |
||||
| 298 | $replacements['$$'.($prefix ? $prefix.'/':'').$name.'$$'] = ''; |
||||
| 299 | continue; |
||||
| 300 | } |
||||
| 301 | // Format date cfs per user Api\Preferences |
||||
| 302 | if($this->mimetype !== 'application/x-yaml' && $contact[$name] && |
||||
| 303 | ($field['type'] == 'date' || $field['type'] == 'date-time')) |
||||
| 304 | { |
||||
| 305 | $this->date_fields[] = '#'.$name; |
||||
| 306 | $replacements['$$'.($prefix ? $prefix.'/':'').$name.'$$'] = Api\DateTime::to($contact[$name], $field['type'] == 'date' ? true : ''); |
||||
| 307 | } |
||||
| 308 | $replacements['$$'.($prefix ? $prefix.'/':'').$name.'$$'] = |
||||
| 309 | // use raw data for yaml, no user-preference specific formatting |
||||
| 310 | $this->mimetype == 'application/x-yaml' || $field['type'] == 'htmlarea' ? (string)$contact[$name] : |
||||
| 311 | Customfields::format($field, (string)$contact[$name]); |
||||
| 312 | } |
||||
| 313 | |||||
| 314 | if($content && strpos($content, '$$#') !== FALSE) |
||||
| 315 | { |
||||
| 316 | $this->cf_link_to_expand($contact, $content, $replacements, 'addressbook'); |
||||
| 317 | } |
||||
| 318 | |||||
| 319 | // Add in extra cat field |
||||
| 320 | $cats = array(); |
||||
| 321 | foreach(is_array($contact['cat_id']) ? $contact['cat_id'] : explode(',',$contact['cat_id']) as $cat_id) |
||||
| 322 | { |
||||
| 323 | if(!$cat_id) continue; |
||||
| 324 | if($GLOBALS['egw']->categories->id2name($cat_id,'main') != $cat_id) |
||||
| 325 | { |
||||
| 326 | $path = explode(' / ', $GLOBALS['egw']->categories->id2name($cat_id, 'path')); |
||||
| 327 | unset($path[0]); // Drop main |
||||
| 328 | $cats[$GLOBALS['egw']->categories->id2name($cat_id,'main')][] = implode(' / ', $path); |
||||
| 329 | } elseif($cat_id) { |
||||
| 330 | $cats[$cat_id] = array(); |
||||
| 331 | } |
||||
| 332 | } |
||||
| 333 | foreach($cats as $main => $cat) { |
||||
| 334 | $replacements['$$'.($prefix ? $prefix.'/':'').'categories$$'] .= $GLOBALS['egw']->categories->id2name($main,'name') |
||||
| 335 | . (count($cat) > 0 ? ': ' : '') . implode(', ', $cats[$main]) . "\n"; |
||||
| 336 | } |
||||
| 337 | return $replacements; |
||||
| 338 | } |
||||
| 339 | |||||
| 340 | /** |
||||
| 341 | * Get links for the given record |
||||
| 342 | * |
||||
| 343 | * Uses egw_link system to get link titles |
||||
| 344 | * |
||||
| 345 | * @param app Name of current app |
||||
|
0 ignored issues
–
show
The type
EGroupware\Api\Storage\Name was not found. Maybe you did not declare it correctly or list all dependencies?
The issue could also be caused by a filter entry in the build configuration.
If the path has been excluded in your configuration, e.g. filter:
dependency_paths: ["lib/*"]
For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths Loading history...
|
|||||
| 346 | * @param id ID of current entry |
||||
|
0 ignored issues
–
show
The type
EGroupware\Api\Storage\ID was not found. Maybe you did not declare it correctly or list all dependencies?
The issue could also be caused by a filter entry in the build configuration.
If the path has been excluded in your configuration, e.g. filter:
dependency_paths: ["lib/*"]
For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths Loading history...
|
|||||
| 347 | * @param only_app Restrict links to only given application |
||||
|
0 ignored issues
–
show
The type
EGroupware\Api\Storage\Restrict was not found. Maybe you did not declare it correctly or list all dependencies?
The issue could also be caused by a filter entry in the build configuration.
If the path has been excluded in your configuration, e.g. filter:
dependency_paths: ["lib/*"]
For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths Loading history...
|
|||||
| 348 | * @param exclude Exclude links to these applications |
||||
|
0 ignored issues
–
show
The type
EGroupware\Api\Storage\Exclude was not found. Maybe you did not declare it correctly or list all dependencies?
The issue could also be caused by a filter entry in the build configuration.
If the path has been excluded in your configuration, e.g. filter:
dependency_paths: ["lib/*"]
For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths Loading history...
|
|||||
| 349 | * @param style String One of: |
||||
| 350 | * 'title' - plain text, just the title of the link |
||||
| 351 | * 'link' - URL to the entry |
||||
| 352 | * 'href' - HREF tag wrapped around the title |
||||
| 353 | */ |
||||
| 354 | protected function get_links($app, $id, $only_app='', $exclude = array(), $style = 'title') |
||||
| 355 | { |
||||
| 356 | $links = Api\Link::get_links($app, $id, $only_app); |
||||
| 357 | $link_titles = array(); |
||||
| 358 | foreach($links as $link_info) |
||||
| 359 | { |
||||
| 360 | // Using only_app only returns the ID |
||||
| 361 | if(!is_array($link_info) && $only_app && $only_app[0] !== '!') |
||||
| 362 | { |
||||
| 363 | $link_info = array( |
||||
| 364 | 'app' => $only_app, |
||||
| 365 | 'id' => $link_info |
||||
| 366 | ); |
||||
| 367 | } |
||||
| 368 | if($exclude && in_array($link_info['id'], $exclude)) continue; |
||||
| 369 | |||||
| 370 | $title = Api\Link::title($link_info['app'], $link_info['id']); |
||||
| 371 | |||||
| 372 | if($style == 'href' || $style == 'link') |
||||
| 373 | { |
||||
| 374 | $link = Api\Link::view($link_info['app'], $link_info['id'], $link_info); |
||||
| 375 | if($link_info['app'] != Api\Link::VFS_APPNAME) |
||||
| 376 | { |
||||
| 377 | // Set app to false so we always get an external link |
||||
| 378 | $link = str_replace(',', '%2C', $GLOBALS['egw']->framework->link('/index.php',$link, false)); |
||||
| 379 | } |
||||
| 380 | else |
||||
| 381 | { |
||||
| 382 | $link = Api\Framework::link($link, array()); |
||||
| 383 | } |
||||
| 384 | // Prepend site |
||||
| 385 | if ($link[0] == '/') $link = Api\Framework::getUrl($link); |
||||
| 386 | |||||
| 387 | $title = $style == 'href' ? Api\Html::a_href(Api\Html::htmlspecialchars($title), $link) : $link; |
||||
| 388 | } |
||||
| 389 | $link_titles[] = $title; |
||||
| 390 | } |
||||
| 391 | return implode("\n",$link_titles); |
||||
| 392 | } |
||||
| 393 | |||||
| 394 | /** |
||||
| 395 | * Get all link placeholders |
||||
| 396 | * |
||||
| 397 | * Calls get_links() repeatedly to get all the combinations for the content. |
||||
| 398 | * |
||||
| 399 | * @param $app String appname |
||||
| 400 | * @param $id String ID of record |
||||
| 401 | * @param $prefix |
||||
| 402 | * @param $content String document content |
||||
| 403 | */ |
||||
| 404 | protected function get_all_links($app, $id, $prefix, &$content) |
||||
| 405 | { |
||||
| 406 | $array = array(); |
||||
| 407 | $pattern = '@\$\$(links_attachments|links|attachments|link)\/?(title|href|link)?\/?([a-z]*)\$\$@'; |
||||
| 408 | static $link_cache=null; |
||||
| 409 | $matches = null; |
||||
| 410 | if(preg_match_all($pattern, $content, $matches)) |
||||
| 411 | { |
||||
| 412 | foreach($matches[0] as $i => $placeholder) |
||||
| 413 | { |
||||
| 414 | $placeholder = substr($placeholder, 2, -2); |
||||
| 415 | if($link_cache[$id][$placeholder]) |
||||
| 416 | { |
||||
| 417 | $array[$placeholder] = $link_cache[$id][$placeholder]; |
||||
| 418 | continue; |
||||
| 419 | } |
||||
| 420 | switch($matches[1][$i]) |
||||
| 421 | { |
||||
| 422 | case 'link': |
||||
| 423 | // Link to current record |
||||
| 424 | $title = Api\Link::title($app, $id); |
||||
| 425 | if(class_exists('EGroupware\Stylite\Vfs\Links\StreamWrapper') && $app != Api\Link::VFS_APPNAME) |
||||
| 426 | { |
||||
| 427 | $title = Stylite\Vfs\Links\StreamWrapper::entry2name($app, $id, $title); |
||||
|
0 ignored issues
–
show
The type
EGroupware\Stylite\Vfs\Links\StreamWrapper was not found. Maybe you did not declare it correctly or list all dependencies?
The issue could also be caused by a filter entry in the build configuration.
If the path has been excluded in your configuration, e.g. filter:
dependency_paths: ["lib/*"]
For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths Loading history...
|
|||||
| 428 | } |
||||
| 429 | |||||
| 430 | $link = Api\Link::view($app, $id); |
||||
| 431 | if($app != Api\Link::VFS_APPNAME) |
||||
| 432 | { |
||||
| 433 | // Set app to false so we always get an external link |
||||
| 434 | $link = str_replace(',', '%2C', $GLOBALS['egw']->framework->link('/index.php',$link, false)); |
||||
| 435 | } |
||||
| 436 | else |
||||
| 437 | { |
||||
| 438 | $link = Api\Framework::link($link, array()); |
||||
| 439 | } |
||||
| 440 | // Prepend site |
||||
| 441 | if ($link[0] == '/') $link = Api\Framework::getUrl($link); |
||||
| 442 | |||||
| 443 | $array['$$'.($prefix?$prefix.'/':'').$placeholder.'$$'] = Api\Html::a_href(Api\Html::htmlspecialchars($title), $link); |
||||
| 444 | break; |
||||
| 445 | case 'links': |
||||
| 446 | $link_app = $matches[3][$i] ? $matches[3][$i] : '!'.Api\Link::VFS_APPNAME; |
||||
| 447 | $array['$$'.($prefix?$prefix.'/':'').$placeholder.'$$'] = $this->get_links($app, $id, $link_app, array(),$matches[2][$i]); |
||||
| 448 | break; |
||||
| 449 | case 'attachments': |
||||
| 450 | $array['$$'.($prefix?$prefix.'/':'').$placeholder.'$$'] = $this->get_links($app, $id, Api\Link::VFS_APPNAME,array(),$matches[2][$i]); |
||||
| 451 | break; |
||||
| 452 | default: |
||||
| 453 | $array['$$'.($prefix?$prefix.'/':'').$placeholder.'$$'] = $this->get_links($app, $id, $matches[3][$i], array(), $matches[2][$i]); |
||||
| 454 | break; |
||||
| 455 | } |
||||
| 456 | $link_cache[$id][$placeholder] = $array[$placeholder]; |
||||
| 457 | } |
||||
| 458 | } |
||||
| 459 | return $array; |
||||
| 460 | } |
||||
| 461 | |||||
| 462 | /** |
||||
| 463 | * Get share placeholder |
||||
| 464 | * |
||||
| 465 | * If the placeholder is present in the content, the share will be automatically |
||||
| 466 | * created. |
||||
| 467 | */ |
||||
| 468 | protected function share_placeholder($app, $id, $prefix, &$content) |
||||
| 469 | { |
||||
| 470 | $replacements = array(); |
||||
| 471 | |||||
| 472 | // Skip if no content or content has no share placeholder |
||||
| 473 | if(!$content || strpos($content, '$$share') === FALSE) |
||||
| 474 | { |
||||
| 475 | return $replacements; |
||||
| 476 | } |
||||
| 477 | |||||
| 478 | if(!$GLOBALS['egw_info']['user']['apps']['stylite']) |
||||
| 479 | { |
||||
| 480 | $replacements['$$'.$prefix.'share$$'] = lang('EPL Only'); |
||||
| 481 | return $replacements; |
||||
| 482 | } |
||||
| 483 | |||||
| 484 | // Get or create the share |
||||
| 485 | $share = $this->create_share($app, $id, $content); |
||||
| 486 | |||||
| 487 | if($share) |
||||
|
0 ignored issues
–
show
|
|||||
| 488 | { |
||||
| 489 | $replacements['$$'.$prefix.'share$$'] = $link = Api\Sharing::share2link($share); |
||||
|
0 ignored issues
–
show
|
|||||
| 490 | } |
||||
| 491 | |||||
| 492 | return $replacements; |
||||
| 493 | } |
||||
| 494 | |||||
| 495 | /** |
||||
| 496 | * Create a share for an entry |
||||
| 497 | * |
||||
| 498 | * @param string $app |
||||
| 499 | * @param string $id |
||||
| 500 | * @param String $content |
||||
| 501 | * @return \EGroupware\Api\Sharing |
||||
| 502 | */ |
||||
| 503 | protected function create_share($app, $id, &$content) |
||||
| 504 | { |
||||
| 505 | // Check if some other process created the share (with custom options) |
||||
| 506 | // and put it in the session cache for us |
||||
| 507 | $path = "$app::$id"; |
||||
| 508 | $session = \EGroupware\Api\Cache::getSession(Api\Sharing::class, $path); |
||||
| 509 | if($session && $session['share_path'] == $path) |
||||
| 510 | { |
||||
| 511 | return $session; |
||||
| 512 | } |
||||
| 513 | |||||
| 514 | // Need to create the share here. |
||||
| 515 | // No way to know here if it should be writable, or who it's going to |
||||
| 516 | $mode = /* ? ? Sharing::WRITABLE :*/ Api\Sharing::READONLY; |
||||
| 517 | $recipients = array(); |
||||
| 518 | $extra = array(); |
||||
| 519 | |||||
| 520 | //$extra['share_writable'] |= ($mode == Sharing::WRITABLE ? 1 : 0); |
||||
| 521 | |||||
| 522 | return \EGroupware\Stylite\Link\Sharing::create($path, $mode, NULL, $recipients, $extra); |
||||
|
0 ignored issues
–
show
The type
EGroupware\Stylite\Link\Sharing was not found. Maybe you did not declare it correctly or list all dependencies?
The issue could also be caused by a filter entry in the build configuration.
If the path has been excluded in your configuration, e.g. filter:
dependency_paths: ["lib/*"]
For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths Loading history...
|
|||||
| 523 | } |
||||
| 524 | |||||
| 525 | /** |
||||
| 526 | * Format a datetime |
||||
| 527 | * |
||||
| 528 | * @param int|string|DateTime $time unix timestamp or Y-m-d H:i:s string (in user time!) |
||||
|
0 ignored issues
–
show
|
|||||
| 529 | * @param string $format =null format string, default $this->datetime_format |
||||
| 530 | * @deprecated use Api\DateTime::to($time='now',$format='') |
||||
| 531 | * @return string |
||||
| 532 | */ |
||||
| 533 | protected function format_datetime($time,$format=null) |
||||
| 534 | { |
||||
| 535 | trigger_error(__METHOD__ . ' is deprecated, use Api\DateTime::to($time, $format)', E_USER_DEPRECATED); |
||||
| 536 | if (is_null($format)) $format = $this->datetime_format; |
||||
| 537 | |||||
| 538 | return Api\DateTime::to($time,$format); |
||||
| 539 | } |
||||
| 540 | |||||
| 541 | /** |
||||
| 542 | * Checks if current user is excepted from the export-limit: |
||||
| 543 | * a) access to admin application |
||||
| 544 | * b) he or one of his memberships is named in export_limit_excepted config var |
||||
| 545 | * |
||||
| 546 | * @return boolean |
||||
| 547 | */ |
||||
| 548 | public static function is_export_limit_excepted() |
||||
| 549 | { |
||||
| 550 | static $is_excepted=null; |
||||
| 551 | |||||
| 552 | if (is_null($is_excepted)) |
||||
| 553 | { |
||||
| 554 | $is_excepted = isset($GLOBALS['egw_info']['user']['apps']['admin']); |
||||
| 555 | |||||
| 556 | // check export-limit and fail if user tries to export more entries then allowed |
||||
| 557 | if (!$is_excepted && (is_array($export_limit_excepted = $GLOBALS['egw_info']['server']['export_limit_excepted']) || |
||||
| 558 | is_array($export_limit_excepted = unserialize($export_limit_excepted)))) |
||||
| 559 | { |
||||
| 560 | $id_and_memberships = $GLOBALS['egw']->accounts->memberships($GLOBALS['egw_info']['user']['account_id'],true); |
||||
| 561 | $id_and_memberships[] = $GLOBALS['egw_info']['user']['account_id']; |
||||
| 562 | $is_excepted = (bool) array_intersect($id_and_memberships, $export_limit_excepted); |
||||
| 563 | } |
||||
| 564 | } |
||||
| 565 | return $is_excepted; |
||||
| 566 | } |
||||
| 567 | |||||
| 568 | /** |
||||
| 569 | * Checks if there is an exportlimit set, and returns |
||||
| 570 | * |
||||
| 571 | * @param string $app ='common' checks and validates app_limit, if not set returns the global limit |
||||
| 572 | * @return mixed - no if no export is allowed, false if there is no restriction and int as there is a valid restriction |
||||
| 573 | * you may have to cast the returned value to int, if you want to use it as number |
||||
| 574 | */ |
||||
| 575 | public static function getExportLimit($app='common') |
||||
| 576 | { |
||||
| 577 | static $exportLimitStore=array(); |
||||
| 578 | if (empty($app)) $app='common'; |
||||
| 579 | //error_log(__METHOD__.__LINE__.' called with app:'.$app); |
||||
| 580 | if (!array_key_exists($app,$exportLimitStore)) |
||||
| 581 | { |
||||
| 582 | //error_log(__METHOD__.__LINE__.' -> '.$app_limit.' '.function_backtrace()); |
||||
| 583 | $exportLimitStore[$app] = $GLOBALS['egw_info']['server']['export_limit']; |
||||
| 584 | if ($app !='common') |
||||
| 585 | { |
||||
| 586 | $app_limit = Api\Hooks::single('export_limit',$app); |
||||
| 587 | if ($app_limit) $exportLimitStore[$app] = $app_limit; |
||||
| 588 | } |
||||
| 589 | //error_log(__METHOD__.__LINE__.' building cache for app:'.$app.' -> '.$exportLimitStore[$app]); |
||||
| 590 | if (empty($exportLimitStore[$app])) |
||||
| 591 | { |
||||
| 592 | $exportLimitStore[$app] = false; |
||||
| 593 | return false; |
||||
| 594 | } |
||||
| 595 | |||||
| 596 | if (is_numeric($exportLimitStore[$app])) |
||||
| 597 | { |
||||
| 598 | $exportLimitStore[$app] = (int)$exportLimitStore[$app]; |
||||
| 599 | } |
||||
| 600 | else |
||||
| 601 | { |
||||
| 602 | $exportLimitStore[$app] = 'no'; |
||||
| 603 | } |
||||
| 604 | //error_log(__METHOD__.__LINE__.' -> '.$exportLimit); |
||||
| 605 | } |
||||
| 606 | //error_log(__METHOD__.__LINE__.' app:'.$app.' -> '.$exportLimitStore[$app]); |
||||
| 607 | return $exportLimitStore[$app]; |
||||
| 608 | } |
||||
| 609 | |||||
| 610 | /** |
||||
| 611 | * hasExportLimit |
||||
| 612 | * checks wether there is an exportlimit set, and returns true or false |
||||
| 613 | * @param mixed $app_limit app_limit, if not set checks the global limit |
||||
| 614 | * @param string $checkas [AND|ISALLOWED], AND default; if set to ISALLOWED it is checked if Export is allowed |
||||
| 615 | * |
||||
| 616 | * @return bool - true if no export is allowed or a limit is set, false if there is no restriction |
||||
| 617 | */ |
||||
| 618 | public static function hasExportLimit($app_limit,$checkas='AND') |
||||
| 619 | { |
||||
| 620 | if (strtoupper($checkas) == 'ISALLOWED') return (empty($app_limit) || ($app_limit !='no' && $app_limit > 0) ); |
||||
| 621 | if (empty($app_limit)) return false; |
||||
| 622 | if ($app_limit == 'no') return true; |
||||
| 623 | if ($app_limit > 0) return true; |
||||
| 624 | } |
||||
| 625 | |||||
| 626 | /** |
||||
| 627 | * Merges a given document with contact data |
||||
| 628 | * |
||||
| 629 | * @param string $document path/url of document |
||||
| 630 | * @param array $ids array with contact id(s) |
||||
| 631 | * @param string &$err error-message on error |
||||
| 632 | * @param string $mimetype mimetype of complete document, eg. text/*, application/vnd.oasis.opendocument.text, application/rtf |
||||
| 633 | * @param array $fix =null regular expression => replacement pairs eg. to fix garbled placeholders |
||||
| 634 | * @return string|boolean merged document or false on error |
||||
| 635 | */ |
||||
| 636 | public function &merge($document,$ids,&$err,$mimetype,array $fix=null) |
||||
| 637 | { |
||||
| 638 | if (!($content = file_get_contents($document))) |
||||
| 639 | { |
||||
| 640 | $err = lang("Document '%1' does not exist or is not readable for you!",$document); |
||||
|
0 ignored issues
–
show
The call to
lang() has too many arguments starting with $document.
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue. If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress. Please note the @ignore annotation hint above. Loading history...
|
|||||
| 641 | return false; |
||||
| 642 | } |
||||
| 643 | |||||
| 644 | if (self::hasExportLimit($this->export_limit) && !self::is_export_limit_excepted() && count($ids) > (int)$this->export_limit) |
||||
| 645 | { |
||||
| 646 | $err = lang('No rights to export more than %1 entries!',(int)$this->export_limit); |
||||
| 647 | return false; |
||||
| 648 | } |
||||
| 649 | |||||
| 650 | // fix application/msword mimetype for rtf files |
||||
| 651 | if ($mimetype == 'application/msword' && strtolower(substr($document,-4)) == '.rtf') |
||||
| 652 | { |
||||
| 653 | $mimetype = 'application/rtf'; |
||||
| 654 | } |
||||
| 655 | |||||
| 656 | try { |
||||
| 657 | $content = $this->merge_string($content,$ids,$err,$mimetype,$fix); |
||||
| 658 | } catch (\Exception $e) { |
||||
| 659 | _egw_log_exception($e); |
||||
| 660 | $err = $e->getMessage(); |
||||
| 661 | return false; |
||||
| 662 | } |
||||
| 663 | return $content; |
||||
| 664 | } |
||||
| 665 | |||||
| 666 | protected function apply_styles (&$content, $mimetype, $mso_application_progid=null) |
||||
| 667 | { |
||||
| 668 | if (!isset($mso_application_progid)) |
||||
| 669 | { |
||||
| 670 | $matches = null; |
||||
| 671 | $mso_application_progid = $mimetype == 'application/xml' && |
||||
| 672 | preg_match('/'.preg_quote('<?mso-application progid="').'([^"]+)'.preg_quote('"?>').'/',substr($content,0,200),$matches) ? |
||||
| 673 | $matches[1] : ''; |
||||
| 674 | } |
||||
| 675 | // Tags we can replace with the target document's version |
||||
| 676 | $replace_tags = array(); |
||||
|
0 ignored issues
–
show
|
|||||
| 677 | switch($mimetype.$mso_application_progid) |
||||
| 678 | { |
||||
| 679 | case 'application/vnd.oasis.opendocument.text': // oo text |
||||
| 680 | case 'application/vnd.oasis.opendocument.spreadsheet': // oo spreadsheet |
||||
| 681 | case 'application/vnd.oasis.opendocument.presentation': |
||||
| 682 | case 'application/vnd.oasis.opendocument.text-template': |
||||
| 683 | case 'application/vnd.oasis.opendocument.spreadsheet-template': |
||||
| 684 | case 'application/vnd.oasis.opendocument.presentation-template': |
||||
| 685 | $doc = new DOMDocument(); |
||||
| 686 | $xslt = new XSLTProcessor(); |
||||
| 687 | $doc->load(EGW_INCLUDE_ROOT.'/api/templates/default/Merge/openoffice.xslt'); |
||||
| 688 | $xslt->importStyleSheet($doc); |
||||
| 689 | |||||
| 690 | //echo $content;die(); |
||||
| 691 | break; |
||||
| 692 | case 'application/xmlWord.Document': // Word 2003*/ |
||||
| 693 | case 'application/vnd.openxmlformats-officedocument.wordprocessingml.document': // ms office 2007 |
||||
| 694 | case 'application/vnd.ms-word.document.macroenabled.12': |
||||
| 695 | case 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet': |
||||
| 696 | case 'application/vnd.ms-excel.sheet.macroenabled.12': |
||||
| 697 | // It seems easier to split the parent tags here |
||||
| 698 | $replace_tags = array( |
||||
| 699 | // Tables, lists don't go inside <w:p> |
||||
| 700 | '/<(ol|ul|table)( [^>]*)?>/' => '</w:t></w:r></w:p><$1$2>', |
||||
| 701 | '/<\/(ol|ul|table)>/' => '</$1><w:p><w:r><w:t>', |
||||
| 702 | // Fix for things other than text (newlines) inside table row |
||||
| 703 | '/<(td)( [^>]*)?>((?!<w:t>))(.*?)<\/td>[\s]*?/' => '<$1$2><w:t>$4</w:t></td>', |
||||
| 704 | // Remove extra whitespace |
||||
| 705 | '/<li([^>]*?)>[^:print:]*?(.*?)<\/li>/' => '<li$1>$2</li>', // This doesn't get it all |
||||
| 706 | '/<w:t>[\s]+(.*?)<\/w:t>/' => '<w:t>$1</w:t>', |
||||
| 707 | // Remove spans with no attributes, linebreaks inside them cause problems |
||||
| 708 | '/<span>(.*?)<\/span>/' => '$1' |
||||
| 709 | ); |
||||
| 710 | $content = preg_replace(array_keys($replace_tags),array_values($replace_tags),$content); |
||||
| 711 | |||||
| 712 | /* |
||||
| 713 | In the case where you have something like <span><span></w:t><w:br/><w:t></span></span> (invalid - mismatched tags), |
||||
| 714 | it takes multiple runs to get rid of both spans. So, loop. |
||||
| 715 | OO.o files have not yet been shown to have this problem. |
||||
| 716 | */ |
||||
| 717 | $count = $i = 0; |
||||
| 718 | do |
||||
| 719 | { |
||||
| 720 | $content = preg_replace('/<span>(.*?)<\/span>/','$1',$content, -1, $count); |
||||
| 721 | $i++; |
||||
| 722 | } while($count > 0 && $i < 10); |
||||
| 723 | |||||
| 724 | $doc = new DOMDocument(); |
||||
| 725 | $xslt = new XSLTProcessor(); |
||||
| 726 | $xslt_file = $mimetype == 'application/xml' ? 'wordml.xslt' : 'msoffice.xslt'; |
||||
| 727 | $doc->load(EGW_INCLUDE_ROOT.'/api/templates/default/Merge/'.$xslt_file); |
||||
| 728 | $xslt->importStyleSheet($doc); |
||||
| 729 | break; |
||||
| 730 | } |
||||
| 731 | |||||
| 732 | // XSLT transform known tags |
||||
| 733 | if($xslt) |
||||
| 734 | { |
||||
| 735 | // does NOT work with php 5.2.6: Catchable fatal error: argument 1 to transformToXml() must be of type DOMDocument |
||||
| 736 | //$element = new SimpleXMLelement($content); |
||||
| 737 | $element = new DOMDocument('1.0', 'utf-8'); |
||||
| 738 | $result = $element->loadXML($content); |
||||
| 739 | if(!$result) |
||||
| 740 | { |
||||
| 741 | throw new Api\Exception('Unable to parse merged document for styles. Check warnings in log for details.'); |
||||
| 742 | } |
||||
| 743 | $content = $xslt->transformToXml($element); |
||||
| 744 | //echo $content;die(); |
||||
| 745 | // Word 2003 needs two declarations, add extra declaration back in |
||||
| 746 | if($mimetype == 'application/xml' && $mso_application_progid == 'Word.Document' && strpos($content, '<?xml') !== 0) { |
||||
| 747 | $content = '<?xml version="1.0" encoding="UTF-8" standalone="yes"?>'.$content; |
||||
| 748 | } |
||||
| 749 | // Validate |
||||
| 750 | /* |
||||
| 751 | $doc = new DOMDocument(); |
||||
| 752 | $doc->loadXML($content); |
||||
| 753 | $doc->schemaValidate(*Schema (xsd) file*); |
||||
| 754 | */ |
||||
| 755 | } |
||||
| 756 | } |
||||
| 757 | |||||
| 758 | /** |
||||
| 759 | * Merges a given document with contact data |
||||
| 760 | * |
||||
| 761 | * @param string $_content |
||||
| 762 | * @param array $ids array with contact id(s) |
||||
| 763 | * @param string &$err error-message on error |
||||
| 764 | * @param string $mimetype mimetype of complete document, eg. text/*, application/vnd.oasis.opendocument.text, application/rtf |
||||
| 765 | * @param array $fix =null regular expression => replacement pairs eg. to fix garbled placeholders |
||||
| 766 | * @param string $charset =null charset to override default set by mimetype or export charset |
||||
| 767 | * @return string|boolean merged document or false on error |
||||
| 768 | */ |
||||
| 769 | public function &merge_string($_content,$ids,&$err,$mimetype,array $fix=null,$charset=null) |
||||
| 770 | { |
||||
| 771 | $matches = null; |
||||
| 772 | if ($mimetype == 'application/xml' && |
||||
| 773 | preg_match('/'.preg_quote('<?mso-application progid="').'([^"]+)'.preg_quote('"?>').'/',substr($_content,0,200),$matches)) |
||||
| 774 | { |
||||
| 775 | $mso_application_progid = $matches[1]; |
||||
| 776 | } |
||||
| 777 | else |
||||
| 778 | { |
||||
| 779 | $mso_application_progid = ''; |
||||
| 780 | } |
||||
| 781 | // alternative syntax using double curly brackets (eg. {{cat_id}} instead $$cat_id$$), |
||||
| 782 | // agressivly removing all xml-tags eg. Word adds within placeholders |
||||
| 783 | $content = preg_replace_callback('/{{[^}]+}}/i', function($matches) |
||||
| 784 | { |
||||
| 785 | return '$$'.strip_tags(substr($matches[0], 2, -2)).'$$'; |
||||
| 786 | }, $_content); |
||||
| 787 | // Handle escaped placeholder markers in RTF, they won't match when escaped |
||||
| 788 | if($mimetype == 'application/rtf') |
||||
| 789 | { |
||||
| 790 | $content = preg_replace('/\\\{\\\{([^\\}]+)\\\}\\\}/i','$$\1$$',$content); |
||||
| 791 | } |
||||
| 792 | |||||
| 793 | // make currently processed mimetype available to class methods; |
||||
| 794 | $this->mimetype = $mimetype; |
||||
| 795 | |||||
| 796 | // fix garbled placeholders |
||||
| 797 | if ($fix && is_array($fix)) |
||||
| 798 | { |
||||
| 799 | $content = preg_replace(array_keys($fix),array_values($fix),$content); |
||||
| 800 | //die("<pre>".htmlspecialchars($content)."</pre>\n"); |
||||
| 801 | } |
||||
| 802 | list($contentstart,$contentrepeat,$contentend) = preg_split('/\$\$pagerepeat\$\$/',$content,-1, PREG_SPLIT_NO_EMPTY); //get differt parts of document, seperatet by Pagerepeat |
||||
| 803 | if ($mimetype == 'text/plain' && $ids && count($ids) > 1) |
||||
|
0 ignored issues
–
show
The expression
$ids of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using ! empty($expr) instead to make it clear that you intend to check for an array without elements.
This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent. Consider making the comparison explicit by using Loading history...
|
|||||
| 804 | { |
||||
| 805 | // textdocuments are simple, they do not hold start and end, but they may have content before and after the $$pagerepeat$$ tag |
||||
| 806 | // header and footer should not hold any $$ tags; if we find $$ tags with the header, we assume it is the pagerepeatcontent |
||||
| 807 | $nohead = false; |
||||
| 808 | if (stripos($contentstart,'$$') !== false) $nohead = true; |
||||
| 809 | if ($nohead) |
||||
| 810 | { |
||||
| 811 | $contentend = $contentrepeat; |
||||
| 812 | $contentrepeat = $contentstart; |
||||
| 813 | $contentstart = ''; |
||||
| 814 | } |
||||
| 815 | |||||
| 816 | } |
||||
| 817 | if (in_array($mimetype, array('application/vnd.oasis.opendocument.text','application/vnd.oasis.opendocument.text-template')) && count($ids) > 1) |
||||
| 818 | { |
||||
| 819 | if(strpos($content, '$$pagerepeat') === false) |
||||
| 820 | { |
||||
| 821 | //for odt files we have to split the content and add a style for page break to the style area |
||||
| 822 | list($contentstart,$contentrepeat,$contentend) = preg_split('/office:body>/',$content,-1, PREG_SPLIT_NO_EMPTY); //get differt parts of document, seperatet by Pagerepeat |
||||
| 823 | $contentstart = substr($contentstart,0,strlen($contentstart)-1); //remove "<" |
||||
|
0 ignored issues
–
show
|
|||||
| 824 | $contentrepeat = substr($contentrepeat,0,strlen($contentrepeat)-2); //remove "</"; |
||||
| 825 | // need to add page-break style to the style list |
||||
| 826 | list($stylestart,$stylerepeat,$styleend) = preg_split('/<\/office:automatic-styles>/',$content,-1, PREG_SPLIT_NO_EMPTY); //get differt parts of document style sheets |
||||
| 827 | $contentstart = $stylestart.'<style:style style:name="P200" style:family="paragraph" style:parent-style-name="Standard"><style:paragraph-properties fo:break-before="page"/></style:style></office:automatic-styles>'; |
||||
| 828 | $contentstart .= '<office:body>'; |
||||
| 829 | $contentend = '</office:body></office:document-content>'; |
||||
| 830 | } |
||||
| 831 | else |
||||
| 832 | { |
||||
| 833 | // Template specifies where to repeat |
||||
| 834 | list($contentstart,$contentrepeat,$contentend) = preg_split('/\$\$pagerepeat\$\$/',$content,-1, PREG_SPLIT_NO_EMPTY); //get different parts of document, seperated by pagerepeat |
||||
| 835 | } |
||||
| 836 | } |
||||
| 837 | if (in_array($mimetype, array('application/vnd.ms-word.document.macroenabled.12', 'application/vnd.openxmlformats-officedocument.wordprocessingml.document')) && count($ids) > 1) |
||||
| 838 | { |
||||
| 839 | //for Word 2007 XML files we have to split the content and add a style for page break to the style area |
||||
| 840 | list($contentstart,$contentrepeat,$contentend) = preg_split('/w:body>/',$content,-1, PREG_SPLIT_NO_EMPTY); //get differt parts of document, seperatet by Pagerepeat |
||||
| 841 | $contentstart = substr($contentstart,0,strlen($contentstart)-1); //remove "</" |
||||
| 842 | $contentrepeat = substr($contentrepeat,0,strlen($contentrepeat)-2); //remove "</"; |
||||
| 843 | $contentstart .= '<w:body>'; |
||||
| 844 | $contentend = '</w:body></w:document>'; |
||||
| 845 | } |
||||
| 846 | list($Labelstart,$Labelrepeat,$Labeltend) = preg_split('/\$\$label\$\$/',$contentrepeat,-1, PREG_SPLIT_NO_EMPTY); //get the Lable content |
||||
| 847 | preg_match_all('/\$\$labelplacement\$\$/',$contentrepeat,$countlables, PREG_SPLIT_NO_EMPTY); |
||||
| 848 | $countlables = count($countlables[0]); |
||||
| 849 | preg_replace('/\$\$labelplacement\$\$/','',$Labelrepeat,1); |
||||
| 850 | if ($countlables > 1) $lableprint = true; |
||||
| 851 | if (count($ids) > 1 && !$contentrepeat) |
||||
| 852 | { |
||||
| 853 | $err = lang('for more than one contact in a document use the tag pagerepeat!'); |
||||
| 854 | return false; |
||||
| 855 | } |
||||
| 856 | if ($this->report_memory_usage) error_log(__METHOD__."(count(ids)=".count($ids).") strlen(contentrepeat)=".strlen($contentrepeat).', strlen(labelrepeat)='.strlen($Labelrepeat)); |
||||
| 857 | |||||
| 858 | if ($contentrepeat) |
||||
| 859 | { |
||||
| 860 | $content_stream = fopen('php://temp','r+'); |
||||
| 861 | fwrite($content_stream, $contentstart); |
||||
| 862 | $joiner = ''; |
||||
| 863 | switch($mimetype) |
||||
| 864 | { |
||||
| 865 | case 'application/rtf': |
||||
| 866 | case 'text/rtf': |
||||
| 867 | $joiner = '\\par \\page\\pard\\plain'; |
||||
| 868 | break; |
||||
| 869 | case 'application/vnd.oasis.opendocument.text': // oo text |
||||
| 870 | case 'application/vnd.oasis.opendocument.spreadsheet': // oo spreadsheet |
||||
| 871 | case 'application/vnd.oasis.opendocument.presentation': |
||||
| 872 | case 'application/vnd.oasis.opendocument.text-template': |
||||
| 873 | case 'application/vnd.oasis.opendocument.spreadsheet-template': |
||||
| 874 | case 'application/vnd.oasis.opendocument.presentation-template': |
||||
| 875 | case 'application/xml': |
||||
| 876 | case 'text/html': |
||||
| 877 | case 'text/csv': |
||||
| 878 | $joiner = ''; |
||||
| 879 | break; |
||||
| 880 | case 'application/vnd.openxmlformats-officedocument.wordprocessingml.document': |
||||
| 881 | case 'application/vnd.ms-word.document.macroenabled.12': |
||||
| 882 | case 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet': |
||||
| 883 | case 'application/vnd.ms-excel.sheet.macroenabled.12': |
||||
| 884 | $joiner = '<w:br w:type="page" />'; |
||||
| 885 | break; |
||||
| 886 | case 'text/plain': |
||||
| 887 | $joiner = "\r\n"; |
||||
| 888 | break; |
||||
| 889 | default: |
||||
| 890 | $err = lang('%1 not implemented for %2!','$$pagerepeat$$',$mimetype); |
||||
|
0 ignored issues
–
show
The call to
lang() has too many arguments starting with '$$pagerepeat$$'.
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue. If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress. Please note the @ignore annotation hint above. Loading history...
|
|||||
| 891 | return false; |
||||
| 892 | } |
||||
| 893 | } |
||||
| 894 | foreach ((array)$ids as $n => $id) |
||||
| 895 | { |
||||
| 896 | if ($contentrepeat) $content = $contentrepeat; //content to repeat |
||||
| 897 | if ($lableprint) $content = $Labelrepeat; |
||||
| 898 | |||||
| 899 | // generate replacements; if exeption is thrown, catch it set error message and return false |
||||
| 900 | try |
||||
| 901 | { |
||||
| 902 | if(!($replacements = $this->get_replacements($id,$content))) |
||||
| 903 | { |
||||
| 904 | $err = lang('Entry not found!'); |
||||
| 905 | return false; |
||||
| 906 | } |
||||
| 907 | } |
||||
| 908 | catch (Api\Exception\WrongUserinput $e) |
||||
| 909 | { |
||||
| 910 | // if this returns with an exeption, something failed big time |
||||
| 911 | $err = $e->getMessage(); |
||||
| 912 | return false; |
||||
| 913 | } |
||||
| 914 | if ($this->report_memory_usage) error_log(__METHOD__."() $n: $id ".Api\Vfs::hsize(memory_get_usage(true))); |
||||
| 915 | // some general replacements: current user, date and time |
||||
| 916 | if (strpos($content,'$$user/') !== null && ($user = $GLOBALS['egw']->accounts->id2name($GLOBALS['egw_info']['user']['account_id'],'person_id'))) |
||||
| 917 | { |
||||
| 918 | $replacements += $this->contact_replacements($user,'user', false, $content); |
||||
| 919 | $replacements['$$user/primary_group$$'] = $GLOBALS['egw']->accounts->id2name($GLOBALS['egw']->accounts->id2name($GLOBALS['egw_info']['user']['account_id'],'account_primary_group')); |
||||
| 920 | } |
||||
| 921 | $replacements['$$date$$'] = Api\DateTime::to('now',true); |
||||
| 922 | $replacements['$$datetime$$'] = Api\DateTime::to('now'); |
||||
| 923 | $replacements['$$time$$'] = Api\DateTime::to('now',false); |
||||
| 924 | |||||
| 925 | $app = $this->get_app(); |
||||
| 926 | $replacements += $this->share_placeholder($app, $id, $prefix, $content); |
||||
|
0 ignored issues
–
show
Comprehensibility
Best Practice
introduced
by
|
|||||
| 927 | |||||
| 928 | // does our extending class registered table-plugins AND document contains table tags |
||||
| 929 | if ($this->table_plugins && preg_match_all('/\\$\\$table\\/([A-Za-z0-9_]+)\\$\\$(.*?)\\$\\$endtable\\$\\$/s',$content,$matches,PREG_SET_ORDER)) |
||||
|
0 ignored issues
–
show
The expression
$this->table_plugins of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using ! empty($expr) instead to make it clear that you intend to check for an array without elements.
This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent. Consider making the comparison explicit by using Loading history...
|
|||||
| 930 | { |
||||
| 931 | // process each table |
||||
| 932 | foreach($matches as $match) |
||||
| 933 | { |
||||
| 934 | $plugin = $match[1]; // plugin name |
||||
| 935 | $callback = $this->table_plugins[$plugin]; |
||||
| 936 | $repeat = $match[2]; // line to repeat |
||||
| 937 | $repeats = ''; |
||||
| 938 | if (isset($callback)) |
||||
| 939 | { |
||||
| 940 | for($n = 0; ($row_replacements = $this->$callback($plugin,$id,$n,$repeat)); ++$n) |
||||
| 941 | { |
||||
| 942 | $_repeat = $this->process_commands($repeat, $row_replacements); |
||||
| 943 | $repeats .= $this->replace($_repeat,$row_replacements,$mimetype,$mso_application_progid); |
||||
| 944 | } |
||||
| 945 | } |
||||
| 946 | $content = str_replace($match[0],$repeats,$content); |
||||
| 947 | } |
||||
| 948 | } |
||||
| 949 | $content = $this->process_commands($this->replace($content,$replacements,$mimetype,$mso_application_progid,$charset), $replacements); |
||||
| 950 | |||||
| 951 | // remove not existing replacements (eg. from calendar array) |
||||
| 952 | if (strpos($content,'$$') !== null) |
||||
| 953 | { |
||||
| 954 | $content = preg_replace('/\$\$[a-z0-9_\/]+\$\$/i','',$content); |
||||
| 955 | } |
||||
| 956 | if ($contentrepeat) |
||||
| 957 | { |
||||
| 958 | fwrite($content_stream, ($n == 0 ? '' : $joiner) . $content); |
||||
| 959 | } |
||||
| 960 | if($lableprint) |
||||
| 961 | { |
||||
| 962 | $contentrep[is_array($id) ? implode(':',$id) : $id] = $content; |
||||
| 963 | } |
||||
| 964 | } |
||||
| 965 | if ($Labelrepeat) |
||||
| 966 | { |
||||
| 967 | $countpage=0; |
||||
| 968 | $count=0; |
||||
| 969 | $contentrepeatpages[$countpage] = $Labelstart.$Labeltend; |
||||
|
0 ignored issues
–
show
Comprehensibility
Best Practice
introduced
by
|
|||||
| 970 | |||||
| 971 | foreach ($contentrep as $Label) |
||||
| 972 | { |
||||
| 973 | $contentrepeatpages[$countpage] = preg_replace('/\$\$labelplacement\$\$/',$Label,$contentrepeatpages[$countpage],1); |
||||
| 974 | $count=$count+1; |
||||
| 975 | if (($count % $countlables) == 0 && count($contentrep)>$count) //new page |
||||
| 976 | { |
||||
| 977 | $countpage = $countpage+1; |
||||
| 978 | $contentrepeatpages[$countpage] = $Labelstart.$Labeltend; |
||||
| 979 | } |
||||
| 980 | } |
||||
| 981 | $contentrepeatpages[$countpage] = preg_replace('/\$\$labelplacement\$\$/','',$contentrepeatpages[$countpage],-1); //clean empty fields |
||||
| 982 | |||||
| 983 | switch($mimetype) |
||||
| 984 | { |
||||
| 985 | case 'application/rtf': |
||||
| 986 | case 'text/rtf': |
||||
| 987 | return $contentstart.implode('\\par \\page\\pard\\plain',$contentrepeatpages).$contentend; |
||||
| 988 | case 'application/vnd.oasis.opendocument.text': |
||||
| 989 | case 'application/vnd.oasis.opendocument.presentation': |
||||
| 990 | case 'application/vnd.oasis.opendocument.text-template': |
||||
| 991 | case 'application/vnd.oasis.opendocument.presentation-template': |
||||
| 992 | return $contentstart.implode('<text:line-break />',$contentrepeatpages).$contentend; |
||||
| 993 | case 'application/vnd.oasis.opendocument.spreadsheet': |
||||
| 994 | case 'application/vnd.oasis.opendocument.spreadsheet-template': |
||||
| 995 | return $contentstart.implode('</text:p><text:p>',$contentrepeatpages).$contentend; |
||||
| 996 | case 'application/vnd.openxmlformats-officedocument.wordprocessingml.document': |
||||
| 997 | case 'application/vnd.ms-word.document.macroenabled.12': |
||||
| 998 | case 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet': |
||||
| 999 | case 'application/vnd.ms-excel.sheet.macroenabled.12': |
||||
| 1000 | return $contentstart.implode('<w:br w:type="page" />',$contentrepeatpages).$contentend; |
||||
| 1001 | case 'text/plain': |
||||
| 1002 | return $contentstart.implode("\r\n",$contentrep).$contentend; |
||||
| 1003 | } |
||||
| 1004 | $err = lang('%1 not implemented for %2!','$$labelplacement$$',$mimetype); |
||||
| 1005 | return false; |
||||
| 1006 | } |
||||
| 1007 | |||||
| 1008 | if ($contentrepeat) |
||||
| 1009 | { |
||||
| 1010 | fwrite($content_stream, $contentend); |
||||
| 1011 | rewind($content_stream); |
||||
| 1012 | return stream_get_contents($content_stream); |
||||
| 1013 | } |
||||
| 1014 | if ($this->report_memory_usage) error_log(__METHOD__."() returning ".Api\Vfs::hsize(memory_get_peak_usage(true))); |
||||
| 1015 | |||||
| 1016 | return $content; |
||||
| 1017 | } |
||||
| 1018 | |||||
| 1019 | /** |
||||
| 1020 | * Replace placeholders in $content of $mimetype with $replacements |
||||
| 1021 | * |
||||
| 1022 | * @param string $content |
||||
| 1023 | * @param array $replacements name => replacement pairs |
||||
| 1024 | * @param string $mimetype mimetype of content |
||||
| 1025 | * @param string $mso_application_progid ='' MS Office 2003: 'Excel.Sheet' or 'Word.Document' |
||||
| 1026 | * @param string $charset =null charset to override default set by mimetype or export charset |
||||
| 1027 | * @return string |
||||
| 1028 | */ |
||||
| 1029 | protected function replace($content,array $replacements,$mimetype,$mso_application_progid='',$charset=null) |
||||
| 1030 | { |
||||
| 1031 | switch($mimetype) |
||||
| 1032 | { |
||||
| 1033 | case 'application/vnd.oasis.opendocument.text': // open office |
||||
| 1034 | case 'application/vnd.oasis.opendocument.spreadsheet': |
||||
| 1035 | case 'application/vnd.oasis.opendocument.presentation': |
||||
| 1036 | case 'application/vnd.oasis.opendocument.text-template': |
||||
| 1037 | case 'application/vnd.oasis.opendocument.spreadsheet-template': |
||||
| 1038 | case 'application/vnd.oasis.opendocument.presentation-template': |
||||
| 1039 | case 'application/vnd.openxmlformats-officedocument.wordprocessingml.document': // ms office 2007 |
||||
| 1040 | case 'application/vnd.ms-word.document.macroenabled.12': |
||||
| 1041 | case 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet': |
||||
| 1042 | case 'application/vnd.ms-excel.sheet.macroenabled.12': |
||||
| 1043 | case 'application/xml': |
||||
| 1044 | case 'text/xml': |
||||
| 1045 | $is_xml = true; |
||||
| 1046 | $charset = 'utf-8'; // xml files --> always use utf-8 |
||||
| 1047 | break; |
||||
| 1048 | |||||
| 1049 | case 'application/rtf': |
||||
| 1050 | case 'text/rtf': |
||||
| 1051 | $charset = 'iso-8859-1'; // rtf seems to user iso-8859-1 or equivalent windows charset, not utf-8 |
||||
| 1052 | break; |
||||
| 1053 | |||||
| 1054 | case 'text/html': |
||||
| 1055 | $is_xml = true; |
||||
| 1056 | $matches = null; |
||||
| 1057 | if (preg_match('/<meta http-equiv="content-type".*charset=([^;"]+)/i',$content,$matches)) |
||||
| 1058 | { |
||||
| 1059 | $charset = $matches[1]; |
||||
| 1060 | } |
||||
| 1061 | elseif (empty($charset)) |
||||
| 1062 | { |
||||
| 1063 | $charset = 'utf-8'; |
||||
| 1064 | } |
||||
| 1065 | break; |
||||
| 1066 | |||||
| 1067 | default: // div. text files --> use our export-charset, defined in addressbook prefs |
||||
| 1068 | if (empty($charset)) $charset = $this->contacts->prefs['csv_charset']; |
||||
| 1069 | break; |
||||
| 1070 | } |
||||
| 1071 | //error_log(__METHOD__."('$document', ... ,$mimetype) --> $charset (egw=".Api\Translation::charset().', export='.$this->contacts->prefs['csv_charset'].')'); |
||||
| 1072 | |||||
| 1073 | // do we need to convert charset |
||||
| 1074 | if ($charset && $charset != Api\Translation::charset()) |
||||
| 1075 | { |
||||
| 1076 | $replacements = Api\Translation::convert($replacements,Api\Translation::charset(),$charset); |
||||
| 1077 | } |
||||
| 1078 | |||||
| 1079 | // Date only placeholders for timestamps |
||||
| 1080 | if(is_array($this->date_fields)) |
||||
|
0 ignored issues
–
show
|
|||||
| 1081 | { |
||||
| 1082 | foreach($this->date_fields as $field) |
||||
| 1083 | { |
||||
| 1084 | if(($value = $replacements['$$'.$field.'$$'])) |
||||
| 1085 | { |
||||
| 1086 | $time = Api\DateTime::createFromFormat('+'.Api\DateTime::$user_dateformat.' '.Api\DateTime::$user_timeformat.'*', $value); |
||||
| 1087 | $replacements['$$'.$field.'/date$$'] = $time ? $time->format(Api\DateTime::$user_dateformat) : ''; |
||||
| 1088 | } |
||||
| 1089 | } |
||||
| 1090 | } |
||||
| 1091 | if ($is_xml) // zip'ed xml document (eg. OO) |
||||
| 1092 | { |
||||
| 1093 | // Numeric fields |
||||
| 1094 | $names = array(); |
||||
| 1095 | |||||
| 1096 | // Tags we can replace with the target document's version |
||||
| 1097 | $replace_tags = array(); |
||||
| 1098 | // only keep tags, if we have xsl extension available |
||||
| 1099 | if (class_exists('XSLTProcessor') && class_exists('DOMDocument') && $this->parse_html_styles) |
||||
| 1100 | { |
||||
| 1101 | switch($mimetype.$mso_application_progid) |
||||
| 1102 | { |
||||
| 1103 | case 'text/html': |
||||
| 1104 | $replace_tags = array( |
||||
| 1105 | '<b>','<strong>','<i>','<em>','<u>','<span>','<ol>','<ul>','<li>', |
||||
| 1106 | '<table>','<tr>','<td>','<a>','<style>','<img>', |
||||
| 1107 | ); |
||||
| 1108 | break; |
||||
| 1109 | case 'application/vnd.oasis.opendocument.text': // open office |
||||
| 1110 | case 'application/vnd.oasis.opendocument.spreadsheet': |
||||
| 1111 | case 'application/vnd.oasis.opendocument.presentation': |
||||
| 1112 | case 'application/vnd.oasis.opendocument.text-template': |
||||
| 1113 | case 'application/vnd.oasis.opendocument.spreadsheet-template': |
||||
| 1114 | case 'application/vnd.oasis.opendocument.presentation-template': |
||||
| 1115 | $replace_tags = array( |
||||
| 1116 | '<b>','<strong>','<i>','<em>','<u>','<span>','<ol>','<ul>','<li>', |
||||
| 1117 | '<table>','<tr>','<td>','<a>', |
||||
| 1118 | ); |
||||
| 1119 | break; |
||||
| 1120 | case 'application/xmlWord.Document': // Word 2003*/ |
||||
| 1121 | case 'application/vnd.openxmlformats-officedocument.wordprocessingml.document': // ms office 2007 |
||||
| 1122 | case 'application/vnd.ms-word.document.macroenabled.12': |
||||
| 1123 | case 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet': |
||||
| 1124 | case 'application/vnd.ms-excel.sheet.macroenabled.12': |
||||
| 1125 | $replace_tags = array( |
||||
| 1126 | '<b>','<strong>','<i>','<em>','<u>','<span>','<ol>','<ul>','<li>', |
||||
| 1127 | '<table>','<tr>','<td>', |
||||
| 1128 | ); |
||||
| 1129 | break; |
||||
| 1130 | } |
||||
| 1131 | } |
||||
| 1132 | // clean replacements from array values and html or html-entities, which mess up xml |
||||
| 1133 | foreach($replacements as $name => &$value) |
||||
| 1134 | { |
||||
| 1135 | // set unresolved array values to empty string |
||||
| 1136 | if(is_array($value)) |
||||
| 1137 | { |
||||
| 1138 | $value = ''; |
||||
| 1139 | continue; |
||||
| 1140 | } |
||||
| 1141 | // decode html entities back to utf-8 |
||||
| 1142 | |||||
| 1143 | if (is_string($value) && (strpos($value,'&') !== false) && $this->parse_html_styles) |
||||
| 1144 | { |
||||
| 1145 | $value = html_entity_decode($value,ENT_QUOTES,$charset); |
||||
| 1146 | |||||
| 1147 | // remove all non-decodable entities |
||||
| 1148 | if (strpos($value,'&') !== false) |
||||
| 1149 | { |
||||
| 1150 | $value = preg_replace('/&[^; ]+;/','',$value); |
||||
| 1151 | } |
||||
| 1152 | } |
||||
| 1153 | if(!$this->parse_html_styles || ( |
||||
| 1154 | strpos($value, "\n") !== FALSE && |
||||
| 1155 | strpos($value,'<br') === FALSE && strpos($value, '<span') === FALSE && strpos($value, '<p') === FALSE && strpos($value, '<div') === FALSE |
||||
| 1156 | )) |
||||
| 1157 | { |
||||
| 1158 | // Encode special chars so they don't break the file |
||||
| 1159 | $value = htmlspecialchars($value,ENT_NOQUOTES); |
||||
| 1160 | } |
||||
| 1161 | else if (is_string($value) && (strpos($value,'<') !== false)) |
||||
| 1162 | { |
||||
| 1163 | // Clean HTML, if it's being kept |
||||
| 1164 | if($replace_tags && extension_loaded('tidy')) { |
||||
| 1165 | $tidy = new tidy(); |
||||
| 1166 | $cleaned = $tidy->repairString($value, self::$tidy_config); |
||||
| 1167 | // Found errors. Strip it all so there's some output |
||||
| 1168 | if($tidy->getStatus() == 2) |
||||
| 1169 | { |
||||
| 1170 | error_log($tidy->errorBuffer); |
||||
| 1171 | $value = strip_tags($value); |
||||
| 1172 | } |
||||
| 1173 | else |
||||
| 1174 | { |
||||
| 1175 | $value = $cleaned; |
||||
| 1176 | } |
||||
| 1177 | } |
||||
| 1178 | // replace </p> and <br /> with CRLF (remove <p> and CRLF) |
||||
| 1179 | $value = strip_tags(str_replace(array("\r","\n",'<p>','</p>','<div>','</div>','<br />'), |
||||
| 1180 | array('','','',"\r\n",'',"\r\n","\r\n"), $value), |
||||
| 1181 | implode('', $replace_tags)); |
||||
| 1182 | |||||
| 1183 | // Change <tag>...\r\n</tag> to <tag>...</tag>\r\n or simplistic line break below will mangle it |
||||
| 1184 | // Loop to catch things like <b><span>Break:\r\n</span></b> |
||||
| 1185 | if($mso_application_progid) |
||||
| 1186 | { |
||||
| 1187 | $count = $i = 0; |
||||
| 1188 | do |
||||
| 1189 | { |
||||
| 1190 | $value = preg_replace('/<(b|strong|i|em|u|span)\b([^>]*?)>(.*?)'."\r\n".'<\/\1>/u', '<$1$2>$3</$1>'."\r\n",$value,-1,$count); |
||||
| 1191 | $i++; |
||||
| 1192 | } while($count > 0 && $i < 10); // Limit of 10 chosen arbitrarily just in case |
||||
| 1193 | } |
||||
| 1194 | } |
||||
| 1195 | // replace all control chars (C0+C1) but CR (\015), LF (\012) and TAB (\011) (eg. vertical tabulators) with space |
||||
| 1196 | // as they are not allowed in xml |
||||
| 1197 | $value = preg_replace('/[\000-\010\013\014\016-\037\177-\237]/u',' ',$value); |
||||
| 1198 | if(is_numeric($value) && $name != '$$user/account_id$$') // account_id causes problems with the preg_replace below |
||||
| 1199 | { |
||||
| 1200 | $names[] = preg_quote($name,'/'); |
||||
| 1201 | } |
||||
| 1202 | } |
||||
| 1203 | |||||
| 1204 | // Look for numbers, set their value if needed |
||||
| 1205 | if($this->numeric_fields || count($names)) |
||||
| 1206 | { |
||||
| 1207 | foreach((array)$this->numeric_fields as $fieldname) { |
||||
| 1208 | $names[] = preg_quote($fieldname,'/'); |
||||
| 1209 | } |
||||
| 1210 | $this->format_spreadsheet_numbers($content, $names, $mimetype.$mso_application_progid); |
||||
| 1211 | } |
||||
| 1212 | |||||
| 1213 | // Look for dates, set their value if needed |
||||
| 1214 | if($this->date_fields || count($names)) |
||||
|
0 ignored issues
–
show
The expression
$this->date_fields of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using ! empty($expr) instead to make it clear that you intend to check for an array without elements.
This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent. Consider making the comparison explicit by using Loading history...
|
|||||
| 1215 | { |
||||
| 1216 | $names = array(); |
||||
| 1217 | foreach((array)$this->date_fields as $fieldname) { |
||||
| 1218 | $names[] = $fieldname; |
||||
| 1219 | } |
||||
| 1220 | $this->format_spreadsheet_dates($content, $names, $replacements, $mimetype.$mso_application_progid); |
||||
| 1221 | } |
||||
| 1222 | |||||
| 1223 | // replace CRLF with linebreak tag of given type |
||||
| 1224 | switch($mimetype.$mso_application_progid) |
||||
| 1225 | { |
||||
| 1226 | case 'application/vnd.oasis.opendocument.text': // open office writer |
||||
| 1227 | case 'application/vnd.oasis.opendocument.text-template': |
||||
| 1228 | case 'application/vnd.oasis.opendocument.presentation': |
||||
| 1229 | case 'application/vnd.oasis.opendocument.presentation-template': |
||||
| 1230 | $break = '<text:line-break/>'; |
||||
| 1231 | break; |
||||
| 1232 | case 'application/vnd.oasis.opendocument.spreadsheet': // open office calc |
||||
| 1233 | case 'application/vnd.oasis.opendocument.spreadsheet-template': |
||||
| 1234 | $break = '</text:p><text:p>'; |
||||
| 1235 | break; |
||||
| 1236 | case 'application/vnd.openxmlformats-officedocument.wordprocessingml.document': // ms word 2007 |
||||
| 1237 | case 'application/vnd.ms-word.document.macroenabled.12': |
||||
| 1238 | $break = '</w:t><w:br/><w:t>'; |
||||
| 1239 | break; |
||||
| 1240 | case 'application/xmlExcel.Sheet': // Excel 2003 |
||||
| 1241 | $break = ' '; |
||||
| 1242 | break; |
||||
| 1243 | case 'application/xmlWord.Document': // Word 2003*/ |
||||
| 1244 | $break = '</w:t><w:br/><w:t>'; |
||||
| 1245 | break; |
||||
| 1246 | case 'text/html': |
||||
| 1247 | $break = '<br/>'; |
||||
| 1248 | break; |
||||
| 1249 | case 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet': // ms excel 2007 |
||||
| 1250 | case 'application/vnd.ms-excel.sheet.macroenabled.12': |
||||
| 1251 | default: |
||||
| 1252 | $break = "\r\n"; |
||||
| 1253 | break; |
||||
| 1254 | } |
||||
| 1255 | // now decode &, < and >, which need to be encoded as entities in xml |
||||
| 1256 | // Check for encoded >< getting double-encoded |
||||
| 1257 | if($this->parse_html_styles) |
||||
| 1258 | { |
||||
| 1259 | $replacements = str_replace(array('&',"\r","\n",'&lt;','&gt;'),array('&','',$break,'<','>'),$replacements); |
||||
| 1260 | } |
||||
| 1261 | else |
||||
| 1262 | { |
||||
| 1263 | // Need to at least handle new lines, or it'll be run together on one line |
||||
| 1264 | $replacements = str_replace(array("\r","\n"),array('',$break),$replacements); |
||||
| 1265 | } |
||||
| 1266 | } |
||||
| 1267 | if ($mimetype == 'application/x-yaml') |
||||
| 1268 | { |
||||
| 1269 | $content = preg_replace_callback('/^( +)([^$\n]*)(\$\$.+?\$\$)/m', function($matches) use ($replacements) |
||||
| 1270 | { |
||||
| 1271 | // allow with {{name/replace/with}} syntax to replace eg. commas with linebreaks: "{{name/, */\n}}" |
||||
| 1272 | $parts = null; |
||||
| 1273 | if (preg_match('|^\$\$([^/]+)/([^/]+)/([^$]*)\$\$$|', $matches[3], $parts) && isset($replacements['$$'.$parts[1].'$$'])) |
||||
| 1274 | { |
||||
| 1275 | $replacement =& $replacements['$$'.$parts[1].'$$']; |
||||
| 1276 | $replacement = preg_replace('/'.$parts[2].'/', strtr($parts[3], array( |
||||
| 1277 | '\\n' => "\n", '\\r' => "\r", '\\t' => "\t", '\\v' => "\v", '\\\\' => '\\', '\\f' => "\f", |
||||
| 1278 | )), $replacement); |
||||
| 1279 | } |
||||
| 1280 | else |
||||
| 1281 | { |
||||
| 1282 | $replacement =& $replacements[$matches[3]]; |
||||
| 1283 | } |
||||
| 1284 | // replacement with multiple lines --> add same number of space as before placeholder |
||||
| 1285 | if (isset($replacement)) |
||||
| 1286 | { |
||||
| 1287 | return $matches[1].$matches[2].implode("\n".$matches[1], preg_split("/\r?\n/", $replacement)); |
||||
| 1288 | } |
||||
| 1289 | return $matches[0]; // regular replacement below |
||||
| 1290 | }, $content); |
||||
| 1291 | } |
||||
| 1292 | return str_replace(array_keys($replacements),array_values($replacements),$content); |
||||
| 1293 | } |
||||
| 1294 | |||||
| 1295 | /** |
||||
| 1296 | * Convert numeric values in spreadsheets into actual numeric values |
||||
| 1297 | */ |
||||
| 1298 | protected function format_spreadsheet_numbers(&$content, $names, $mimetype) |
||||
| 1299 | { |
||||
| 1300 | foreach((array)$this->numeric_fields as $fieldname) { |
||||
| 1301 | $names[] = preg_quote($fieldname,'/'); |
||||
| 1302 | } |
||||
| 1303 | switch($mimetype) |
||||
| 1304 | { |
||||
| 1305 | case 'application/vnd.oasis.opendocument.spreadsheet': // open office calc |
||||
| 1306 | case 'application/vnd.oasis.opendocument.spreadsheet-template': |
||||
| 1307 | $format = '/<table:table-cell([^>]+?)office:value-type="[^"]+"([^>]*?)(?:calcext:value-type="[^"]+")?>.?<([a-z].*?)[^>]*>('.implode('|',$names).')<\/\3>.?<\/table:table-cell>/s'; |
||||
| 1308 | $replacement = '<table:table-cell$1office:value-type="float" office:value="$4"$2><$3>$4</$3></table:table-cell>'; |
||||
| 1309 | break; |
||||
| 1310 | case 'application/vnd.oasis.opendocument.text': // tables in open office writer |
||||
| 1311 | case 'application/vnd.oasis.opendocument.presentation': |
||||
| 1312 | case 'application/vnd.oasis.opendocument.text-template': |
||||
| 1313 | case 'application/vnd.oasis.opendocument.presentation-template': |
||||
| 1314 | $format = '/<table:table-cell([^>]+?)office:value-type="[^"]+"([^>]*?)>.?<([a-z].*?)[^>]*>('.implode('|',$names).')<\/\3>.?<\/table:table-cell>/s'; |
||||
| 1315 | $replacement = '<table:table-cell$1office:value-type="float" office:value="$4"$2><text:p text:style-name="Standard">$4</text:p></table:table-cell>'; |
||||
| 1316 | break; |
||||
| 1317 | case 'application/vnd.oasis.opendocument.text': // open office writer |
||||
| 1318 | case 'application/xmlExcel.Sheet': // Excel 2003 |
||||
| 1319 | $format = '/'.preg_quote('<Data ss:Type="String">','/').'('.implode('|',$names).')'.preg_quote('</Data>','/').'/'; |
||||
| 1320 | $replacement = '<Data ss:Type="Number">$1</Data>'; |
||||
| 1321 | |||||
| 1322 | break; |
||||
| 1323 | } |
||||
| 1324 | if($format && $names) |
||||
| 1325 | { |
||||
| 1326 | // Dealing with backtrack limit per AmigoJack 10-Jul-2010 comment on php.net preg-replace docs |
||||
| 1327 | do { |
||||
| 1328 | $result = preg_replace($format, $replacement, $content, -1); |
||||
| 1329 | } |
||||
| 1330 | // try to increase/double pcre.backtrack_limit failure |
||||
| 1331 | while(preg_last_error() == PREG_BACKTRACK_LIMIT_ERROR && self::increase_backtrack_limit()); |
||||
| 1332 | |||||
| 1333 | if ($result) $content = $result; // On failure $result would be NULL |
||||
| 1334 | } |
||||
| 1335 | } |
||||
| 1336 | |||||
| 1337 | /** |
||||
| 1338 | * Increase/double prce.backtrack_limit up to 1/4 of memory_limit |
||||
| 1339 | * |
||||
| 1340 | * @return boolean true: backtrack_limit increased, may try again, false limit already to high |
||||
| 1341 | */ |
||||
| 1342 | protected static function increase_backtrack_limit() |
||||
| 1343 | { |
||||
| 1344 | static $backtrack_limit=null,$memory_limit=null; |
||||
| 1345 | if (!isset($backtrack_limit)) |
||||
| 1346 | { |
||||
| 1347 | $backtrack_limit = ini_get('pcre.backtrack_limit'); |
||||
| 1348 | } |
||||
| 1349 | if (!isset($memory_limit)) |
||||
| 1350 | { |
||||
| 1351 | $memory_limit = ini_get('memory_limit'); |
||||
| 1352 | switch(strtoupper(substr($memory_limit, -1))) |
||||
| 1353 | { |
||||
| 1354 | case 'G': $memory_limit *= 1024; |
||||
|
0 ignored issues
–
show
Coding Style
Comprehensibility
introduced
by
|
|||||
| 1355 | case 'M': $memory_limit *= 1024; |
||||
|
0 ignored issues
–
show
Coding Style
Comprehensibility
introduced
by
|
|||||
| 1356 | case 'K': $memory_limit *= 1024; |
||||
| 1357 | } |
||||
| 1358 | } |
||||
| 1359 | if ($backtrack_limit < $memory_limit/8) |
||||
| 1360 | { |
||||
| 1361 | ini_set( 'pcre.backtrack_limit', $backtrack_limit*=2); |
||||
| 1362 | return true; |
||||
| 1363 | } |
||||
| 1364 | error_log("pcre.backtrack_limit exceeded @ $backtrack_limit, some cells left as text."); |
||||
| 1365 | return false; |
||||
| 1366 | } |
||||
| 1367 | |||||
| 1368 | /** |
||||
| 1369 | * Convert date / timestamp values in spreadsheets into actual date / timestamp values |
||||
| 1370 | */ |
||||
| 1371 | protected function format_spreadsheet_dates(&$content, $names, &$values, $mimetype) |
||||
| 1372 | { |
||||
| 1373 | if(!in_array($mimetype, array( |
||||
| 1374 | 'application/vnd.oasis.opendocument.spreadsheet', // open office calc |
||||
| 1375 | 'application/xmlExcel.Sheet', // Excel 2003 |
||||
| 1376 | //'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'//Excel WTF |
||||
| 1377 | ))) return; |
||||
| 1378 | |||||
| 1379 | // Some different formats dates could be in, depending what they've been through |
||||
| 1380 | $formats = array( |
||||
|
0 ignored issues
–
show
|
|||||
| 1381 | '!'.Api\DateTime::$user_dateformat . ' ' .Api\DateTime::$user_timeformat.':s', |
||||
| 1382 | '!'.Api\DateTime::$user_dateformat . '*' .Api\DateTime::$user_timeformat.':s', |
||||
| 1383 | '!'.Api\DateTime::$user_dateformat . '* ' .Api\DateTime::$user_timeformat, |
||||
| 1384 | '!'.Api\DateTime::$user_dateformat . '*', |
||||
| 1385 | '!'.Api\DateTime::$user_dateformat, |
||||
| 1386 | '!Y-m-d\TH:i:s' |
||||
| 1387 | ); |
||||
| 1388 | |||||
| 1389 | // Properly format values for spreadsheet |
||||
| 1390 | foreach($names as $idx => &$field) |
||||
| 1391 | { |
||||
| 1392 | $key = '$$'.$field.'$$'; |
||||
| 1393 | $field = preg_quote($field, '/'); |
||||
| 1394 | if($values[$key]) |
||||
| 1395 | { |
||||
| 1396 | $date = Api\DateTime::createFromUserFormat($values[$key]); |
||||
| 1397 | if($mimetype == 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' || |
||||
| 1398 | $mimetype == 'application/vnd.ms-excel.sheet.macroenabled.12')//Excel WTF |
||||
| 1399 | { |
||||
| 1400 | $interval = $date->diff(new Api\DateTime('1900-01-00 0:00')); |
||||
| 1401 | $values[$key] = $interval->format('%a')+1;// 1900-02-29 did not exist |
||||
| 1402 | // 1440 minutes in a day - fractional part |
||||
| 1403 | $values[$key] += ($date->format('H') * 60 + $date->format('i'))/1440; |
||||
| 1404 | } |
||||
| 1405 | else |
||||
| 1406 | { |
||||
| 1407 | $values[$key] = date('Y-m-d\TH:i:s',Api\DateTime::to($date,'ts')); |
||||
| 1408 | } |
||||
| 1409 | } |
||||
| 1410 | else |
||||
| 1411 | { |
||||
| 1412 | unset($names[$idx]); |
||||
| 1413 | } |
||||
| 1414 | } |
||||
| 1415 | |||||
| 1416 | switch($mimetype) |
||||
| 1417 | { |
||||
| 1418 | case 'application/vnd.oasis.opendocument.spreadsheet': // open office calc |
||||
| 1419 | // Removing these forces calc to respect our set value-type |
||||
| 1420 | $content = str_ireplace('calcext:value-type="string"','',$content); |
||||
| 1421 | |||||
| 1422 | $format = '/<table:table-cell([^>]+?)office:value-type="[^"]+"([^>]*?)>.?<([a-z].*?)[^>]*>\$\$('.implode('|',$names).')\$\$<\/\3>.?<\/table:table-cell>/s'; |
||||
| 1423 | $replacement = '<table:table-cell$1office:value-type="date" office:date-value="\$\$$4\$\$"$2><$3>\$\$$4\$\$</$3></table:table-cell>'; |
||||
| 1424 | break; |
||||
| 1425 | case 'application/xmlExcel.Sheet': // Excel 2003 |
||||
| 1426 | $format = '/'.preg_quote('<Data ss:Type="String">','/').'..('.implode('|',$names).')..'.preg_quote('</Data>','/').'/'; |
||||
| 1427 | $replacement = '<Data ss:Type="DateTime">\$\$$1\$\$</Data>'; |
||||
| 1428 | |||||
| 1429 | break; |
||||
| 1430 | case 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet': |
||||
| 1431 | case 'application/vnd.ms-excel.sheet.macroenabled.12': |
||||
| 1432 | break; |
||||
| 1433 | } |
||||
| 1434 | if($format && $names) |
||||
| 1435 | { |
||||
| 1436 | // Dealing with backtrack limit per AmigoJack 10-Jul-2010 comment on php.net preg-replace docs |
||||
| 1437 | do { |
||||
| 1438 | $result = preg_replace($format, $replacement, $content, -1); |
||||
| 1439 | } |
||||
| 1440 | // try to increase/double pcre.backtrack_limit failure |
||||
| 1441 | while(preg_last_error() == PREG_BACKTRACK_LIMIT_ERROR && self::increase_backtrack_limit()); |
||||
| 1442 | |||||
| 1443 | if ($result) $content = $result; // On failure $result would be NULL |
||||
| 1444 | } |
||||
| 1445 | } |
||||
| 1446 | |||||
| 1447 | /** |
||||
| 1448 | * Expand link_to custom fields with the merge replacements from the app |
||||
| 1449 | * but only if the template uses them. |
||||
| 1450 | */ |
||||
| 1451 | public function cf_link_to_expand($values, $content, &$replacements, $app = null) |
||||
| 1452 | { |
||||
| 1453 | if($app == null) |
||||
| 1454 | { |
||||
| 1455 | $app = str_replace('_merge','',get_class($this)); |
||||
| 1456 | } |
||||
| 1457 | $cfs = Api\Storage\Customfields::get($app); |
||||
| 1458 | |||||
| 1459 | // Cache, in case more than one sub-placeholder is used |
||||
| 1460 | $app_replacements = array(); |
||||
| 1461 | |||||
| 1462 | // Custom field placeholders look like {{#name}} |
||||
| 1463 | // Placeholders that need expanded will look like {{#name/placeholder}} |
||||
| 1464 | $matches = null; |
||||
| 1465 | preg_match_all('/\${2}(([^\/#]*?\/)?)#([^$\/]+)\/(.*?)[$}]{2}/', $content, $matches); |
||||
| 1466 | list($placeholders, , , $cf, $sub) = $matches; |
||||
| 1467 | |||||
| 1468 | // Collect any used custom fields from entries so you can do |
||||
| 1469 | // {{#other_app/#other_app_cf/n_fn}} |
||||
| 1470 | $expand_sub_cfs = []; |
||||
| 1471 | foreach($sub as $index => $cf_sub) |
||||
| 1472 | { |
||||
| 1473 | if(strpos($cf_sub, '#') === 0) |
||||
| 1474 | { |
||||
| 1475 | $expand_sub_cfs[$cf[$index]] .= '$$'.$cf_sub . '$$ '; |
||||
| 1476 | } |
||||
| 1477 | } |
||||
| 1478 | |||||
| 1479 | foreach($cf as $index => $field) |
||||
| 1480 | { |
||||
| 1481 | if($cfs[$field]) |
||||
| 1482 | { |
||||
| 1483 | if(in_array($cfs[$field]['type'],array_keys($GLOBALS['egw_info']['apps']))) |
||||
| 1484 | { |
||||
| 1485 | $field_app = $cfs[$field]['type']; |
||||
| 1486 | } |
||||
| 1487 | else if ($cfs[$field]['type'] == 'api-accounts' || $cfs[$field]['type'] == 'select-account') |
||||
| 1488 | { |
||||
| 1489 | // Special case for api-accounts -> contact |
||||
| 1490 | $field_app = 'addressbook'; |
||||
| 1491 | $account = $GLOBALS['egw']->accounts->read($values['#'.$field]); |
||||
| 1492 | $app_replacements[$field] = $this->contact_replacements($account['person_id']); |
||||
| 1493 | } |
||||
| 1494 | else if (($list = explode('-',$cfs[$field]['type']) && in_array($list[0], array_keys($GLOBALS['egw_info']['apps'])))) |
||||
|
0 ignored issues
–
show
Comprehensibility
Best Practice
introduced
by
|
|||||
| 1495 | { |
||||
| 1496 | // Sub-type - use app |
||||
| 1497 | $field_app = $list[0]; |
||||
| 1498 | } |
||||
| 1499 | else |
||||
| 1500 | { |
||||
| 1501 | continue; |
||||
| 1502 | } |
||||
| 1503 | |||||
| 1504 | // Get replacements for that application |
||||
| 1505 | if(!$app_replacements[$field]) |
||||
| 1506 | { |
||||
| 1507 | // If we send the real content it can result in infinite loop of lookups |
||||
| 1508 | // so we send only the used fields |
||||
| 1509 | $content = $expand_sub_cfs[$field] ? $expand_sub_cfs[$field] : ''; |
||||
| 1510 | $app_replacements[$field] = $this->get_app_replacements($field_app, $values['#'.$field], $content); |
||||
| 1511 | } |
||||
| 1512 | $replacements[$placeholders[$index]] = $app_replacements[$field]['$$'.$sub[$index].'$$']; |
||||
| 1513 | } |
||||
| 1514 | else |
||||
| 1515 | { |
||||
| 1516 | if ($cfs[$field]['type'] == 'date' || $cfs[$field]['type'] == 'date-time') $this->date_fields[] = '#'.$field; |
||||
| 1517 | } |
||||
| 1518 | } |
||||
| 1519 | } |
||||
| 1520 | |||||
| 1521 | /** |
||||
| 1522 | * Figure out which app we're running as |
||||
| 1523 | * |
||||
| 1524 | * @return string |
||||
| 1525 | */ |
||||
| 1526 | protected function get_app() |
||||
| 1527 | { |
||||
| 1528 | switch (get_class($this)) |
||||
| 1529 | { |
||||
| 1530 | case 'EGroupware\Api\Contacts\Merge': |
||||
| 1531 | $app = 'addressbook'; |
||||
| 1532 | break; |
||||
| 1533 | default: |
||||
| 1534 | $app = str_replace('_merge','',get_class($this)); |
||||
| 1535 | if(!in_array($app, array_keys($GLOBALS['egw_info']['apps']))) |
||||
| 1536 | { |
||||
| 1537 | $app = false; |
||||
| 1538 | } |
||||
| 1539 | break; |
||||
| 1540 | |||||
| 1541 | } |
||||
| 1542 | |||||
| 1543 | return $app; |
||||
| 1544 | } |
||||
| 1545 | |||||
| 1546 | /** |
||||
| 1547 | * Get the replacements for any entry specified by app & id |
||||
| 1548 | * |
||||
| 1549 | * @param stribg $app |
||||
|
0 ignored issues
–
show
The type
EGroupware\Api\Storage\stribg was not found. Maybe you did not declare it correctly or list all dependencies?
The issue could also be caused by a filter entry in the build configuration.
If the path has been excluded in your configuration, e.g. filter:
dependency_paths: ["lib/*"]
For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths Loading history...
|
|||||
| 1550 | * @param string $id |
||||
| 1551 | * @param string $content |
||||
| 1552 | * @return array |
||||
| 1553 | */ |
||||
| 1554 | public function get_app_replacements($app, $id, $content, $prefix='') |
||||
| 1555 | { |
||||
| 1556 | $replacements = array(); |
||||
| 1557 | if($app == 'addressbook') |
||||
|
0 ignored issues
–
show
|
|||||
| 1558 | { |
||||
| 1559 | return $this->contact_replacements($id, $prefix, false, $content); |
||||
| 1560 | } |
||||
| 1561 | |||||
| 1562 | try |
||||
| 1563 | { |
||||
| 1564 | $classname = "{$app}_merge"; |
||||
| 1565 | $class = new $classname(); |
||||
| 1566 | $method = $app.'_replacements'; |
||||
| 1567 | if(method_exists($class,$method)) |
||||
| 1568 | { |
||||
| 1569 | $replacements = $class->$method($id, $prefix, $content); |
||||
| 1570 | } |
||||
| 1571 | else |
||||
| 1572 | { |
||||
| 1573 | $replacements = $class->get_replacements($id, $content); |
||||
| 1574 | } |
||||
| 1575 | } |
||||
| 1576 | catch (\Exception $e) |
||||
| 1577 | { |
||||
| 1578 | // Don't break merge, just log it |
||||
| 1579 | error_log($e->getMessage()); |
||||
| 1580 | } |
||||
| 1581 | return $replacements; |
||||
| 1582 | } |
||||
| 1583 | |||||
| 1584 | /** |
||||
| 1585 | * Process special flags, such as IF or NELF |
||||
| 1586 | * |
||||
| 1587 | * @param content Text to be examined and changed |
||||
|
0 ignored issues
–
show
The type
EGroupware\Api\Storage\Text was not found. Maybe you did not declare it correctly or list all dependencies?
The issue could also be caused by a filter entry in the build configuration.
If the path has been excluded in your configuration, e.g. filter:
dependency_paths: ["lib/*"]
For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths Loading history...
|
|||||
| 1588 | * @param replacements array of markers => replacement |
||||
| 1589 | * |
||||
| 1590 | * @return changed content |
||||
|
0 ignored issues
–
show
The type
EGroupware\Api\Storage\changed was not found. Maybe you did not declare it correctly or list all dependencies?
The issue could also be caused by a filter entry in the build configuration.
If the path has been excluded in your configuration, e.g. filter:
dependency_paths: ["lib/*"]
For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths Loading history...
|
|||||
| 1591 | */ |
||||
| 1592 | private function process_commands($content, $replacements) |
||||
| 1593 | { |
||||
| 1594 | if (strpos($content,'$$IF') !== false) |
||||
| 1595 | { //Example use to use: $$IF n_prefix~Herr~Sehr geehrter~Sehr geehrte$$ |
||||
| 1596 | $this->replacements =& $replacements; |
||||
|
0 ignored issues
–
show
|
|||||
| 1597 | $content = preg_replace_callback('/\$\$IF ([#0-9a-z_\/-]+)~(.*)~(.*)~(.*)\$\$/imU',Array($this,'replace_callback'),$content); |
||||
| 1598 | unset($this->replacements); |
||||
| 1599 | } |
||||
| 1600 | if (strpos($content,'$$NELF') !== false) |
||||
| 1601 | { //Example: $$NEPBR org_unit$$ sets a LF and value of org_unit, only if there is a value |
||||
| 1602 | $this->replacements =& $replacements; |
||||
| 1603 | $content = preg_replace_callback('/\$\$NELF ([#0-9a-z_\/-]+)\$\$/imU',Array($this,'replace_callback'),$content); |
||||
| 1604 | unset($this->replacements); |
||||
| 1605 | } |
||||
| 1606 | if (strpos($content,'$$NENVLF') !== false) |
||||
| 1607 | { //Example: $$NEPBRNV org_unit$$ sets only a LF if there is a value for org_units, but did not add any value |
||||
| 1608 | $this->replacements =& $replacements; |
||||
| 1609 | $content = preg_replace_callback('/\$\$NENVLF ([#0-9a-z_\/-]+)\$\$/imU',Array($this,'replace_callback'),$content); |
||||
| 1610 | unset($this->replacements); |
||||
| 1611 | } |
||||
| 1612 | if (strpos($content,'$$LETTERPREFIX$$') !== false) |
||||
| 1613 | { //Example use to use: $$LETTERPREFIX$$ |
||||
| 1614 | $LETTERPREFIXCUSTOM = '$$LETTERPREFIXCUSTOM n_prefix title n_family$$'; |
||||
| 1615 | $content = str_replace('$$LETTERPREFIX$$',$LETTERPREFIXCUSTOM,$content); |
||||
| 1616 | } |
||||
| 1617 | if (strpos($content,'$$LETTERPREFIXCUSTOM') !== false) |
||||
| 1618 | { //Example use to use for a custom Letter Prefix: $$LETTERPREFIX n_prefix title n_family$$ |
||||
| 1619 | $this->replacements =& $replacements; |
||||
| 1620 | $content = preg_replace_callback('/\$\$LETTERPREFIXCUSTOM ([#0-9a-z_-]+)(.*)\$\$/imU',Array($this,'replace_callback'),$content); |
||||
| 1621 | unset($this->replacements); |
||||
| 1622 | } |
||||
| 1623 | return $content; |
||||
| 1624 | } |
||||
| 1625 | |||||
| 1626 | /** |
||||
| 1627 | * Callback for preg_replace to process $$IF |
||||
| 1628 | * |
||||
| 1629 | * @param array $param |
||||
| 1630 | * @return string |
||||
| 1631 | */ |
||||
| 1632 | private function replace_callback($param) |
||||
| 1633 | { |
||||
| 1634 | if (array_key_exists('$$'.$param[4].'$$',$this->replacements)) $param[4] = $this->replacements['$$'.$param[4].'$$']; |
||||
| 1635 | if (array_key_exists('$$'.$param[3].'$$',$this->replacements)) $param[3] = $this->replacements['$$'.$param[3].'$$']; |
||||
| 1636 | |||||
| 1637 | $pattern = '/'.preg_quote($param[2], '/').'/'; |
||||
| 1638 | if (strpos($param[0],'$$IF') === 0 && (trim($param[2]) == "EMPTY" || $param[2] === '')) |
||||
| 1639 | { |
||||
| 1640 | $pattern = '/^$/'; |
||||
| 1641 | } |
||||
| 1642 | $replace = preg_match($pattern,$this->replacements['$$'.$param[1].'$$']) ? $param[3] : $param[4]; |
||||
| 1643 | switch($this->mimetype) |
||||
| 1644 | { |
||||
| 1645 | case 'application/vnd.oasis.opendocument.text': // open office |
||||
| 1646 | case 'application/vnd.oasis.opendocument.spreadsheet': |
||||
| 1647 | case 'application/vnd.oasis.opendocument.presentation': |
||||
| 1648 | case 'application/vnd.oasis.opendocument.text-template': |
||||
| 1649 | case 'application/vnd.oasis.opendocument.spreadsheet-template': |
||||
| 1650 | case 'application/vnd.oasis.opendocument.presentation-template': |
||||
| 1651 | case 'application/vnd.openxmlformats-officedocument.wordprocessingml.document': // ms office 2007 |
||||
| 1652 | case 'application/vnd.ms-word.document.macroenabled.12': |
||||
| 1653 | case 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet': |
||||
| 1654 | case 'application/vnd.ms-excel.sheet.macroenabled.12': |
||||
| 1655 | case 'application/xml': |
||||
| 1656 | case 'text/xml': |
||||
| 1657 | case 'text/html': |
||||
| 1658 | $is_xml = true; |
||||
| 1659 | break; |
||||
| 1660 | } |
||||
| 1661 | |||||
| 1662 | switch($this->mimetype) |
||||
| 1663 | { |
||||
| 1664 | case 'application/rtf': |
||||
| 1665 | case 'text/rtf': |
||||
| 1666 | $LF = '}\par \pard\plain{'; |
||||
| 1667 | break; |
||||
| 1668 | case 'application/vnd.oasis.opendocument.text': |
||||
| 1669 | case 'application/vnd.oasis.opendocument.presentation': |
||||
| 1670 | case 'application/vnd.oasis.opendocument.text-template': |
||||
| 1671 | case 'application/vnd.oasis.opendocument.presentation-template': |
||||
| 1672 | $LF ='<text:line-break/>'; |
||||
| 1673 | break; |
||||
| 1674 | case 'application/vnd.oasis.opendocument.spreadsheet': // open office calc |
||||
| 1675 | case 'application/vnd.oasis.opendocument.spreadsheet-template': |
||||
| 1676 | $LF = '</text:p><text:p>'; |
||||
| 1677 | break; |
||||
| 1678 | case 'application/xmlExcel.Sheet': // Excel 2003 |
||||
| 1679 | $LF = ' '; |
||||
| 1680 | break; |
||||
| 1681 | case 'application/vnd.openxmlformats-officedocument.wordprocessingml.document': |
||||
| 1682 | case 'application/vnd.ms-word.document.macroenabled.12': |
||||
| 1683 | case 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet': |
||||
| 1684 | case 'application/vnd.ms-excel.sheet.macroenabled.12': |
||||
| 1685 | $LF ='</w:t></w:r></w:p><w:p><w:r><w:t>'; |
||||
| 1686 | break; |
||||
| 1687 | case 'application/xml'; |
||||
| 1688 | $LF ='</w:t></w:r><w:r><w:br w:type="text-wrapping" w:clear="all"/></w:r><w:r><w:t>'; |
||||
| 1689 | break; |
||||
| 1690 | case 'text/html': |
||||
| 1691 | $LF = "<br/>"; |
||||
| 1692 | break; |
||||
| 1693 | default: |
||||
| 1694 | $LF = "\n"; |
||||
| 1695 | } |
||||
| 1696 | if($is_xml) { |
||||
| 1697 | $this->replacements = str_replace(array('&','&amp;','<','>',"\r","\n"),array('&','&','<','>','',$LF),$this->replacements); |
||||
|
0 ignored issues
–
show
|
|||||
| 1698 | } |
||||
| 1699 | if (strpos($param[0],'$$NELF') === 0) |
||||
| 1700 | { //sets a Pagebreak and value, only if the field has a value |
||||
| 1701 | if ($this->replacements['$$'.$param[1].'$$'] !='') $replace = $LF.$this->replacements['$$'.$param[1].'$$']; |
||||
| 1702 | } |
||||
| 1703 | if (strpos($param[0],'$$NENVLF') === 0) |
||||
| 1704 | { //sets a Pagebreak without any value, only if the field has a value |
||||
| 1705 | if ($this->replacements['$$'.$param[1].'$$'] !='') $replace = $LF; |
||||
| 1706 | } |
||||
| 1707 | if (strpos($param[0],'$$LETTERPREFIXCUSTOM') === 0) |
||||
| 1708 | { //sets a Letterprefix |
||||
| 1709 | $replaceprefixsort = array(); |
||||
| 1710 | // ToDo Stefan: $contentstart is NOT defined here!!! |
||||
| 1711 | $replaceprefix = explode(' ',substr($param[0],21,-2)); |
||||
| 1712 | foreach ($replaceprefix as $nameprefix) |
||||
| 1713 | { |
||||
| 1714 | if ($this->replacements['$$'.$nameprefix.'$$'] !='') $replaceprefixsort[] = $this->replacements['$$'.$nameprefix.'$$']; |
||||
| 1715 | } |
||||
| 1716 | $replace = implode($replaceprefixsort,' '); |
||||
|
0 ignored issues
–
show
The call to
implode() has too many arguments starting with ' '.
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue. If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress. Please note the @ignore annotation hint above. Loading history...
|
|||||
| 1717 | } |
||||
| 1718 | return $replace; |
||||
| 1719 | } |
||||
| 1720 | |||||
| 1721 | /** |
||||
| 1722 | * Download document merged with contact(s) |
||||
| 1723 | * |
||||
| 1724 | * @param string $document vfs-path of document |
||||
| 1725 | * @param array $ids array with contact id(s) |
||||
| 1726 | * @param string $name ='' name to use for downloaded document |
||||
| 1727 | * @param string $dirs comma or whitespace separated directories, used if $document is a relative path |
||||
| 1728 | * @return string with error-message on error, otherwise it does NOT return |
||||
| 1729 | */ |
||||
| 1730 | public function download($document, $ids, $name='', $dirs='') |
||||
| 1731 | { |
||||
| 1732 | $result = $this->merge_file($document, $ids, $name, $dirs, $header); |
||||
| 1733 | |||||
| 1734 | if(is_file($result) && is_readable($result)) |
||||
| 1735 | { |
||||
| 1736 | Api\Header\Content::type($header['name'],$header['mime'],$header['filesize']); |
||||
| 1737 | readfile($result,'r'); |
||||
| 1738 | exit; |
||||
|
0 ignored issues
–
show
|
|||||
| 1739 | } |
||||
| 1740 | |||||
| 1741 | return $result; |
||||
| 1742 | } |
||||
| 1743 | |||||
| 1744 | /** |
||||
| 1745 | * Merge the IDs into the document, puts the document into the output buffer |
||||
| 1746 | * |
||||
| 1747 | * @param string $document vfs-path of document |
||||
| 1748 | * @param array $ids array with contact id(s) |
||||
| 1749 | * @param string $name ='' name to use for downloaded document |
||||
| 1750 | * @param string $dirs comma or whitespace separated directories, used if $document is a relative path |
||||
| 1751 | * @param Array $header File name, mime & filesize if you want to send a header |
||||
| 1752 | * |
||||
| 1753 | * @return string with error-message on error |
||||
| 1754 | * @throws Api\Exception |
||||
| 1755 | */ |
||||
| 1756 | public function merge_file($document, $ids, &$name='', $dirs='', &$header) |
||||
|
0 ignored issues
–
show
Parameters which have default values should be placed at the end.
If you place a parameter with a default value before a parameter with a default value, the default value of the first parameter will never be used as it will always need to be passed anyway: // $a must always be passed; it's default value is never used.
function someFunction($a = 5, $b) { }
Loading history...
|
|||||
| 1757 | { |
||||
| 1758 | //error_log(__METHOD__."('$document', ".array2string($ids).", '$name', dirs='$dirs') ->".function_backtrace()); |
||||
| 1759 | if (($error = $this->check_document($document, $dirs))) |
||||
| 1760 | { |
||||
| 1761 | return $error; |
||||
| 1762 | } |
||||
| 1763 | $content_url = Api\Vfs::PREFIX.$document; |
||||
| 1764 | switch (($mimetype = Api\Vfs::mime_content_type($document))) |
||||
| 1765 | { |
||||
| 1766 | case 'message/rfc822': |
||||
| 1767 | //error_log(__METHOD__."('$document', ".array2string($ids).", '$name', dirs='$dirs')=>$content_url ->".function_backtrace()); |
||||
| 1768 | $mail_bo = Api\Mail::getInstance(); |
||||
| 1769 | $mail_bo->openConnection(); |
||||
| 1770 | try |
||||
| 1771 | { |
||||
| 1772 | $msgs = $mail_bo->importMessageToMergeAndSend($this, $content_url, $ids, $_folder=($this->keep_emails ? '' : FALSE)); |
||||
|
0 ignored issues
–
show
$_folder = $this->keep_emails ? '' : FALSE cannot be passed to EGroupware\Api\Mail::importMessageToMergeAndSend() as the parameter $_folder expects a reference.
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
Loading history...
|
|||||
| 1773 | } |
||||
| 1774 | catch (Api\Exception\WrongUserinput $e) |
||||
| 1775 | { |
||||
| 1776 | // if this returns with an exeption, something failed big time |
||||
| 1777 | return $e->getMessage(); |
||||
| 1778 | } |
||||
| 1779 | //error_log(__METHOD__.__LINE__.' Message after importMessageToMergeAndSend:'.array2string($msgs)); |
||||
| 1780 | $retString = ''; |
||||
| 1781 | if (count($msgs['success'])>0) $retString .= count($msgs['success']).' '.(count($msgs['success'])+count($msgs['failed'])==1?lang('Message prepared for sending.'):lang('Message(s) send ok.'));//implode('<br />',$msgs['success']); |
||||
| 1782 | //if (strlen($retString)>0) $retString .= '<br />'; |
||||
| 1783 | foreach($msgs['failed'] as $c =>$e) |
||||
| 1784 | { |
||||
| 1785 | $errorString .= lang('contact').' '.lang('id').':'.$c.'->'.$e.'.'; |
||||
|
0 ignored issues
–
show
Comprehensibility
Best Practice
introduced
by
|
|||||
| 1786 | } |
||||
| 1787 | if (count($msgs['failed'])>0) $retString .= count($msgs['failed']).' '.lang('Message(s) send failed!').'=>'.$errorString; |
||||
| 1788 | return $retString; |
||||
| 1789 | case 'application/vnd.oasis.opendocument.text': |
||||
| 1790 | case 'application/vnd.oasis.opendocument.spreadsheet': |
||||
| 1791 | case 'application/vnd.oasis.opendocument.presentation': |
||||
| 1792 | case 'application/vnd.oasis.opendocument.text-template': |
||||
| 1793 | case 'application/vnd.oasis.opendocument.spreadsheet-template': |
||||
| 1794 | case 'application/vnd.oasis.opendocument.presentation-template': |
||||
| 1795 | switch($mimetype) |
||||
| 1796 | { |
||||
| 1797 | case 'application/vnd.oasis.opendocument.text': $ext = '.odt'; break; |
||||
| 1798 | case 'application/vnd.oasis.opendocument.spreadsheet': $ext = '.ods'; break; |
||||
| 1799 | case 'application/vnd.oasis.opendocument.presentation': $ext = '.odp'; break; |
||||
| 1800 | case 'application/vnd.oasis.opendocument.text-template': $ext = '.ott'; break; |
||||
| 1801 | case 'application/vnd.oasis.opendocument.spreadsheet-template': $ext = '.ots'; break; |
||||
| 1802 | case 'application/vnd.oasis.opendocument.presentation-template': $ext = '.otp'; break; |
||||
| 1803 | } |
||||
| 1804 | $archive = tempnam($GLOBALS['egw_info']['server']['temp_dir'], basename($document,$ext).'-').$ext; |
||||
| 1805 | copy($content_url,$archive); |
||||
| 1806 | $content_url = 'zip://'.$archive.'#'.($content_file = 'content.xml'); |
||||
| 1807 | $this->parse_html_styles = true; |
||||
| 1808 | break; |
||||
| 1809 | case 'application/vnd.openxmlformats-officedocument.wordprocessingml.d': // mimetypes in vfs are limited to 64 chars |
||||
| 1810 | $mimetype = 'application/vnd.openxmlformats-officedocument.wordprocessingml.document'; |
||||
| 1811 | case 'application/vnd.openxmlformats-officedocument.wordprocessingml.document': |
||||
| 1812 | case 'application/vnd.ms-word.document.macroenabled.12': |
||||
| 1813 | $archive = tempnam($GLOBALS['egw_info']['server']['temp_dir'], basename($document,'.docx').'-').'.docx'; |
||||
| 1814 | copy($content_url,$archive); |
||||
| 1815 | $content_url = 'zip://'.$archive.'#'.($content_file = 'word/document.xml'); |
||||
| 1816 | $fix = array( // regular expression to fix garbled placeholders |
||||
| 1817 | '/'.preg_quote('$$</w:t></w:r><w:proofErr w:type="spellStart"/><w:r><w:t>','/').'([a-z0-9_]+)'. |
||||
| 1818 | preg_quote('</w:t></w:r><w:proofErr w:type="spellEnd"/><w:r><w:t>','/').'/i' => '$$\\1$$', |
||||
| 1819 | '/'.preg_quote('$$</w:t></w:r><w:proofErr w:type="spellStart"/><w:r><w:rPr><w:lang w:val="','/'). |
||||
| 1820 | '([a-z]{2}-[A-Z]{2})'.preg_quote('"/></w:rPr><w:t>','/').'([a-z0-9_]+)'. |
||||
| 1821 | preg_quote('</w:t></w:r><w:proofErr w:type="spellEnd"/><w:r><w:rPr><w:lang w:val="','/'). |
||||
| 1822 | '([a-z]{2}-[A-Z]{2})'.preg_quote('"/></w:rPr><w:t>$$','/').'/i' => '$$\\2$$', |
||||
| 1823 | '/'.preg_quote('$</w:t></w:r><w:proofErr w:type="spellStart"/><w:r><w:t>','/').'([a-z0-9_]+)'. |
||||
| 1824 | preg_quote('</w:t></w:r><w:proofErr w:type="spellEnd"/><w:r><w:t>','/').'/i' => '$\\1$', |
||||
| 1825 | '/'.preg_quote('$ $</w:t></w:r><w:proofErr w:type="spellStart"/><w:r><w:t>','/').'([a-z0-9_]+)'. |
||||
| 1826 | preg_quote('</w:t></w:r><w:proofErr w:type="spellEnd"/><w:r><w:t>','/').'/i' => '$ $\\1$ $', |
||||
| 1827 | ); |
||||
| 1828 | break; |
||||
| 1829 | case 'application/xml': |
||||
| 1830 | $fix = array( // hack to get Excel 2003 to display additional rows in tables |
||||
| 1831 | '/ss:ExpandedRowCount="\d+"/' => 'ss:ExpandedRowCount="9999"', |
||||
| 1832 | ); |
||||
| 1833 | break; |
||||
| 1834 | case 'application/vnd.openxmlformats-officedocument.spreadsheetml.shee': |
||||
| 1835 | $mimetype = 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'; |
||||
| 1836 | case 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet': |
||||
| 1837 | case 'application/vnd.ms-excel.sheet.macroenabled.12': |
||||
| 1838 | $fix = array( // hack to get Excel 2007 to display additional rows in tables |
||||
| 1839 | '/ss:ExpandedRowCount="\d+"/' => 'ss:ExpandedRowCount="9999"', |
||||
| 1840 | ); |
||||
| 1841 | $archive = tempnam($GLOBALS['egw_info']['server']['temp_dir'], basename($document,'.xlsx').'-').'.xlsx'; |
||||
| 1842 | copy($content_url,$archive); |
||||
| 1843 | $content_url = 'zip://'.$archive.'#'.($content_file = 'xl/sharedStrings.xml'); |
||||
| 1844 | break; |
||||
| 1845 | } |
||||
| 1846 | $err = null; |
||||
| 1847 | if (!($merged =& $this->merge($content_url,$ids,$err,$mimetype,$fix))) |
||||
| 1848 | { |
||||
| 1849 | //error_log(__METHOD__."() !this->merge() err=$err"); |
||||
| 1850 | return $err; |
||||
| 1851 | } |
||||
| 1852 | // Apply HTML formatting to target document, if possible |
||||
| 1853 | // check if we can use the XSL extension, to not give a fatal error and rendering whole merge-print non-functional |
||||
| 1854 | if (class_exists('XSLTProcessor') && class_exists('DOMDocument') && $this->parse_html_styles) |
||||
| 1855 | { |
||||
| 1856 | try |
||||
| 1857 | { |
||||
| 1858 | $this->apply_styles($merged, $mimetype); |
||||
| 1859 | } |
||||
| 1860 | catch (\Exception $e) |
||||
| 1861 | { |
||||
| 1862 | // Error converting HTML styles over |
||||
| 1863 | error_log($e->getMessage()); |
||||
| 1864 | error_log("Target document: $content_url, IDs: ". array2string($ids)); |
||||
| 1865 | |||||
| 1866 | // Try again, but strip HTML so user gets something |
||||
| 1867 | $this->parse_html_styles = false; |
||||
| 1868 | if (!($merged =& $this->merge($content_url,$ids,$err,$mimetype,$fix))) |
||||
| 1869 | { |
||||
| 1870 | return $err; |
||||
| 1871 | } |
||||
| 1872 | } |
||||
| 1873 | if ($this->report_memory_usage) error_log(__METHOD__."() after HTML processing ".Api\Vfs::hsize(memory_get_peak_usage(true))); |
||||
| 1874 | } |
||||
| 1875 | if(!empty($name)) |
||||
| 1876 | { |
||||
| 1877 | if(empty($ext)) |
||||
| 1878 | { |
||||
| 1879 | $ext = '.'.pathinfo($document,PATHINFO_EXTENSION); |
||||
| 1880 | } |
||||
| 1881 | $name .= $ext; |
||||
| 1882 | } |
||||
| 1883 | else |
||||
| 1884 | { |
||||
| 1885 | $name = basename($document); |
||||
| 1886 | } |
||||
| 1887 | $header = array('name' => $name, 'mime' => $mimetype); |
||||
| 1888 | if (isset($archive)) |
||||
| 1889 | { |
||||
| 1890 | $zip = new ZipArchive; |
||||
| 1891 | if ($zip->open($archive, ZipArchive::CHECKCONS) !== true) |
||||
| 1892 | { |
||||
| 1893 | error_log(__METHOD__.__LINE__." !ZipArchive::open('$archive',ZIPARCHIVE"."::CHECKCONS) failed. Trying open without validating"); |
||||
| 1894 | if ($zip->open($archive) !== true) throw new Api\Exception("!ZipArchive::open('$archive',|ZIPARCHIVE::CHECKCONS)"); |
||||
| 1895 | } |
||||
| 1896 | if ($zip->addFromString($content_file,$merged) !== true) throw new Api\Exception("!ZipArchive::addFromString('$content_file',\$merged)"); |
||||
| 1897 | if ($zip->close() !== true) throw new Api\Exception("!ZipArchive::close()"); |
||||
| 1898 | unset($zip); |
||||
| 1899 | unset($merged); |
||||
| 1900 | if ($this->report_memory_usage) error_log(__METHOD__."() after ZIP processing ".Api\Vfs::hsize(memory_get_peak_usage(true))); |
||||
| 1901 | $header['filesize'] = filesize($archive); |
||||
| 1902 | } |
||||
| 1903 | else |
||||
| 1904 | { |
||||
| 1905 | $archive = tempnam($GLOBALS['egw_info']['server']['temp_dir'], basename($document,'.'.$ext).'-').'.'.$ext; |
||||
| 1906 | if ($mimetype == 'application/xml') |
||||
| 1907 | { |
||||
| 1908 | if (strpos($merged,'<?mso-application progid="Word.Document"?>') !== false) |
||||
| 1909 | { |
||||
| 1910 | $header['mimetype'] = 'application/msword'; // to open it automatically in word or oowriter |
||||
| 1911 | } |
||||
| 1912 | elseif (strpos($merged,'<?mso-application progid="Excel.Sheet"?>') !== false) |
||||
| 1913 | { |
||||
| 1914 | $header['mimetype'] = 'application/vnd.ms-excel'; // to open it automatically in excel or oocalc |
||||
| 1915 | } |
||||
| 1916 | } |
||||
| 1917 | $handle = fopen($archive, 'w'); |
||||
| 1918 | fwrite($handle, $merged); |
||||
| 1919 | fclose($handle); |
||||
| 1920 | } |
||||
| 1921 | return $archive; |
||||
| 1922 | } |
||||
| 1923 | |||||
| 1924 | /** |
||||
| 1925 | * Download document merged with contact(s) |
||||
| 1926 | * frontend for HTTP POST requests |
||||
| 1927 | * accepts POST vars and calls internal function download() |
||||
| 1928 | * string data_document_name: the document name |
||||
| 1929 | * string data_document_dir: the document vfs directory |
||||
| 1930 | * string data_checked: contact id(s) to merge with (can be comma separated) |
||||
| 1931 | * |
||||
| 1932 | * @return string with error-message on error, otherwise it does NOT return |
||||
| 1933 | */ |
||||
| 1934 | public function download_by_request() |
||||
| 1935 | { |
||||
| 1936 | if(empty($_POST['data_document_name'])) return false; |
||||
| 1937 | if(empty($_POST['data_document_dir'])) return false; |
||||
| 1938 | if(empty($_POST['data_checked'])) return false; |
||||
| 1939 | |||||
| 1940 | return $this->download( |
||||
| 1941 | $_POST['data_document_name'], |
||||
| 1942 | explode(',',$_POST['data_checked']), |
||||
| 1943 | '', |
||||
| 1944 | $_POST['data_document_dir'] |
||||
| 1945 | ); |
||||
| 1946 | } |
||||
| 1947 | |||||
| 1948 | /** |
||||
| 1949 | * Get a list of document actions / files from the given directory |
||||
| 1950 | * |
||||
| 1951 | * @param string $dirs Directory(s comma or space separated) to search |
||||
| 1952 | * @param string $prefix='document_' prefix for array keys |
||||
| 1953 | * @param array|string $mime_filter=null allowed mime type(s), default all, negative filter if $mime_filter[0] === '!' |
||||
| 1954 | * @return array List of documents, suitable for a selectbox. The key is document_<filename>. |
||||
| 1955 | */ |
||||
| 1956 | public static function get_documents($dirs, $prefix='document_', $mime_filter=null, $app='') |
||||
| 1957 | { |
||||
| 1958 | $export_limit=self::getExportLimit($app); |
||||
| 1959 | if (!$dirs || (!self::hasExportLimit($export_limit,'ISALLOWED') && !self::is_export_limit_excepted())) return array(); |
||||
| 1960 | |||||
| 1961 | // split multiple comma or whitespace separated directories |
||||
| 1962 | // to still allow space or comma in dirnames, we also use the trailing slash of all pathes to split |
||||
| 1963 | if (count($dirs = preg_split('/[,\s]+\//', $dirs)) > 1) |
||||
| 1964 | { |
||||
| 1965 | foreach($dirs as $n => &$d) |
||||
| 1966 | { |
||||
| 1967 | if ($n) $d = '/'.$d; // re-adding trailing slash removed by split |
||||
| 1968 | } |
||||
| 1969 | } |
||||
| 1970 | if ($mime_filter && ($negativ_filter = $mime_filter[0] === '!')) |
||||
| 1971 | { |
||||
| 1972 | if (is_array($mime_filter)) |
||||
| 1973 | { |
||||
| 1974 | unset($mime_filter[0]); |
||||
| 1975 | } |
||||
| 1976 | else |
||||
| 1977 | { |
||||
| 1978 | $mime_filter = substr($mime_filter, 1); |
||||
| 1979 | } |
||||
| 1980 | } |
||||
| 1981 | $list = array(); |
||||
| 1982 | foreach($dirs as $dir) |
||||
| 1983 | { |
||||
| 1984 | if (($files = Api\Vfs::find($dir,array('need_mime'=>true),true))) |
||||
| 1985 | { |
||||
| 1986 | foreach($files as $file) |
||||
| 1987 | { |
||||
| 1988 | // return only the mime-types we support |
||||
| 1989 | $parts = explode('.',$file['name']); |
||||
| 1990 | if (!self::is_implemented($file['mime'],'.'.array_pop($parts))) continue; |
||||
| 1991 | if ($mime_filter && $negativ_filter === in_array($file['mime'], (array)$mime_filter)) continue; |
||||
| 1992 | $list[$prefix.$file['name']] = Api\Vfs::decodePath($file['name']); |
||||
| 1993 | } |
||||
| 1994 | } |
||||
| 1995 | } |
||||
| 1996 | return $list; |
||||
| 1997 | } |
||||
| 1998 | |||||
| 1999 | /** |
||||
| 2000 | * From this number of documents, show them in submenus by mime type |
||||
| 2001 | */ |
||||
| 2002 | const SHOW_DOCS_BY_MIME_LIMIT = 10; |
||||
| 2003 | |||||
| 2004 | /** |
||||
| 2005 | * Get insert-in-document action with optional default document on top |
||||
| 2006 | * |
||||
| 2007 | * If more than SHOW_DOCS_BY_MIME_LIMIT=10 documents found, they are displayed in submenus by mime type. |
||||
| 2008 | * |
||||
| 2009 | * @param string $dirs Directory(s comma or space separated) to search |
||||
| 2010 | * @param int $group see nextmatch_widget::egw_actions |
||||
| 2011 | * @param string $caption ='Insert in document' |
||||
| 2012 | * @param string $prefix ='document_' |
||||
| 2013 | * @param string $default_doc ='' full path to default document to show on top with action == 'document'! |
||||
| 2014 | * @param int|string $export_limit =null export-limit, default $GLOBALS['egw_info']['server']['export_limit'] |
||||
| 2015 | * @return array see nextmatch_widget::egw_actions |
||||
| 2016 | */ |
||||
| 2017 | public static function document_action($dirs, $group=0, $caption='Insert in document', $prefix='document_', $default_doc='', |
||||
| 2018 | $export_limit=null) |
||||
| 2019 | { |
||||
| 2020 | $documents = array(); |
||||
| 2021 | $editable_mimes = array(); |
||||
| 2022 | if ($export_limit == null) $export_limit = self::getExportLimit(); // check if there is a globalsetting |
||||
|
0 ignored issues
–
show
|
|||||
| 2023 | |||||
| 2024 | try { |
||||
| 2025 | if (class_exists('EGroupware\\collabora\\Bo') && |
||||
| 2026 | $GLOBALS['egw_info']['user']['apps']['collabora'] && |
||||
| 2027 | ($discovery = \EGroupware\collabora\Bo::discover()) && |
||||
|
0 ignored issues
–
show
The type
EGroupware\collabora\Bo was not found. Maybe you did not declare it correctly or list all dependencies?
The issue could also be caused by a filter entry in the build configuration.
If the path has been excluded in your configuration, e.g. filter:
dependency_paths: ["lib/*"]
For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths Loading history...
|
|||||
| 2028 | $GLOBALS['egw_info']['user']['preferences']['filemanager']['merge_open_handler'] != 'download' |
||||
| 2029 | ) |
||||
| 2030 | { |
||||
| 2031 | $editable_mimes = $discovery; |
||||
| 2032 | } |
||||
| 2033 | } |
||||
| 2034 | catch (\Exception $e) |
||||
| 2035 | { |
||||
| 2036 | // ignore failed discovery |
||||
| 2037 | unset($e); |
||||
| 2038 | } |
||||
| 2039 | if ($default_doc && ($file = Api\Vfs::stat($default_doc))) // put default document on top |
||||
| 2040 | { |
||||
| 2041 | if(!$file['mime']) |
||||
| 2042 | { |
||||
| 2043 | $file['mime'] = Api\Vfs::mime_content_type($default_doc); |
||||
| 2044 | $file['path'] = $default_doc; |
||||
| 2045 | } |
||||
| 2046 | $documents['document'] = array( |
||||
| 2047 | 'icon' => Api\Vfs::mime_icon($file['mime']), |
||||
| 2048 | 'caption' => Api\Vfs::decodePath(Api\Vfs::basename($default_doc)), |
||||
| 2049 | 'group' => 1, |
||||
| 2050 | 'postSubmit' => true, // download needs post submit (not Ajax) to work |
||||
| 2051 | ); |
||||
| 2052 | if ($file['mime'] == 'message/rfc822') |
||||
| 2053 | { |
||||
| 2054 | self::document_mail_action($documents['document'], $file); |
||||
| 2055 | } |
||||
| 2056 | else if ($editable_mimes[$file['mime']]) |
||||
| 2057 | { |
||||
| 2058 | self::document_editable_action($documents['document'], $file); |
||||
| 2059 | } |
||||
| 2060 | } |
||||
| 2061 | |||||
| 2062 | $files = array(); |
||||
| 2063 | if ($dirs) |
||||
| 2064 | { |
||||
| 2065 | // split multiple comma or whitespace separated directories |
||||
| 2066 | // to still allow space or comma in dirnames, we also use the trailing slash of all pathes to split |
||||
| 2067 | if (count($dirs = preg_split('/[,\s]+\//', $dirs)) > 1) |
||||
| 2068 | { |
||||
| 2069 | foreach($dirs as $n => &$d) |
||||
| 2070 | { |
||||
| 2071 | if ($n) $d = '/'.$d; // re-adding trailing slash removed by split |
||||
| 2072 | } |
||||
| 2073 | } |
||||
| 2074 | foreach($dirs as $dir) |
||||
| 2075 | { |
||||
| 2076 | $files += Api\Vfs::find($dir,array( |
||||
| 2077 | 'need_mime' => true, |
||||
| 2078 | 'order' => 'fs_name', |
||||
| 2079 | 'sort' => 'ASC', |
||||
| 2080 | ),true); |
||||
| 2081 | } |
||||
| 2082 | } |
||||
| 2083 | |||||
| 2084 | $dircount = array(); |
||||
| 2085 | foreach($files as $key => $file) |
||||
| 2086 | { |
||||
| 2087 | // use only the mime-types we support |
||||
| 2088 | $parts = explode('.',$file['name']); |
||||
| 2089 | if (!self::is_implemented($file['mime'],'.'.array_pop($parts)) || |
||||
| 2090 | !Api\Vfs::check_access($file['path'], Api\Vfs::READABLE, $file) || // remove files not readable by user |
||||
| 2091 | $file['path'] === $default_doc) // default doc already added |
||||
| 2092 | { |
||||
| 2093 | unset($files[$key]); |
||||
| 2094 | } |
||||
| 2095 | else |
||||
| 2096 | { |
||||
| 2097 | $dirname = Api\Vfs::dirname($file['path']); |
||||
| 2098 | if(!isset($dircount[$dirname])) |
||||
| 2099 | { |
||||
| 2100 | $dircount[$dirname] = 1; |
||||
| 2101 | } |
||||
| 2102 | else |
||||
| 2103 | { |
||||
| 2104 | $dircount[$dirname] ++; |
||||
| 2105 | } |
||||
| 2106 | } |
||||
| 2107 | } |
||||
| 2108 | foreach($files as $file) |
||||
| 2109 | { |
||||
| 2110 | if (count($dircount) > 1) |
||||
| 2111 | { |
||||
| 2112 | $name_arr = explode('/', $file['name']); |
||||
| 2113 | $current_level = &$documents; |
||||
| 2114 | for($count = 0; $count < count($name_arr); $count++) |
||||
|
0 ignored issues
–
show
It seems like you are calling the size function
count() as part of the test condition. You might want to compute the size beforehand, and not on each iteration.
If the size of the collection does not change during the iteration, it is generally a good practice to compute it beforehand, and not on each iteration: for ($i=0; $i<count($array); $i++) { // calls count() on each iteration
}
// Better
for ($i=0, $c=count($array); $i<$c; $i++) { // calls count() just once
}
Loading history...
|
|||||
| 2115 | { |
||||
| 2116 | if($count == 0) |
||||
| 2117 | { |
||||
| 2118 | $current_level = &$documents; |
||||
| 2119 | } |
||||
| 2120 | else |
||||
| 2121 | { |
||||
| 2122 | $current_level = &$current_level[$prefix.$name_arr[($count-1)]]['children']; |
||||
| 2123 | } |
||||
| 2124 | switch($count) |
||||
| 2125 | { |
||||
| 2126 | case (count($name_arr)-1): |
||||
| 2127 | $current_level[$prefix.$file['name']] = array( |
||||
| 2128 | 'icon' => Api\Vfs::mime_icon($file['mime']), |
||||
| 2129 | 'caption' => Api\Vfs::decodePath($name_arr[$count]), |
||||
| 2130 | 'group' => 2, |
||||
| 2131 | 'postSubmit' => true, // download needs post submit (not Ajax) to work |
||||
| 2132 | ); |
||||
| 2133 | if ($file['mime'] == 'message/rfc822') |
||||
| 2134 | { |
||||
| 2135 | self::document_mail_action($current_level[$prefix.$file['name']], $file); |
||||
| 2136 | } |
||||
| 2137 | else if ($editable_mimes[$file['mime']]) |
||||
| 2138 | { |
||||
| 2139 | self::document_editable_action($current_level[$prefix.$file['name']], $file); |
||||
| 2140 | } |
||||
| 2141 | break; |
||||
| 2142 | |||||
| 2143 | default: |
||||
| 2144 | if(!is_array($current_level[$prefix.$name_arr[$count]])) |
||||
| 2145 | { |
||||
| 2146 | // create parent folder |
||||
| 2147 | $current_level[$prefix.$name_arr[$count]] = array( |
||||
| 2148 | 'icon' => 'phpgwapi/foldertree_folder', |
||||
| 2149 | 'caption' => Api\Vfs::decodePath($name_arr[$count]), |
||||
| 2150 | 'group' => 2, |
||||
| 2151 | 'children' => array(), |
||||
| 2152 | ); |
||||
| 2153 | } |
||||
| 2154 | break; |
||||
| 2155 | } |
||||
| 2156 | } |
||||
| 2157 | } |
||||
| 2158 | else if (count($files) >= self::SHOW_DOCS_BY_MIME_LIMIT) |
||||
| 2159 | { |
||||
| 2160 | if (!isset($documents[$file['mime']])) |
||||
| 2161 | { |
||||
| 2162 | $documents[$file['mime']] = array( |
||||
| 2163 | 'icon' => Api\Vfs::mime_icon($file['mime']), |
||||
| 2164 | 'caption' => Api\MimeMagic::mime2label($file['mime']), |
||||
| 2165 | 'group' => 2, |
||||
| 2166 | 'children' => array(), |
||||
| 2167 | ); |
||||
| 2168 | } |
||||
| 2169 | $documents[$file['mime']]['children'][$prefix.$file['name']] = array( |
||||
| 2170 | 'caption' => Api\Vfs::decodePath($file['name']), |
||||
| 2171 | 'postSubmit' => true, // download needs post submit (not Ajax) to work |
||||
| 2172 | ); |
||||
| 2173 | if ($file['mime'] == 'message/rfc822') |
||||
| 2174 | { |
||||
| 2175 | self::document_mail_action($documents[$file['mime']]['children'][$prefix.$file['name']], $file); |
||||
| 2176 | } |
||||
| 2177 | else if ($editable_mimes[$file['mime']]) |
||||
| 2178 | { |
||||
| 2179 | self::document_editable_action($documents[$file['mime']]['children'][$prefix.$file['name']], $file); |
||||
| 2180 | } |
||||
| 2181 | } |
||||
| 2182 | else |
||||
| 2183 | { |
||||
| 2184 | $documents[$prefix.$file['name']] = array( |
||||
| 2185 | 'icon' => Api\Vfs::mime_icon($file['mime']), |
||||
| 2186 | 'caption' => Api\Vfs::decodePath($file['name']), |
||||
| 2187 | 'group' => 2, |
||||
| 2188 | 'postSubmit' => true, // download needs post submit (not Ajax) to work |
||||
| 2189 | ); |
||||
| 2190 | if ($file['mime'] == 'message/rfc822') |
||||
| 2191 | { |
||||
| 2192 | self::document_mail_action($documents[$prefix.$file['name']], $file); |
||||
| 2193 | } |
||||
| 2194 | else if ($editable_mimes[$file['mime']]) |
||||
| 2195 | { |
||||
| 2196 | self::document_editable_action($documents[$prefix.$file['name']], $file); |
||||
| 2197 | } |
||||
| 2198 | } |
||||
| 2199 | } |
||||
| 2200 | |||||
| 2201 | return array( |
||||
| 2202 | 'icon' => 'etemplate/merge', |
||||
| 2203 | 'caption' => $caption, |
||||
| 2204 | 'children' => $documents, |
||||
| 2205 | // disable action if no document or export completly forbidden for non-admins |
||||
| 2206 | 'enabled' => (boolean)$documents && (self::hasExportLimit($export_limit,'ISALLOWED') || self::is_export_limit_excepted()), |
||||
| 2207 | 'hideOnDisabled' => true, // do not show 'Insert in document', if no documents defined or no export allowed |
||||
| 2208 | 'group' => $group, |
||||
| 2209 | ); |
||||
| 2210 | } |
||||
| 2211 | |||||
| 2212 | /** |
||||
| 2213 | * Set up a document action for an eml (email) document |
||||
| 2214 | * |
||||
| 2215 | * Email (.eml) documents get special action handling. They don't send a file |
||||
| 2216 | * back to the client like the other documents. Merging for a single selected |
||||
| 2217 | * contact opens a compose window, multiple contacts just sends. |
||||
| 2218 | * |
||||
| 2219 | * @param Array &$action Action to be modified for mail |
||||
| 2220 | * @param Array $file Array of information about the document from Api\Vfs::find |
||||
| 2221 | * @return void |
||||
| 2222 | */ |
||||
| 2223 | private static function document_mail_action(Array &$action, $file) |
||||
| 2224 | { |
||||
| 2225 | unset($action['postSubmit']); |
||||
| 2226 | |||||
| 2227 | // Lots takes a while, confirm |
||||
| 2228 | $action['confirm_multiple'] = lang('Do you want to send the message to all selected entries, WITHOUT further editing?'); |
||||
| 2229 | |||||
| 2230 | // These parameters trigger compose + merge - only if 1 row |
||||
| 2231 | $extra = array( |
||||
| 2232 | 'from=merge', |
||||
| 2233 | 'document='.$file['path'], |
||||
| 2234 | 'merge='.get_called_class() |
||||
| 2235 | ); |
||||
| 2236 | |||||
| 2237 | // egw.open() used if only 1 row selected |
||||
| 2238 | $action['egw_open'] = 'edit-mail--'.implode('&',$extra); |
||||
| 2239 | $action['target'] = 'compose_' .$file['path']; |
||||
| 2240 | |||||
| 2241 | // long_task runs menuaction once for each selected row |
||||
| 2242 | $action['nm_action'] = 'long_task'; |
||||
| 2243 | $action['popup'] = Api\Link::get_registry('mail', 'edit_popup'); |
||||
| 2244 | $action['message'] = lang('insert in %1',Api\Vfs::decodePath($file['name'])); |
||||
|
0 ignored issues
–
show
The call to
lang() has too many arguments starting with EGroupware\Api\Vfs::decodePath($file['name']).
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue. If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress. Please note the @ignore annotation hint above. Loading history...
|
|||||
| 2245 | $action['menuaction'] = 'mail.mail_compose.ajax_merge&document='.$file['path'].'&merge='. get_called_class(); |
||||
| 2246 | } |
||||
| 2247 | |||||
| 2248 | /** |
||||
| 2249 | * Set up a document action so the generated file is saved and opened in |
||||
| 2250 | * the collabora editor (if collabora is available) |
||||
| 2251 | * |
||||
| 2252 | * @param Array &$action Action to be modified for editor |
||||
| 2253 | * @param Array $file Array of information about the document from Api\Vfs::find |
||||
| 2254 | * @return void |
||||
| 2255 | */ |
||||
| 2256 | private static function document_editable_action(Array &$action, $file) |
||||
| 2257 | { |
||||
| 2258 | unset($action['postSubmit']); |
||||
| 2259 | $action['nm_action'] = 'location'; |
||||
| 2260 | $action['url'] = urldecode(http_build_query(array( |
||||
| 2261 | 'menuaction' => 'collabora.EGroupware\\collabora\\Ui.merge_edit', |
||||
| 2262 | 'document' => $file['path'], |
||||
| 2263 | 'merge' => get_called_class(), |
||||
| 2264 | 'id' => '$id', |
||||
| 2265 | 'select_all' => '$select_all' |
||||
| 2266 | ))); |
||||
| 2267 | $action['target'] = '_blank'; |
||||
| 2268 | } |
||||
| 2269 | |||||
| 2270 | /** |
||||
| 2271 | * Check if given document (relative path from document_actions()) exists in one of the given dirs |
||||
| 2272 | * |
||||
| 2273 | * @param string &$document maybe relative path of document, on return true absolute path to existing document |
||||
| 2274 | * @param string $dirs comma or whitespace separated directories |
||||
| 2275 | * @return string|boolean false if document exists, otherwise string with error-message |
||||
| 2276 | */ |
||||
| 2277 | public static function check_document(&$document, $dirs) |
||||
| 2278 | { |
||||
| 2279 | if($document[0] !== '/') |
||||
| 2280 | { |
||||
| 2281 | // split multiple comma or whitespace separated directories |
||||
| 2282 | // to still allow space or comma in dirnames, we also use the trailing slash of all pathes to split |
||||
| 2283 | if ($dirs && ($dirs = preg_split('/[,\s]+\//', $dirs))) |
||||
| 2284 | { |
||||
| 2285 | foreach($dirs as $n => $dir) |
||||
| 2286 | { |
||||
| 2287 | if ($n) $dir = '/'.$dir; // re-adding trailing slash removed by split |
||||
| 2288 | if (Api\Vfs::stat($dir.'/'.$document) && Api\Vfs::is_readable($dir.'/'.$document)) |
||||
| 2289 | { |
||||
| 2290 | $document = $dir.'/'.$document; |
||||
| 2291 | return false; |
||||
| 2292 | } |
||||
| 2293 | } |
||||
| 2294 | } |
||||
| 2295 | } |
||||
| 2296 | elseif (Api\Vfs::stat($document) && Api\Vfs::is_readable($document)) |
||||
| 2297 | { |
||||
| 2298 | return false; |
||||
| 2299 | } |
||||
| 2300 | //error_log(__METHOD__."('$document', dirs='$dirs') returning 'Document '$document' does not exist or is not readable for you!'"); |
||||
| 2301 | return lang("Document '%1' does not exist or is not readable for you!",$document); |
||||
|
0 ignored issues
–
show
The call to
lang() has too many arguments starting with $document.
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue. If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress. Please note the @ignore annotation hint above. Loading history...
|
|||||
| 2302 | } |
||||
| 2303 | |||||
| 2304 | /** |
||||
| 2305 | * Get a list of supported extentions |
||||
| 2306 | */ |
||||
| 2307 | public static function get_file_extensions() |
||||
| 2308 | { |
||||
| 2309 | return array('txt', 'rtf', 'odt', 'ods', 'docx', 'xml', 'eml'); |
||||
| 2310 | } |
||||
| 2311 | |||||
| 2312 | /** |
||||
| 2313 | * Format a number according to user prefs with decimal and thousands separator |
||||
| 2314 | * |
||||
| 2315 | * Reimplemented from etemplate to NOT use user prefs for Excel 2003, which gives an xml error |
||||
| 2316 | * |
||||
| 2317 | * @param int|float|string $number |
||||
| 2318 | * @param int $num_decimal_places =2 |
||||
| 2319 | * @param string $_mimetype ='' |
||||
| 2320 | * @return string |
||||
| 2321 | */ |
||||
| 2322 | static public function number_format($number,$num_decimal_places=2,$_mimetype='') |
||||
| 2323 | { |
||||
| 2324 | if ((string)$number === '') return ''; |
||||
| 2325 | //error_log(__METHOD__.$_mimetype); |
||||
| 2326 | switch($_mimetype) |
||||
| 2327 | { |
||||
| 2328 | case 'application/xml': // Excel 2003 |
||||
| 2329 | case 'application/vnd.oasis.opendocument.spreadsheet': // OO.o spreadsheet |
||||
| 2330 | return number_format(str_replace(' ','',$number),$num_decimal_places,'.',''); |
||||
| 2331 | } |
||||
| 2332 | return Api\Etemplate::number_format($number,$num_decimal_places); |
||||
| 2333 | } |
||||
| 2334 | } |
||||
| 2335 |
The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g.
excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths