@@ -213,7 +213,7 @@ |
||
| 213 | 213 | /** |
| 214 | 214 | * removes an entry from the comments run time cache |
| 215 | 215 | * |
| 216 | - * @param mixed $id the comment's id |
|
| 216 | + * @param string $id the comment's id |
|
| 217 | 217 | */ |
| 218 | 218 | protected function uncache($id) { |
| 219 | 219 | $id = (string)$id; |
@@ -41,850 +41,850 @@ |
||
| 41 | 41 | |
| 42 | 42 | class Manager implements ICommentsManager { |
| 43 | 43 | |
| 44 | - /** @var IDBConnection */ |
|
| 45 | - protected $dbConn; |
|
| 46 | - |
|
| 47 | - /** @var ILogger */ |
|
| 48 | - protected $logger; |
|
| 49 | - |
|
| 50 | - /** @var IConfig */ |
|
| 51 | - protected $config; |
|
| 52 | - |
|
| 53 | - /** @var IComment[] */ |
|
| 54 | - protected $commentsCache = []; |
|
| 55 | - |
|
| 56 | - /** @var \Closure[] */ |
|
| 57 | - protected $eventHandlerClosures = []; |
|
| 58 | - |
|
| 59 | - /** @var ICommentsEventHandler[] */ |
|
| 60 | - protected $eventHandlers = []; |
|
| 61 | - |
|
| 62 | - /** @var \Closure[] */ |
|
| 63 | - protected $displayNameResolvers = []; |
|
| 64 | - |
|
| 65 | - /** |
|
| 66 | - * Manager constructor. |
|
| 67 | - * |
|
| 68 | - * @param IDBConnection $dbConn |
|
| 69 | - * @param ILogger $logger |
|
| 70 | - * @param IConfig $config |
|
| 71 | - */ |
|
| 72 | - public function __construct( |
|
| 73 | - IDBConnection $dbConn, |
|
| 74 | - ILogger $logger, |
|
| 75 | - IConfig $config |
|
| 76 | - ) { |
|
| 77 | - $this->dbConn = $dbConn; |
|
| 78 | - $this->logger = $logger; |
|
| 79 | - $this->config = $config; |
|
| 80 | - } |
|
| 81 | - |
|
| 82 | - /** |
|
| 83 | - * converts data base data into PHP native, proper types as defined by |
|
| 84 | - * IComment interface. |
|
| 85 | - * |
|
| 86 | - * @param array $data |
|
| 87 | - * @return array |
|
| 88 | - */ |
|
| 89 | - protected function normalizeDatabaseData(array $data) { |
|
| 90 | - $data['id'] = (string)$data['id']; |
|
| 91 | - $data['parent_id'] = (string)$data['parent_id']; |
|
| 92 | - $data['topmost_parent_id'] = (string)$data['topmost_parent_id']; |
|
| 93 | - $data['creation_timestamp'] = new \DateTime($data['creation_timestamp']); |
|
| 94 | - if (!is_null($data['latest_child_timestamp'])) { |
|
| 95 | - $data['latest_child_timestamp'] = new \DateTime($data['latest_child_timestamp']); |
|
| 96 | - } |
|
| 97 | - $data['children_count'] = (int)$data['children_count']; |
|
| 98 | - return $data; |
|
| 99 | - } |
|
| 100 | - |
|
| 101 | - /** |
|
| 102 | - * prepares a comment for an insert or update operation after making sure |
|
| 103 | - * all necessary fields have a value assigned. |
|
| 104 | - * |
|
| 105 | - * @param IComment $comment |
|
| 106 | - * @return IComment returns the same updated IComment instance as provided |
|
| 107 | - * by parameter for convenience |
|
| 108 | - * @throws \UnexpectedValueException |
|
| 109 | - */ |
|
| 110 | - protected function prepareCommentForDatabaseWrite(IComment $comment) { |
|
| 111 | - if (!$comment->getActorType() |
|
| 112 | - || !$comment->getActorId() |
|
| 113 | - || !$comment->getObjectType() |
|
| 114 | - || !$comment->getObjectId() |
|
| 115 | - || !$comment->getVerb() |
|
| 116 | - ) { |
|
| 117 | - throw new \UnexpectedValueException('Actor, Object and Verb information must be provided for saving'); |
|
| 118 | - } |
|
| 119 | - |
|
| 120 | - if ($comment->getId() === '') { |
|
| 121 | - $comment->setChildrenCount(0); |
|
| 122 | - $comment->setLatestChildDateTime(new \DateTime('0000-00-00 00:00:00', new \DateTimeZone('UTC'))); |
|
| 123 | - $comment->setLatestChildDateTime(null); |
|
| 124 | - } |
|
| 125 | - |
|
| 126 | - if (is_null($comment->getCreationDateTime())) { |
|
| 127 | - $comment->setCreationDateTime(new \DateTime()); |
|
| 128 | - } |
|
| 129 | - |
|
| 130 | - if ($comment->getParentId() !== '0') { |
|
| 131 | - $comment->setTopmostParentId($this->determineTopmostParentId($comment->getParentId())); |
|
| 132 | - } else { |
|
| 133 | - $comment->setTopmostParentId('0'); |
|
| 134 | - } |
|
| 135 | - |
|
| 136 | - $this->cache($comment); |
|
| 137 | - |
|
| 138 | - return $comment; |
|
| 139 | - } |
|
| 140 | - |
|
| 141 | - /** |
|
| 142 | - * returns the topmost parent id of a given comment identified by ID |
|
| 143 | - * |
|
| 144 | - * @param string $id |
|
| 145 | - * @return string |
|
| 146 | - * @throws NotFoundException |
|
| 147 | - */ |
|
| 148 | - protected function determineTopmostParentId($id) { |
|
| 149 | - $comment = $this->get($id); |
|
| 150 | - if ($comment->getParentId() === '0') { |
|
| 151 | - return $comment->getId(); |
|
| 152 | - } else { |
|
| 153 | - return $this->determineTopmostParentId($comment->getId()); |
|
| 154 | - } |
|
| 155 | - } |
|
| 156 | - |
|
| 157 | - /** |
|
| 158 | - * updates child information of a comment |
|
| 159 | - * |
|
| 160 | - * @param string $id |
|
| 161 | - * @param \DateTime $cDateTime the date time of the most recent child |
|
| 162 | - * @throws NotFoundException |
|
| 163 | - */ |
|
| 164 | - protected function updateChildrenInformation($id, \DateTime $cDateTime) { |
|
| 165 | - $qb = $this->dbConn->getQueryBuilder(); |
|
| 166 | - $query = $qb->select($qb->createFunction('COUNT(`id`)')) |
|
| 167 | - ->from('comments') |
|
| 168 | - ->where($qb->expr()->eq('parent_id', $qb->createParameter('id'))) |
|
| 169 | - ->setParameter('id', $id); |
|
| 170 | - |
|
| 171 | - $resultStatement = $query->execute(); |
|
| 172 | - $data = $resultStatement->fetch(\PDO::FETCH_NUM); |
|
| 173 | - $resultStatement->closeCursor(); |
|
| 174 | - $children = (int)$data[0]; |
|
| 175 | - |
|
| 176 | - $comment = $this->get($id); |
|
| 177 | - $comment->setChildrenCount($children); |
|
| 178 | - $comment->setLatestChildDateTime($cDateTime); |
|
| 179 | - $this->save($comment); |
|
| 180 | - } |
|
| 181 | - |
|
| 182 | - /** |
|
| 183 | - * Tests whether actor or object type and id parameters are acceptable. |
|
| 184 | - * Throws exception if not. |
|
| 185 | - * |
|
| 186 | - * @param string $role |
|
| 187 | - * @param string $type |
|
| 188 | - * @param string $id |
|
| 189 | - * @throws \InvalidArgumentException |
|
| 190 | - */ |
|
| 191 | - protected function checkRoleParameters($role, $type, $id) { |
|
| 192 | - if ( |
|
| 193 | - !is_string($type) || empty($type) |
|
| 194 | - || !is_string($id) || empty($id) |
|
| 195 | - ) { |
|
| 196 | - throw new \InvalidArgumentException($role . ' parameters must be string and not empty'); |
|
| 197 | - } |
|
| 198 | - } |
|
| 199 | - |
|
| 200 | - /** |
|
| 201 | - * run-time caches a comment |
|
| 202 | - * |
|
| 203 | - * @param IComment $comment |
|
| 204 | - */ |
|
| 205 | - protected function cache(IComment $comment) { |
|
| 206 | - $id = $comment->getId(); |
|
| 207 | - if (empty($id)) { |
|
| 208 | - return; |
|
| 209 | - } |
|
| 210 | - $this->commentsCache[(string)$id] = $comment; |
|
| 211 | - } |
|
| 212 | - |
|
| 213 | - /** |
|
| 214 | - * removes an entry from the comments run time cache |
|
| 215 | - * |
|
| 216 | - * @param mixed $id the comment's id |
|
| 217 | - */ |
|
| 218 | - protected function uncache($id) { |
|
| 219 | - $id = (string)$id; |
|
| 220 | - if (isset($this->commentsCache[$id])) { |
|
| 221 | - unset($this->commentsCache[$id]); |
|
| 222 | - } |
|
| 223 | - } |
|
| 224 | - |
|
| 225 | - /** |
|
| 226 | - * returns a comment instance |
|
| 227 | - * |
|
| 228 | - * @param string $id the ID of the comment |
|
| 229 | - * @return IComment |
|
| 230 | - * @throws NotFoundException |
|
| 231 | - * @throws \InvalidArgumentException |
|
| 232 | - * @since 9.0.0 |
|
| 233 | - */ |
|
| 234 | - public function get($id) { |
|
| 235 | - if ((int)$id === 0) { |
|
| 236 | - throw new \InvalidArgumentException('IDs must be translatable to a number in this implementation.'); |
|
| 237 | - } |
|
| 238 | - |
|
| 239 | - if (isset($this->commentsCache[$id])) { |
|
| 240 | - return $this->commentsCache[$id]; |
|
| 241 | - } |
|
| 242 | - |
|
| 243 | - $qb = $this->dbConn->getQueryBuilder(); |
|
| 244 | - $resultStatement = $qb->select('*') |
|
| 245 | - ->from('comments') |
|
| 246 | - ->where($qb->expr()->eq('id', $qb->createParameter('id'))) |
|
| 247 | - ->setParameter('id', $id, IQueryBuilder::PARAM_INT) |
|
| 248 | - ->execute(); |
|
| 249 | - |
|
| 250 | - $data = $resultStatement->fetch(); |
|
| 251 | - $resultStatement->closeCursor(); |
|
| 252 | - if (!$data) { |
|
| 253 | - throw new NotFoundException(); |
|
| 254 | - } |
|
| 255 | - |
|
| 256 | - $comment = new Comment($this->normalizeDatabaseData($data)); |
|
| 257 | - $this->cache($comment); |
|
| 258 | - return $comment; |
|
| 259 | - } |
|
| 260 | - |
|
| 261 | - /** |
|
| 262 | - * returns the comment specified by the id and all it's child comments. |
|
| 263 | - * At this point of time, we do only support one level depth. |
|
| 264 | - * |
|
| 265 | - * @param string $id |
|
| 266 | - * @param int $limit max number of entries to return, 0 returns all |
|
| 267 | - * @param int $offset the start entry |
|
| 268 | - * @return array |
|
| 269 | - * @since 9.0.0 |
|
| 270 | - * |
|
| 271 | - * The return array looks like this |
|
| 272 | - * [ |
|
| 273 | - * 'comment' => IComment, // root comment |
|
| 274 | - * 'replies' => |
|
| 275 | - * [ |
|
| 276 | - * 0 => |
|
| 277 | - * [ |
|
| 278 | - * 'comment' => IComment, |
|
| 279 | - * 'replies' => [] |
|
| 280 | - * ] |
|
| 281 | - * 1 => |
|
| 282 | - * [ |
|
| 283 | - * 'comment' => IComment, |
|
| 284 | - * 'replies'=> [] |
|
| 285 | - * ], |
|
| 286 | - * … |
|
| 287 | - * ] |
|
| 288 | - * ] |
|
| 289 | - */ |
|
| 290 | - public function getTree($id, $limit = 0, $offset = 0) { |
|
| 291 | - $tree = []; |
|
| 292 | - $tree['comment'] = $this->get($id); |
|
| 293 | - $tree['replies'] = []; |
|
| 294 | - |
|
| 295 | - $qb = $this->dbConn->getQueryBuilder(); |
|
| 296 | - $query = $qb->select('*') |
|
| 297 | - ->from('comments') |
|
| 298 | - ->where($qb->expr()->eq('topmost_parent_id', $qb->createParameter('id'))) |
|
| 299 | - ->orderBy('creation_timestamp', 'DESC') |
|
| 300 | - ->setParameter('id', $id); |
|
| 301 | - |
|
| 302 | - if ($limit > 0) { |
|
| 303 | - $query->setMaxResults($limit); |
|
| 304 | - } |
|
| 305 | - if ($offset > 0) { |
|
| 306 | - $query->setFirstResult($offset); |
|
| 307 | - } |
|
| 308 | - |
|
| 309 | - $resultStatement = $query->execute(); |
|
| 310 | - while ($data = $resultStatement->fetch()) { |
|
| 311 | - $comment = new Comment($this->normalizeDatabaseData($data)); |
|
| 312 | - $this->cache($comment); |
|
| 313 | - $tree['replies'][] = [ |
|
| 314 | - 'comment' => $comment, |
|
| 315 | - 'replies' => [] |
|
| 316 | - ]; |
|
| 317 | - } |
|
| 318 | - $resultStatement->closeCursor(); |
|
| 319 | - |
|
| 320 | - return $tree; |
|
| 321 | - } |
|
| 322 | - |
|
| 323 | - /** |
|
| 324 | - * returns comments for a specific object (e.g. a file). |
|
| 325 | - * |
|
| 326 | - * The sort order is always newest to oldest. |
|
| 327 | - * |
|
| 328 | - * @param string $objectType the object type, e.g. 'files' |
|
| 329 | - * @param string $objectId the id of the object |
|
| 330 | - * @param int $limit optional, number of maximum comments to be returned. if |
|
| 331 | - * not specified, all comments are returned. |
|
| 332 | - * @param int $offset optional, starting point |
|
| 333 | - * @param \DateTime $notOlderThan optional, timestamp of the oldest comments |
|
| 334 | - * that may be returned |
|
| 335 | - * @return IComment[] |
|
| 336 | - * @since 9.0.0 |
|
| 337 | - */ |
|
| 338 | - public function getForObject( |
|
| 339 | - $objectType, |
|
| 340 | - $objectId, |
|
| 341 | - $limit = 0, |
|
| 342 | - $offset = 0, |
|
| 343 | - \DateTime $notOlderThan = null |
|
| 344 | - ) { |
|
| 345 | - $comments = []; |
|
| 346 | - |
|
| 347 | - $qb = $this->dbConn->getQueryBuilder(); |
|
| 348 | - $query = $qb->select('*') |
|
| 349 | - ->from('comments') |
|
| 350 | - ->where($qb->expr()->eq('object_type', $qb->createParameter('type'))) |
|
| 351 | - ->andWhere($qb->expr()->eq('object_id', $qb->createParameter('id'))) |
|
| 352 | - ->orderBy('creation_timestamp', 'DESC') |
|
| 353 | - ->setParameter('type', $objectType) |
|
| 354 | - ->setParameter('id', $objectId); |
|
| 355 | - |
|
| 356 | - if ($limit > 0) { |
|
| 357 | - $query->setMaxResults($limit); |
|
| 358 | - } |
|
| 359 | - if ($offset > 0) { |
|
| 360 | - $query->setFirstResult($offset); |
|
| 361 | - } |
|
| 362 | - if (!is_null($notOlderThan)) { |
|
| 363 | - $query |
|
| 364 | - ->andWhere($qb->expr()->gt('creation_timestamp', $qb->createParameter('notOlderThan'))) |
|
| 365 | - ->setParameter('notOlderThan', $notOlderThan, 'datetime'); |
|
| 366 | - } |
|
| 367 | - |
|
| 368 | - $resultStatement = $query->execute(); |
|
| 369 | - while ($data = $resultStatement->fetch()) { |
|
| 370 | - $comment = new Comment($this->normalizeDatabaseData($data)); |
|
| 371 | - $this->cache($comment); |
|
| 372 | - $comments[] = $comment; |
|
| 373 | - } |
|
| 374 | - $resultStatement->closeCursor(); |
|
| 375 | - |
|
| 376 | - return $comments; |
|
| 377 | - } |
|
| 378 | - |
|
| 379 | - /** |
|
| 380 | - * @param $objectType string the object type, e.g. 'files' |
|
| 381 | - * @param $objectId string the id of the object |
|
| 382 | - * @param \DateTime $notOlderThan optional, timestamp of the oldest comments |
|
| 383 | - * that may be returned |
|
| 384 | - * @return Int |
|
| 385 | - * @since 9.0.0 |
|
| 386 | - */ |
|
| 387 | - public function getNumberOfCommentsForObject($objectType, $objectId, \DateTime $notOlderThan = null) { |
|
| 388 | - $qb = $this->dbConn->getQueryBuilder(); |
|
| 389 | - $query = $qb->select($qb->createFunction('COUNT(`id`)')) |
|
| 390 | - ->from('comments') |
|
| 391 | - ->where($qb->expr()->eq('object_type', $qb->createParameter('type'))) |
|
| 392 | - ->andWhere($qb->expr()->eq('object_id', $qb->createParameter('id'))) |
|
| 393 | - ->setParameter('type', $objectType) |
|
| 394 | - ->setParameter('id', $objectId); |
|
| 395 | - |
|
| 396 | - if (!is_null($notOlderThan)) { |
|
| 397 | - $query |
|
| 398 | - ->andWhere($qb->expr()->gt('creation_timestamp', $qb->createParameter('notOlderThan'))) |
|
| 399 | - ->setParameter('notOlderThan', $notOlderThan, 'datetime'); |
|
| 400 | - } |
|
| 401 | - |
|
| 402 | - $resultStatement = $query->execute(); |
|
| 403 | - $data = $resultStatement->fetch(\PDO::FETCH_NUM); |
|
| 404 | - $resultStatement->closeCursor(); |
|
| 405 | - return (int)$data[0]; |
|
| 406 | - } |
|
| 407 | - |
|
| 408 | - /** |
|
| 409 | - * Get the number of unread comments for all files in a folder |
|
| 410 | - * |
|
| 411 | - * @param int $folderId |
|
| 412 | - * @param IUser $user |
|
| 413 | - * @return array [$fileId => $unreadCount] |
|
| 414 | - */ |
|
| 415 | - public function getNumberOfUnreadCommentsForFolder($folderId, IUser $user) { |
|
| 416 | - $qb = $this->dbConn->getQueryBuilder(); |
|
| 417 | - $query = $qb->select('f.fileid') |
|
| 418 | - ->selectAlias( |
|
| 419 | - $qb->createFunction('COUNT(' . $qb->getColumnName('c.id') . ')'), |
|
| 420 | - 'num_ids' |
|
| 421 | - ) |
|
| 422 | - ->from('comments', 'c') |
|
| 423 | - ->innerJoin('c', 'filecache', 'f', $qb->expr()->andX( |
|
| 424 | - $qb->expr()->eq('c.object_type', $qb->createNamedParameter('files')), |
|
| 425 | - $qb->expr()->eq('f.fileid', $qb->expr()->castColumn('c.object_id', IQueryBuilder::PARAM_INT)) |
|
| 426 | - )) |
|
| 427 | - ->leftJoin('c', 'comments_read_markers', 'm', $qb->expr()->andX( |
|
| 428 | - $qb->expr()->eq('m.object_type', $qb->createNamedParameter('files')), |
|
| 429 | - $qb->expr()->eq('m.object_id', 'c.object_id'), |
|
| 430 | - $qb->expr()->eq('m.user_id', $qb->createNamedParameter($user->getUID())) |
|
| 431 | - )) |
|
| 432 | - ->andWhere($qb->expr()->eq('f.parent', $qb->createNamedParameter($folderId))) |
|
| 433 | - ->andWhere($qb->expr()->orX( |
|
| 434 | - $qb->expr()->gt('c.creation_timestamp', 'marker_datetime'), |
|
| 435 | - $qb->expr()->isNull('marker_datetime') |
|
| 436 | - )) |
|
| 437 | - ->groupBy('f.fileid'); |
|
| 438 | - |
|
| 439 | - $resultStatement = $query->execute(); |
|
| 440 | - |
|
| 441 | - $results = []; |
|
| 442 | - while ($row = $resultStatement->fetch()) { |
|
| 443 | - $results[$row['fileid']] = (int) $row['num_ids']; |
|
| 444 | - } |
|
| 445 | - $resultStatement->closeCursor(); |
|
| 446 | - return $results; |
|
| 447 | - } |
|
| 448 | - |
|
| 449 | - /** |
|
| 450 | - * creates a new comment and returns it. At this point of time, it is not |
|
| 451 | - * saved in the used data storage. Use save() after setting other fields |
|
| 452 | - * of the comment (e.g. message or verb). |
|
| 453 | - * |
|
| 454 | - * @param string $actorType the actor type (e.g. 'users') |
|
| 455 | - * @param string $actorId a user id |
|
| 456 | - * @param string $objectType the object type the comment is attached to |
|
| 457 | - * @param string $objectId the object id the comment is attached to |
|
| 458 | - * @return IComment |
|
| 459 | - * @since 9.0.0 |
|
| 460 | - */ |
|
| 461 | - public function create($actorType, $actorId, $objectType, $objectId) { |
|
| 462 | - $comment = new Comment(); |
|
| 463 | - $comment |
|
| 464 | - ->setActor($actorType, $actorId) |
|
| 465 | - ->setObject($objectType, $objectId); |
|
| 466 | - return $comment; |
|
| 467 | - } |
|
| 468 | - |
|
| 469 | - /** |
|
| 470 | - * permanently deletes the comment specified by the ID |
|
| 471 | - * |
|
| 472 | - * When the comment has child comments, their parent ID will be changed to |
|
| 473 | - * the parent ID of the item that is to be deleted. |
|
| 474 | - * |
|
| 475 | - * @param string $id |
|
| 476 | - * @return bool |
|
| 477 | - * @throws \InvalidArgumentException |
|
| 478 | - * @since 9.0.0 |
|
| 479 | - */ |
|
| 480 | - public function delete($id) { |
|
| 481 | - if (!is_string($id)) { |
|
| 482 | - throw new \InvalidArgumentException('Parameter must be string'); |
|
| 483 | - } |
|
| 484 | - |
|
| 485 | - try { |
|
| 486 | - $comment = $this->get($id); |
|
| 487 | - } catch (\Exception $e) { |
|
| 488 | - // Ignore exceptions, we just don't fire a hook then |
|
| 489 | - $comment = null; |
|
| 490 | - } |
|
| 491 | - |
|
| 492 | - $qb = $this->dbConn->getQueryBuilder(); |
|
| 493 | - $query = $qb->delete('comments') |
|
| 494 | - ->where($qb->expr()->eq('id', $qb->createParameter('id'))) |
|
| 495 | - ->setParameter('id', $id); |
|
| 496 | - |
|
| 497 | - try { |
|
| 498 | - $affectedRows = $query->execute(); |
|
| 499 | - $this->uncache($id); |
|
| 500 | - } catch (DriverException $e) { |
|
| 501 | - $this->logger->logException($e, ['app' => 'core_comments']); |
|
| 502 | - return false; |
|
| 503 | - } |
|
| 504 | - |
|
| 505 | - if ($affectedRows > 0 && $comment instanceof IComment) { |
|
| 506 | - $this->sendEvent(CommentsEvent::EVENT_DELETE, $comment); |
|
| 507 | - } |
|
| 508 | - |
|
| 509 | - return ($affectedRows > 0); |
|
| 510 | - } |
|
| 511 | - |
|
| 512 | - /** |
|
| 513 | - * saves the comment permanently |
|
| 514 | - * |
|
| 515 | - * if the supplied comment has an empty ID, a new entry comment will be |
|
| 516 | - * saved and the instance updated with the new ID. |
|
| 517 | - * |
|
| 518 | - * Otherwise, an existing comment will be updated. |
|
| 519 | - * |
|
| 520 | - * Throws NotFoundException when a comment that is to be updated does not |
|
| 521 | - * exist anymore at this point of time. |
|
| 522 | - * |
|
| 523 | - * @param IComment $comment |
|
| 524 | - * @return bool |
|
| 525 | - * @throws NotFoundException |
|
| 526 | - * @since 9.0.0 |
|
| 527 | - */ |
|
| 528 | - public function save(IComment $comment) { |
|
| 529 | - if ($this->prepareCommentForDatabaseWrite($comment)->getId() === '') { |
|
| 530 | - $result = $this->insert($comment); |
|
| 531 | - } else { |
|
| 532 | - $result = $this->update($comment); |
|
| 533 | - } |
|
| 534 | - |
|
| 535 | - if ($result && !!$comment->getParentId()) { |
|
| 536 | - $this->updateChildrenInformation( |
|
| 537 | - $comment->getParentId(), |
|
| 538 | - $comment->getCreationDateTime() |
|
| 539 | - ); |
|
| 540 | - $this->cache($comment); |
|
| 541 | - } |
|
| 542 | - |
|
| 543 | - return $result; |
|
| 544 | - } |
|
| 545 | - |
|
| 546 | - /** |
|
| 547 | - * inserts the provided comment in the database |
|
| 548 | - * |
|
| 549 | - * @param IComment $comment |
|
| 550 | - * @return bool |
|
| 551 | - */ |
|
| 552 | - protected function insert(IComment &$comment) { |
|
| 553 | - $qb = $this->dbConn->getQueryBuilder(); |
|
| 554 | - $affectedRows = $qb |
|
| 555 | - ->insert('comments') |
|
| 556 | - ->values([ |
|
| 557 | - 'parent_id' => $qb->createNamedParameter($comment->getParentId()), |
|
| 558 | - 'topmost_parent_id' => $qb->createNamedParameter($comment->getTopmostParentId()), |
|
| 559 | - 'children_count' => $qb->createNamedParameter($comment->getChildrenCount()), |
|
| 560 | - 'actor_type' => $qb->createNamedParameter($comment->getActorType()), |
|
| 561 | - 'actor_id' => $qb->createNamedParameter($comment->getActorId()), |
|
| 562 | - 'message' => $qb->createNamedParameter($comment->getMessage()), |
|
| 563 | - 'verb' => $qb->createNamedParameter($comment->getVerb()), |
|
| 564 | - 'creation_timestamp' => $qb->createNamedParameter($comment->getCreationDateTime(), 'datetime'), |
|
| 565 | - 'latest_child_timestamp' => $qb->createNamedParameter($comment->getLatestChildDateTime(), 'datetime'), |
|
| 566 | - 'object_type' => $qb->createNamedParameter($comment->getObjectType()), |
|
| 567 | - 'object_id' => $qb->createNamedParameter($comment->getObjectId()), |
|
| 568 | - ]) |
|
| 569 | - ->execute(); |
|
| 570 | - |
|
| 571 | - if ($affectedRows > 0) { |
|
| 572 | - $comment->setId((string)$qb->getLastInsertId()); |
|
| 573 | - $this->sendEvent(CommentsEvent::EVENT_ADD, $comment); |
|
| 574 | - } |
|
| 575 | - |
|
| 576 | - return $affectedRows > 0; |
|
| 577 | - } |
|
| 578 | - |
|
| 579 | - /** |
|
| 580 | - * updates a Comment data row |
|
| 581 | - * |
|
| 582 | - * @param IComment $comment |
|
| 583 | - * @return bool |
|
| 584 | - * @throws NotFoundException |
|
| 585 | - */ |
|
| 586 | - protected function update(IComment $comment) { |
|
| 587 | - // for properly working preUpdate Events we need the old comments as is |
|
| 588 | - // in the DB and overcome caching. Also avoid that outdated information stays. |
|
| 589 | - $this->uncache($comment->getId()); |
|
| 590 | - $this->sendEvent(CommentsEvent::EVENT_PRE_UPDATE, $this->get($comment->getId())); |
|
| 591 | - $this->uncache($comment->getId()); |
|
| 592 | - |
|
| 593 | - $qb = $this->dbConn->getQueryBuilder(); |
|
| 594 | - $affectedRows = $qb |
|
| 595 | - ->update('comments') |
|
| 596 | - ->set('parent_id', $qb->createNamedParameter($comment->getParentId())) |
|
| 597 | - ->set('topmost_parent_id', $qb->createNamedParameter($comment->getTopmostParentId())) |
|
| 598 | - ->set('children_count', $qb->createNamedParameter($comment->getChildrenCount())) |
|
| 599 | - ->set('actor_type', $qb->createNamedParameter($comment->getActorType())) |
|
| 600 | - ->set('actor_id', $qb->createNamedParameter($comment->getActorId())) |
|
| 601 | - ->set('message', $qb->createNamedParameter($comment->getMessage())) |
|
| 602 | - ->set('verb', $qb->createNamedParameter($comment->getVerb())) |
|
| 603 | - ->set('creation_timestamp', $qb->createNamedParameter($comment->getCreationDateTime(), 'datetime')) |
|
| 604 | - ->set('latest_child_timestamp', $qb->createNamedParameter($comment->getLatestChildDateTime(), 'datetime')) |
|
| 605 | - ->set('object_type', $qb->createNamedParameter($comment->getObjectType())) |
|
| 606 | - ->set('object_id', $qb->createNamedParameter($comment->getObjectId())) |
|
| 607 | - ->where($qb->expr()->eq('id', $qb->createParameter('id'))) |
|
| 608 | - ->setParameter('id', $comment->getId()) |
|
| 609 | - ->execute(); |
|
| 610 | - |
|
| 611 | - if ($affectedRows === 0) { |
|
| 612 | - throw new NotFoundException('Comment to update does ceased to exist'); |
|
| 613 | - } |
|
| 614 | - |
|
| 615 | - $this->sendEvent(CommentsEvent::EVENT_UPDATE, $comment); |
|
| 616 | - |
|
| 617 | - return $affectedRows > 0; |
|
| 618 | - } |
|
| 619 | - |
|
| 620 | - /** |
|
| 621 | - * removes references to specific actor (e.g. on user delete) of a comment. |
|
| 622 | - * The comment itself must not get lost/deleted. |
|
| 623 | - * |
|
| 624 | - * @param string $actorType the actor type (e.g. 'users') |
|
| 625 | - * @param string $actorId a user id |
|
| 626 | - * @return boolean |
|
| 627 | - * @since 9.0.0 |
|
| 628 | - */ |
|
| 629 | - public function deleteReferencesOfActor($actorType, $actorId) { |
|
| 630 | - $this->checkRoleParameters('Actor', $actorType, $actorId); |
|
| 631 | - |
|
| 632 | - $qb = $this->dbConn->getQueryBuilder(); |
|
| 633 | - $affectedRows = $qb |
|
| 634 | - ->update('comments') |
|
| 635 | - ->set('actor_type', $qb->createNamedParameter(ICommentsManager::DELETED_USER)) |
|
| 636 | - ->set('actor_id', $qb->createNamedParameter(ICommentsManager::DELETED_USER)) |
|
| 637 | - ->where($qb->expr()->eq('actor_type', $qb->createParameter('type'))) |
|
| 638 | - ->andWhere($qb->expr()->eq('actor_id', $qb->createParameter('id'))) |
|
| 639 | - ->setParameter('type', $actorType) |
|
| 640 | - ->setParameter('id', $actorId) |
|
| 641 | - ->execute(); |
|
| 642 | - |
|
| 643 | - $this->commentsCache = []; |
|
| 644 | - |
|
| 645 | - return is_int($affectedRows); |
|
| 646 | - } |
|
| 647 | - |
|
| 648 | - /** |
|
| 649 | - * deletes all comments made of a specific object (e.g. on file delete) |
|
| 650 | - * |
|
| 651 | - * @param string $objectType the object type (e.g. 'files') |
|
| 652 | - * @param string $objectId e.g. the file id |
|
| 653 | - * @return boolean |
|
| 654 | - * @since 9.0.0 |
|
| 655 | - */ |
|
| 656 | - public function deleteCommentsAtObject($objectType, $objectId) { |
|
| 657 | - $this->checkRoleParameters('Object', $objectType, $objectId); |
|
| 658 | - |
|
| 659 | - $qb = $this->dbConn->getQueryBuilder(); |
|
| 660 | - $affectedRows = $qb |
|
| 661 | - ->delete('comments') |
|
| 662 | - ->where($qb->expr()->eq('object_type', $qb->createParameter('type'))) |
|
| 663 | - ->andWhere($qb->expr()->eq('object_id', $qb->createParameter('id'))) |
|
| 664 | - ->setParameter('type', $objectType) |
|
| 665 | - ->setParameter('id', $objectId) |
|
| 666 | - ->execute(); |
|
| 667 | - |
|
| 668 | - $this->commentsCache = []; |
|
| 669 | - |
|
| 670 | - return is_int($affectedRows); |
|
| 671 | - } |
|
| 672 | - |
|
| 673 | - /** |
|
| 674 | - * deletes the read markers for the specified user |
|
| 675 | - * |
|
| 676 | - * @param \OCP\IUser $user |
|
| 677 | - * @return bool |
|
| 678 | - * @since 9.0.0 |
|
| 679 | - */ |
|
| 680 | - public function deleteReadMarksFromUser(IUser $user) { |
|
| 681 | - $qb = $this->dbConn->getQueryBuilder(); |
|
| 682 | - $query = $qb->delete('comments_read_markers') |
|
| 683 | - ->where($qb->expr()->eq('user_id', $qb->createParameter('user_id'))) |
|
| 684 | - ->setParameter('user_id', $user->getUID()); |
|
| 685 | - |
|
| 686 | - try { |
|
| 687 | - $affectedRows = $query->execute(); |
|
| 688 | - } catch (DriverException $e) { |
|
| 689 | - $this->logger->logException($e, ['app' => 'core_comments']); |
|
| 690 | - return false; |
|
| 691 | - } |
|
| 692 | - return ($affectedRows > 0); |
|
| 693 | - } |
|
| 694 | - |
|
| 695 | - /** |
|
| 696 | - * sets the read marker for a given file to the specified date for the |
|
| 697 | - * provided user |
|
| 698 | - * |
|
| 699 | - * @param string $objectType |
|
| 700 | - * @param string $objectId |
|
| 701 | - * @param \DateTime $dateTime |
|
| 702 | - * @param IUser $user |
|
| 703 | - * @since 9.0.0 |
|
| 704 | - * @suppress SqlInjectionChecker |
|
| 705 | - */ |
|
| 706 | - public function setReadMark($objectType, $objectId, \DateTime $dateTime, IUser $user) { |
|
| 707 | - $this->checkRoleParameters('Object', $objectType, $objectId); |
|
| 708 | - |
|
| 709 | - $qb = $this->dbConn->getQueryBuilder(); |
|
| 710 | - $values = [ |
|
| 711 | - 'user_id' => $qb->createNamedParameter($user->getUID()), |
|
| 712 | - 'marker_datetime' => $qb->createNamedParameter($dateTime, 'datetime'), |
|
| 713 | - 'object_type' => $qb->createNamedParameter($objectType), |
|
| 714 | - 'object_id' => $qb->createNamedParameter($objectId), |
|
| 715 | - ]; |
|
| 716 | - |
|
| 717 | - // Strategy: try to update, if this does not return affected rows, do an insert. |
|
| 718 | - $affectedRows = $qb |
|
| 719 | - ->update('comments_read_markers') |
|
| 720 | - ->set('user_id', $values['user_id']) |
|
| 721 | - ->set('marker_datetime', $values['marker_datetime']) |
|
| 722 | - ->set('object_type', $values['object_type']) |
|
| 723 | - ->set('object_id', $values['object_id']) |
|
| 724 | - ->where($qb->expr()->eq('user_id', $qb->createParameter('user_id'))) |
|
| 725 | - ->andWhere($qb->expr()->eq('object_type', $qb->createParameter('object_type'))) |
|
| 726 | - ->andWhere($qb->expr()->eq('object_id', $qb->createParameter('object_id'))) |
|
| 727 | - ->setParameter('user_id', $user->getUID(), IQueryBuilder::PARAM_STR) |
|
| 728 | - ->setParameter('object_type', $objectType, IQueryBuilder::PARAM_STR) |
|
| 729 | - ->setParameter('object_id', $objectId, IQueryBuilder::PARAM_STR) |
|
| 730 | - ->execute(); |
|
| 731 | - |
|
| 732 | - if ($affectedRows > 0) { |
|
| 733 | - return; |
|
| 734 | - } |
|
| 735 | - |
|
| 736 | - $qb->insert('comments_read_markers') |
|
| 737 | - ->values($values) |
|
| 738 | - ->execute(); |
|
| 739 | - } |
|
| 740 | - |
|
| 741 | - /** |
|
| 742 | - * returns the read marker for a given file to the specified date for the |
|
| 743 | - * provided user. It returns null, when the marker is not present, i.e. |
|
| 744 | - * no comments were marked as read. |
|
| 745 | - * |
|
| 746 | - * @param string $objectType |
|
| 747 | - * @param string $objectId |
|
| 748 | - * @param IUser $user |
|
| 749 | - * @return \DateTime|null |
|
| 750 | - * @since 9.0.0 |
|
| 751 | - */ |
|
| 752 | - public function getReadMark($objectType, $objectId, IUser $user) { |
|
| 753 | - $qb = $this->dbConn->getQueryBuilder(); |
|
| 754 | - $resultStatement = $qb->select('marker_datetime') |
|
| 755 | - ->from('comments_read_markers') |
|
| 756 | - ->where($qb->expr()->eq('user_id', $qb->createParameter('user_id'))) |
|
| 757 | - ->andWhere($qb->expr()->eq('object_type', $qb->createParameter('object_type'))) |
|
| 758 | - ->andWhere($qb->expr()->eq('object_id', $qb->createParameter('object_id'))) |
|
| 759 | - ->setParameter('user_id', $user->getUID(), IQueryBuilder::PARAM_STR) |
|
| 760 | - ->setParameter('object_type', $objectType, IQueryBuilder::PARAM_STR) |
|
| 761 | - ->setParameter('object_id', $objectId, IQueryBuilder::PARAM_STR) |
|
| 762 | - ->execute(); |
|
| 763 | - |
|
| 764 | - $data = $resultStatement->fetch(); |
|
| 765 | - $resultStatement->closeCursor(); |
|
| 766 | - if (!$data || is_null($data['marker_datetime'])) { |
|
| 767 | - return null; |
|
| 768 | - } |
|
| 769 | - |
|
| 770 | - return new \DateTime($data['marker_datetime']); |
|
| 771 | - } |
|
| 772 | - |
|
| 773 | - /** |
|
| 774 | - * deletes the read markers on the specified object |
|
| 775 | - * |
|
| 776 | - * @param string $objectType |
|
| 777 | - * @param string $objectId |
|
| 778 | - * @return bool |
|
| 779 | - * @since 9.0.0 |
|
| 780 | - */ |
|
| 781 | - public function deleteReadMarksOnObject($objectType, $objectId) { |
|
| 782 | - $this->checkRoleParameters('Object', $objectType, $objectId); |
|
| 783 | - |
|
| 784 | - $qb = $this->dbConn->getQueryBuilder(); |
|
| 785 | - $query = $qb->delete('comments_read_markers') |
|
| 786 | - ->where($qb->expr()->eq('object_type', $qb->createParameter('object_type'))) |
|
| 787 | - ->andWhere($qb->expr()->eq('object_id', $qb->createParameter('object_id'))) |
|
| 788 | - ->setParameter('object_type', $objectType) |
|
| 789 | - ->setParameter('object_id', $objectId); |
|
| 790 | - |
|
| 791 | - try { |
|
| 792 | - $affectedRows = $query->execute(); |
|
| 793 | - } catch (DriverException $e) { |
|
| 794 | - $this->logger->logException($e, ['app' => 'core_comments']); |
|
| 795 | - return false; |
|
| 796 | - } |
|
| 797 | - return ($affectedRows > 0); |
|
| 798 | - } |
|
| 799 | - |
|
| 800 | - /** |
|
| 801 | - * registers an Entity to the manager, so event notifications can be send |
|
| 802 | - * to consumers of the comments infrastructure |
|
| 803 | - * |
|
| 804 | - * @param \Closure $closure |
|
| 805 | - */ |
|
| 806 | - public function registerEventHandler(\Closure $closure) { |
|
| 807 | - $this->eventHandlerClosures[] = $closure; |
|
| 808 | - $this->eventHandlers = []; |
|
| 809 | - } |
|
| 810 | - |
|
| 811 | - /** |
|
| 812 | - * registers a method that resolves an ID to a display name for a given type |
|
| 813 | - * |
|
| 814 | - * @param string $type |
|
| 815 | - * @param \Closure $closure |
|
| 816 | - * @throws \OutOfBoundsException |
|
| 817 | - * @since 11.0.0 |
|
| 818 | - * |
|
| 819 | - * Only one resolver shall be registered per type. Otherwise a |
|
| 820 | - * \OutOfBoundsException has to thrown. |
|
| 821 | - */ |
|
| 822 | - public function registerDisplayNameResolver($type, \Closure $closure) { |
|
| 823 | - if (!is_string($type)) { |
|
| 824 | - throw new \InvalidArgumentException('String expected.'); |
|
| 825 | - } |
|
| 826 | - if (isset($this->displayNameResolvers[$type])) { |
|
| 827 | - throw new \OutOfBoundsException('Displayname resolver for this type already registered'); |
|
| 828 | - } |
|
| 829 | - $this->displayNameResolvers[$type] = $closure; |
|
| 830 | - } |
|
| 831 | - |
|
| 832 | - /** |
|
| 833 | - * resolves a given ID of a given Type to a display name. |
|
| 834 | - * |
|
| 835 | - * @param string $type |
|
| 836 | - * @param string $id |
|
| 837 | - * @return string |
|
| 838 | - * @throws \OutOfBoundsException |
|
| 839 | - * @since 11.0.0 |
|
| 840 | - * |
|
| 841 | - * If a provided type was not registered, an \OutOfBoundsException shall |
|
| 842 | - * be thrown. It is upon the resolver discretion what to return of the |
|
| 843 | - * provided ID is unknown. It must be ensured that a string is returned. |
|
| 844 | - */ |
|
| 845 | - public function resolveDisplayName($type, $id) { |
|
| 846 | - if (!is_string($type)) { |
|
| 847 | - throw new \InvalidArgumentException('String expected.'); |
|
| 848 | - } |
|
| 849 | - if (!isset($this->displayNameResolvers[$type])) { |
|
| 850 | - throw new \OutOfBoundsException('No Displayname resolver for this type registered'); |
|
| 851 | - } |
|
| 852 | - return (string)$this->displayNameResolvers[$type]($id); |
|
| 853 | - } |
|
| 854 | - |
|
| 855 | - /** |
|
| 856 | - * returns valid, registered entities |
|
| 857 | - * |
|
| 858 | - * @return \OCP\Comments\ICommentsEventHandler[] |
|
| 859 | - */ |
|
| 860 | - private function getEventHandlers() { |
|
| 861 | - if (!empty($this->eventHandlers)) { |
|
| 862 | - return $this->eventHandlers; |
|
| 863 | - } |
|
| 864 | - |
|
| 865 | - $this->eventHandlers = []; |
|
| 866 | - foreach ($this->eventHandlerClosures as $name => $closure) { |
|
| 867 | - $entity = $closure(); |
|
| 868 | - if (!($entity instanceof ICommentsEventHandler)) { |
|
| 869 | - throw new \InvalidArgumentException('The given entity does not implement the ICommentsEntity interface'); |
|
| 870 | - } |
|
| 871 | - $this->eventHandlers[$name] = $entity; |
|
| 872 | - } |
|
| 873 | - |
|
| 874 | - return $this->eventHandlers; |
|
| 875 | - } |
|
| 876 | - |
|
| 877 | - /** |
|
| 878 | - * sends notifications to the registered entities |
|
| 879 | - * |
|
| 880 | - * @param $eventType |
|
| 881 | - * @param IComment $comment |
|
| 882 | - */ |
|
| 883 | - private function sendEvent($eventType, IComment $comment) { |
|
| 884 | - $entities = $this->getEventHandlers(); |
|
| 885 | - $event = new CommentsEvent($eventType, $comment); |
|
| 886 | - foreach ($entities as $entity) { |
|
| 887 | - $entity->handle($event); |
|
| 888 | - } |
|
| 889 | - } |
|
| 44 | + /** @var IDBConnection */ |
|
| 45 | + protected $dbConn; |
|
| 46 | + |
|
| 47 | + /** @var ILogger */ |
|
| 48 | + protected $logger; |
|
| 49 | + |
|
| 50 | + /** @var IConfig */ |
|
| 51 | + protected $config; |
|
| 52 | + |
|
| 53 | + /** @var IComment[] */ |
|
| 54 | + protected $commentsCache = []; |
|
| 55 | + |
|
| 56 | + /** @var \Closure[] */ |
|
| 57 | + protected $eventHandlerClosures = []; |
|
| 58 | + |
|
| 59 | + /** @var ICommentsEventHandler[] */ |
|
| 60 | + protected $eventHandlers = []; |
|
| 61 | + |
|
| 62 | + /** @var \Closure[] */ |
|
| 63 | + protected $displayNameResolvers = []; |
|
| 64 | + |
|
| 65 | + /** |
|
| 66 | + * Manager constructor. |
|
| 67 | + * |
|
| 68 | + * @param IDBConnection $dbConn |
|
| 69 | + * @param ILogger $logger |
|
| 70 | + * @param IConfig $config |
|
| 71 | + */ |
|
| 72 | + public function __construct( |
|
| 73 | + IDBConnection $dbConn, |
|
| 74 | + ILogger $logger, |
|
| 75 | + IConfig $config |
|
| 76 | + ) { |
|
| 77 | + $this->dbConn = $dbConn; |
|
| 78 | + $this->logger = $logger; |
|
| 79 | + $this->config = $config; |
|
| 80 | + } |
|
| 81 | + |
|
| 82 | + /** |
|
| 83 | + * converts data base data into PHP native, proper types as defined by |
|
| 84 | + * IComment interface. |
|
| 85 | + * |
|
| 86 | + * @param array $data |
|
| 87 | + * @return array |
|
| 88 | + */ |
|
| 89 | + protected function normalizeDatabaseData(array $data) { |
|
| 90 | + $data['id'] = (string)$data['id']; |
|
| 91 | + $data['parent_id'] = (string)$data['parent_id']; |
|
| 92 | + $data['topmost_parent_id'] = (string)$data['topmost_parent_id']; |
|
| 93 | + $data['creation_timestamp'] = new \DateTime($data['creation_timestamp']); |
|
| 94 | + if (!is_null($data['latest_child_timestamp'])) { |
|
| 95 | + $data['latest_child_timestamp'] = new \DateTime($data['latest_child_timestamp']); |
|
| 96 | + } |
|
| 97 | + $data['children_count'] = (int)$data['children_count']; |
|
| 98 | + return $data; |
|
| 99 | + } |
|
| 100 | + |
|
| 101 | + /** |
|
| 102 | + * prepares a comment for an insert or update operation after making sure |
|
| 103 | + * all necessary fields have a value assigned. |
|
| 104 | + * |
|
| 105 | + * @param IComment $comment |
|
| 106 | + * @return IComment returns the same updated IComment instance as provided |
|
| 107 | + * by parameter for convenience |
|
| 108 | + * @throws \UnexpectedValueException |
|
| 109 | + */ |
|
| 110 | + protected function prepareCommentForDatabaseWrite(IComment $comment) { |
|
| 111 | + if (!$comment->getActorType() |
|
| 112 | + || !$comment->getActorId() |
|
| 113 | + || !$comment->getObjectType() |
|
| 114 | + || !$comment->getObjectId() |
|
| 115 | + || !$comment->getVerb() |
|
| 116 | + ) { |
|
| 117 | + throw new \UnexpectedValueException('Actor, Object and Verb information must be provided for saving'); |
|
| 118 | + } |
|
| 119 | + |
|
| 120 | + if ($comment->getId() === '') { |
|
| 121 | + $comment->setChildrenCount(0); |
|
| 122 | + $comment->setLatestChildDateTime(new \DateTime('0000-00-00 00:00:00', new \DateTimeZone('UTC'))); |
|
| 123 | + $comment->setLatestChildDateTime(null); |
|
| 124 | + } |
|
| 125 | + |
|
| 126 | + if (is_null($comment->getCreationDateTime())) { |
|
| 127 | + $comment->setCreationDateTime(new \DateTime()); |
|
| 128 | + } |
|
| 129 | + |
|
| 130 | + if ($comment->getParentId() !== '0') { |
|
| 131 | + $comment->setTopmostParentId($this->determineTopmostParentId($comment->getParentId())); |
|
| 132 | + } else { |
|
| 133 | + $comment->setTopmostParentId('0'); |
|
| 134 | + } |
|
| 135 | + |
|
| 136 | + $this->cache($comment); |
|
| 137 | + |
|
| 138 | + return $comment; |
|
| 139 | + } |
|
| 140 | + |
|
| 141 | + /** |
|
| 142 | + * returns the topmost parent id of a given comment identified by ID |
|
| 143 | + * |
|
| 144 | + * @param string $id |
|
| 145 | + * @return string |
|
| 146 | + * @throws NotFoundException |
|
| 147 | + */ |
|
| 148 | + protected function determineTopmostParentId($id) { |
|
| 149 | + $comment = $this->get($id); |
|
| 150 | + if ($comment->getParentId() === '0') { |
|
| 151 | + return $comment->getId(); |
|
| 152 | + } else { |
|
| 153 | + return $this->determineTopmostParentId($comment->getId()); |
|
| 154 | + } |
|
| 155 | + } |
|
| 156 | + |
|
| 157 | + /** |
|
| 158 | + * updates child information of a comment |
|
| 159 | + * |
|
| 160 | + * @param string $id |
|
| 161 | + * @param \DateTime $cDateTime the date time of the most recent child |
|
| 162 | + * @throws NotFoundException |
|
| 163 | + */ |
|
| 164 | + protected function updateChildrenInformation($id, \DateTime $cDateTime) { |
|
| 165 | + $qb = $this->dbConn->getQueryBuilder(); |
|
| 166 | + $query = $qb->select($qb->createFunction('COUNT(`id`)')) |
|
| 167 | + ->from('comments') |
|
| 168 | + ->where($qb->expr()->eq('parent_id', $qb->createParameter('id'))) |
|
| 169 | + ->setParameter('id', $id); |
|
| 170 | + |
|
| 171 | + $resultStatement = $query->execute(); |
|
| 172 | + $data = $resultStatement->fetch(\PDO::FETCH_NUM); |
|
| 173 | + $resultStatement->closeCursor(); |
|
| 174 | + $children = (int)$data[0]; |
|
| 175 | + |
|
| 176 | + $comment = $this->get($id); |
|
| 177 | + $comment->setChildrenCount($children); |
|
| 178 | + $comment->setLatestChildDateTime($cDateTime); |
|
| 179 | + $this->save($comment); |
|
| 180 | + } |
|
| 181 | + |
|
| 182 | + /** |
|
| 183 | + * Tests whether actor or object type and id parameters are acceptable. |
|
| 184 | + * Throws exception if not. |
|
| 185 | + * |
|
| 186 | + * @param string $role |
|
| 187 | + * @param string $type |
|
| 188 | + * @param string $id |
|
| 189 | + * @throws \InvalidArgumentException |
|
| 190 | + */ |
|
| 191 | + protected function checkRoleParameters($role, $type, $id) { |
|
| 192 | + if ( |
|
| 193 | + !is_string($type) || empty($type) |
|
| 194 | + || !is_string($id) || empty($id) |
|
| 195 | + ) { |
|
| 196 | + throw new \InvalidArgumentException($role . ' parameters must be string and not empty'); |
|
| 197 | + } |
|
| 198 | + } |
|
| 199 | + |
|
| 200 | + /** |
|
| 201 | + * run-time caches a comment |
|
| 202 | + * |
|
| 203 | + * @param IComment $comment |
|
| 204 | + */ |
|
| 205 | + protected function cache(IComment $comment) { |
|
| 206 | + $id = $comment->getId(); |
|
| 207 | + if (empty($id)) { |
|
| 208 | + return; |
|
| 209 | + } |
|
| 210 | + $this->commentsCache[(string)$id] = $comment; |
|
| 211 | + } |
|
| 212 | + |
|
| 213 | + /** |
|
| 214 | + * removes an entry from the comments run time cache |
|
| 215 | + * |
|
| 216 | + * @param mixed $id the comment's id |
|
| 217 | + */ |
|
| 218 | + protected function uncache($id) { |
|
| 219 | + $id = (string)$id; |
|
| 220 | + if (isset($this->commentsCache[$id])) { |
|
| 221 | + unset($this->commentsCache[$id]); |
|
| 222 | + } |
|
| 223 | + } |
|
| 224 | + |
|
| 225 | + /** |
|
| 226 | + * returns a comment instance |
|
| 227 | + * |
|
| 228 | + * @param string $id the ID of the comment |
|
| 229 | + * @return IComment |
|
| 230 | + * @throws NotFoundException |
|
| 231 | + * @throws \InvalidArgumentException |
|
| 232 | + * @since 9.0.0 |
|
| 233 | + */ |
|
| 234 | + public function get($id) { |
|
| 235 | + if ((int)$id === 0) { |
|
| 236 | + throw new \InvalidArgumentException('IDs must be translatable to a number in this implementation.'); |
|
| 237 | + } |
|
| 238 | + |
|
| 239 | + if (isset($this->commentsCache[$id])) { |
|
| 240 | + return $this->commentsCache[$id]; |
|
| 241 | + } |
|
| 242 | + |
|
| 243 | + $qb = $this->dbConn->getQueryBuilder(); |
|
| 244 | + $resultStatement = $qb->select('*') |
|
| 245 | + ->from('comments') |
|
| 246 | + ->where($qb->expr()->eq('id', $qb->createParameter('id'))) |
|
| 247 | + ->setParameter('id', $id, IQueryBuilder::PARAM_INT) |
|
| 248 | + ->execute(); |
|
| 249 | + |
|
| 250 | + $data = $resultStatement->fetch(); |
|
| 251 | + $resultStatement->closeCursor(); |
|
| 252 | + if (!$data) { |
|
| 253 | + throw new NotFoundException(); |
|
| 254 | + } |
|
| 255 | + |
|
| 256 | + $comment = new Comment($this->normalizeDatabaseData($data)); |
|
| 257 | + $this->cache($comment); |
|
| 258 | + return $comment; |
|
| 259 | + } |
|
| 260 | + |
|
| 261 | + /** |
|
| 262 | + * returns the comment specified by the id and all it's child comments. |
|
| 263 | + * At this point of time, we do only support one level depth. |
|
| 264 | + * |
|
| 265 | + * @param string $id |
|
| 266 | + * @param int $limit max number of entries to return, 0 returns all |
|
| 267 | + * @param int $offset the start entry |
|
| 268 | + * @return array |
|
| 269 | + * @since 9.0.0 |
|
| 270 | + * |
|
| 271 | + * The return array looks like this |
|
| 272 | + * [ |
|
| 273 | + * 'comment' => IComment, // root comment |
|
| 274 | + * 'replies' => |
|
| 275 | + * [ |
|
| 276 | + * 0 => |
|
| 277 | + * [ |
|
| 278 | + * 'comment' => IComment, |
|
| 279 | + * 'replies' => [] |
|
| 280 | + * ] |
|
| 281 | + * 1 => |
|
| 282 | + * [ |
|
| 283 | + * 'comment' => IComment, |
|
| 284 | + * 'replies'=> [] |
|
| 285 | + * ], |
|
| 286 | + * … |
|
| 287 | + * ] |
|
| 288 | + * ] |
|
| 289 | + */ |
|
| 290 | + public function getTree($id, $limit = 0, $offset = 0) { |
|
| 291 | + $tree = []; |
|
| 292 | + $tree['comment'] = $this->get($id); |
|
| 293 | + $tree['replies'] = []; |
|
| 294 | + |
|
| 295 | + $qb = $this->dbConn->getQueryBuilder(); |
|
| 296 | + $query = $qb->select('*') |
|
| 297 | + ->from('comments') |
|
| 298 | + ->where($qb->expr()->eq('topmost_parent_id', $qb->createParameter('id'))) |
|
| 299 | + ->orderBy('creation_timestamp', 'DESC') |
|
| 300 | + ->setParameter('id', $id); |
|
| 301 | + |
|
| 302 | + if ($limit > 0) { |
|
| 303 | + $query->setMaxResults($limit); |
|
| 304 | + } |
|
| 305 | + if ($offset > 0) { |
|
| 306 | + $query->setFirstResult($offset); |
|
| 307 | + } |
|
| 308 | + |
|
| 309 | + $resultStatement = $query->execute(); |
|
| 310 | + while ($data = $resultStatement->fetch()) { |
|
| 311 | + $comment = new Comment($this->normalizeDatabaseData($data)); |
|
| 312 | + $this->cache($comment); |
|
| 313 | + $tree['replies'][] = [ |
|
| 314 | + 'comment' => $comment, |
|
| 315 | + 'replies' => [] |
|
| 316 | + ]; |
|
| 317 | + } |
|
| 318 | + $resultStatement->closeCursor(); |
|
| 319 | + |
|
| 320 | + return $tree; |
|
| 321 | + } |
|
| 322 | + |
|
| 323 | + /** |
|
| 324 | + * returns comments for a specific object (e.g. a file). |
|
| 325 | + * |
|
| 326 | + * The sort order is always newest to oldest. |
|
| 327 | + * |
|
| 328 | + * @param string $objectType the object type, e.g. 'files' |
|
| 329 | + * @param string $objectId the id of the object |
|
| 330 | + * @param int $limit optional, number of maximum comments to be returned. if |
|
| 331 | + * not specified, all comments are returned. |
|
| 332 | + * @param int $offset optional, starting point |
|
| 333 | + * @param \DateTime $notOlderThan optional, timestamp of the oldest comments |
|
| 334 | + * that may be returned |
|
| 335 | + * @return IComment[] |
|
| 336 | + * @since 9.0.0 |
|
| 337 | + */ |
|
| 338 | + public function getForObject( |
|
| 339 | + $objectType, |
|
| 340 | + $objectId, |
|
| 341 | + $limit = 0, |
|
| 342 | + $offset = 0, |
|
| 343 | + \DateTime $notOlderThan = null |
|
| 344 | + ) { |
|
| 345 | + $comments = []; |
|
| 346 | + |
|
| 347 | + $qb = $this->dbConn->getQueryBuilder(); |
|
| 348 | + $query = $qb->select('*') |
|
| 349 | + ->from('comments') |
|
| 350 | + ->where($qb->expr()->eq('object_type', $qb->createParameter('type'))) |
|
| 351 | + ->andWhere($qb->expr()->eq('object_id', $qb->createParameter('id'))) |
|
| 352 | + ->orderBy('creation_timestamp', 'DESC') |
|
| 353 | + ->setParameter('type', $objectType) |
|
| 354 | + ->setParameter('id', $objectId); |
|
| 355 | + |
|
| 356 | + if ($limit > 0) { |
|
| 357 | + $query->setMaxResults($limit); |
|
| 358 | + } |
|
| 359 | + if ($offset > 0) { |
|
| 360 | + $query->setFirstResult($offset); |
|
| 361 | + } |
|
| 362 | + if (!is_null($notOlderThan)) { |
|
| 363 | + $query |
|
| 364 | + ->andWhere($qb->expr()->gt('creation_timestamp', $qb->createParameter('notOlderThan'))) |
|
| 365 | + ->setParameter('notOlderThan', $notOlderThan, 'datetime'); |
|
| 366 | + } |
|
| 367 | + |
|
| 368 | + $resultStatement = $query->execute(); |
|
| 369 | + while ($data = $resultStatement->fetch()) { |
|
| 370 | + $comment = new Comment($this->normalizeDatabaseData($data)); |
|
| 371 | + $this->cache($comment); |
|
| 372 | + $comments[] = $comment; |
|
| 373 | + } |
|
| 374 | + $resultStatement->closeCursor(); |
|
| 375 | + |
|
| 376 | + return $comments; |
|
| 377 | + } |
|
| 378 | + |
|
| 379 | + /** |
|
| 380 | + * @param $objectType string the object type, e.g. 'files' |
|
| 381 | + * @param $objectId string the id of the object |
|
| 382 | + * @param \DateTime $notOlderThan optional, timestamp of the oldest comments |
|
| 383 | + * that may be returned |
|
| 384 | + * @return Int |
|
| 385 | + * @since 9.0.0 |
|
| 386 | + */ |
|
| 387 | + public function getNumberOfCommentsForObject($objectType, $objectId, \DateTime $notOlderThan = null) { |
|
| 388 | + $qb = $this->dbConn->getQueryBuilder(); |
|
| 389 | + $query = $qb->select($qb->createFunction('COUNT(`id`)')) |
|
| 390 | + ->from('comments') |
|
| 391 | + ->where($qb->expr()->eq('object_type', $qb->createParameter('type'))) |
|
| 392 | + ->andWhere($qb->expr()->eq('object_id', $qb->createParameter('id'))) |
|
| 393 | + ->setParameter('type', $objectType) |
|
| 394 | + ->setParameter('id', $objectId); |
|
| 395 | + |
|
| 396 | + if (!is_null($notOlderThan)) { |
|
| 397 | + $query |
|
| 398 | + ->andWhere($qb->expr()->gt('creation_timestamp', $qb->createParameter('notOlderThan'))) |
|
| 399 | + ->setParameter('notOlderThan', $notOlderThan, 'datetime'); |
|
| 400 | + } |
|
| 401 | + |
|
| 402 | + $resultStatement = $query->execute(); |
|
| 403 | + $data = $resultStatement->fetch(\PDO::FETCH_NUM); |
|
| 404 | + $resultStatement->closeCursor(); |
|
| 405 | + return (int)$data[0]; |
|
| 406 | + } |
|
| 407 | + |
|
| 408 | + /** |
|
| 409 | + * Get the number of unread comments for all files in a folder |
|
| 410 | + * |
|
| 411 | + * @param int $folderId |
|
| 412 | + * @param IUser $user |
|
| 413 | + * @return array [$fileId => $unreadCount] |
|
| 414 | + */ |
|
| 415 | + public function getNumberOfUnreadCommentsForFolder($folderId, IUser $user) { |
|
| 416 | + $qb = $this->dbConn->getQueryBuilder(); |
|
| 417 | + $query = $qb->select('f.fileid') |
|
| 418 | + ->selectAlias( |
|
| 419 | + $qb->createFunction('COUNT(' . $qb->getColumnName('c.id') . ')'), |
|
| 420 | + 'num_ids' |
|
| 421 | + ) |
|
| 422 | + ->from('comments', 'c') |
|
| 423 | + ->innerJoin('c', 'filecache', 'f', $qb->expr()->andX( |
|
| 424 | + $qb->expr()->eq('c.object_type', $qb->createNamedParameter('files')), |
|
| 425 | + $qb->expr()->eq('f.fileid', $qb->expr()->castColumn('c.object_id', IQueryBuilder::PARAM_INT)) |
|
| 426 | + )) |
|
| 427 | + ->leftJoin('c', 'comments_read_markers', 'm', $qb->expr()->andX( |
|
| 428 | + $qb->expr()->eq('m.object_type', $qb->createNamedParameter('files')), |
|
| 429 | + $qb->expr()->eq('m.object_id', 'c.object_id'), |
|
| 430 | + $qb->expr()->eq('m.user_id', $qb->createNamedParameter($user->getUID())) |
|
| 431 | + )) |
|
| 432 | + ->andWhere($qb->expr()->eq('f.parent', $qb->createNamedParameter($folderId))) |
|
| 433 | + ->andWhere($qb->expr()->orX( |
|
| 434 | + $qb->expr()->gt('c.creation_timestamp', 'marker_datetime'), |
|
| 435 | + $qb->expr()->isNull('marker_datetime') |
|
| 436 | + )) |
|
| 437 | + ->groupBy('f.fileid'); |
|
| 438 | + |
|
| 439 | + $resultStatement = $query->execute(); |
|
| 440 | + |
|
| 441 | + $results = []; |
|
| 442 | + while ($row = $resultStatement->fetch()) { |
|
| 443 | + $results[$row['fileid']] = (int) $row['num_ids']; |
|
| 444 | + } |
|
| 445 | + $resultStatement->closeCursor(); |
|
| 446 | + return $results; |
|
| 447 | + } |
|
| 448 | + |
|
| 449 | + /** |
|
| 450 | + * creates a new comment and returns it. At this point of time, it is not |
|
| 451 | + * saved in the used data storage. Use save() after setting other fields |
|
| 452 | + * of the comment (e.g. message or verb). |
|
| 453 | + * |
|
| 454 | + * @param string $actorType the actor type (e.g. 'users') |
|
| 455 | + * @param string $actorId a user id |
|
| 456 | + * @param string $objectType the object type the comment is attached to |
|
| 457 | + * @param string $objectId the object id the comment is attached to |
|
| 458 | + * @return IComment |
|
| 459 | + * @since 9.0.0 |
|
| 460 | + */ |
|
| 461 | + public function create($actorType, $actorId, $objectType, $objectId) { |
|
| 462 | + $comment = new Comment(); |
|
| 463 | + $comment |
|
| 464 | + ->setActor($actorType, $actorId) |
|
| 465 | + ->setObject($objectType, $objectId); |
|
| 466 | + return $comment; |
|
| 467 | + } |
|
| 468 | + |
|
| 469 | + /** |
|
| 470 | + * permanently deletes the comment specified by the ID |
|
| 471 | + * |
|
| 472 | + * When the comment has child comments, their parent ID will be changed to |
|
| 473 | + * the parent ID of the item that is to be deleted. |
|
| 474 | + * |
|
| 475 | + * @param string $id |
|
| 476 | + * @return bool |
|
| 477 | + * @throws \InvalidArgumentException |
|
| 478 | + * @since 9.0.0 |
|
| 479 | + */ |
|
| 480 | + public function delete($id) { |
|
| 481 | + if (!is_string($id)) { |
|
| 482 | + throw new \InvalidArgumentException('Parameter must be string'); |
|
| 483 | + } |
|
| 484 | + |
|
| 485 | + try { |
|
| 486 | + $comment = $this->get($id); |
|
| 487 | + } catch (\Exception $e) { |
|
| 488 | + // Ignore exceptions, we just don't fire a hook then |
|
| 489 | + $comment = null; |
|
| 490 | + } |
|
| 491 | + |
|
| 492 | + $qb = $this->dbConn->getQueryBuilder(); |
|
| 493 | + $query = $qb->delete('comments') |
|
| 494 | + ->where($qb->expr()->eq('id', $qb->createParameter('id'))) |
|
| 495 | + ->setParameter('id', $id); |
|
| 496 | + |
|
| 497 | + try { |
|
| 498 | + $affectedRows = $query->execute(); |
|
| 499 | + $this->uncache($id); |
|
| 500 | + } catch (DriverException $e) { |
|
| 501 | + $this->logger->logException($e, ['app' => 'core_comments']); |
|
| 502 | + return false; |
|
| 503 | + } |
|
| 504 | + |
|
| 505 | + if ($affectedRows > 0 && $comment instanceof IComment) { |
|
| 506 | + $this->sendEvent(CommentsEvent::EVENT_DELETE, $comment); |
|
| 507 | + } |
|
| 508 | + |
|
| 509 | + return ($affectedRows > 0); |
|
| 510 | + } |
|
| 511 | + |
|
| 512 | + /** |
|
| 513 | + * saves the comment permanently |
|
| 514 | + * |
|
| 515 | + * if the supplied comment has an empty ID, a new entry comment will be |
|
| 516 | + * saved and the instance updated with the new ID. |
|
| 517 | + * |
|
| 518 | + * Otherwise, an existing comment will be updated. |
|
| 519 | + * |
|
| 520 | + * Throws NotFoundException when a comment that is to be updated does not |
|
| 521 | + * exist anymore at this point of time. |
|
| 522 | + * |
|
| 523 | + * @param IComment $comment |
|
| 524 | + * @return bool |
|
| 525 | + * @throws NotFoundException |
|
| 526 | + * @since 9.0.0 |
|
| 527 | + */ |
|
| 528 | + public function save(IComment $comment) { |
|
| 529 | + if ($this->prepareCommentForDatabaseWrite($comment)->getId() === '') { |
|
| 530 | + $result = $this->insert($comment); |
|
| 531 | + } else { |
|
| 532 | + $result = $this->update($comment); |
|
| 533 | + } |
|
| 534 | + |
|
| 535 | + if ($result && !!$comment->getParentId()) { |
|
| 536 | + $this->updateChildrenInformation( |
|
| 537 | + $comment->getParentId(), |
|
| 538 | + $comment->getCreationDateTime() |
|
| 539 | + ); |
|
| 540 | + $this->cache($comment); |
|
| 541 | + } |
|
| 542 | + |
|
| 543 | + return $result; |
|
| 544 | + } |
|
| 545 | + |
|
| 546 | + /** |
|
| 547 | + * inserts the provided comment in the database |
|
| 548 | + * |
|
| 549 | + * @param IComment $comment |
|
| 550 | + * @return bool |
|
| 551 | + */ |
|
| 552 | + protected function insert(IComment &$comment) { |
|
| 553 | + $qb = $this->dbConn->getQueryBuilder(); |
|
| 554 | + $affectedRows = $qb |
|
| 555 | + ->insert('comments') |
|
| 556 | + ->values([ |
|
| 557 | + 'parent_id' => $qb->createNamedParameter($comment->getParentId()), |
|
| 558 | + 'topmost_parent_id' => $qb->createNamedParameter($comment->getTopmostParentId()), |
|
| 559 | + 'children_count' => $qb->createNamedParameter($comment->getChildrenCount()), |
|
| 560 | + 'actor_type' => $qb->createNamedParameter($comment->getActorType()), |
|
| 561 | + 'actor_id' => $qb->createNamedParameter($comment->getActorId()), |
|
| 562 | + 'message' => $qb->createNamedParameter($comment->getMessage()), |
|
| 563 | + 'verb' => $qb->createNamedParameter($comment->getVerb()), |
|
| 564 | + 'creation_timestamp' => $qb->createNamedParameter($comment->getCreationDateTime(), 'datetime'), |
|
| 565 | + 'latest_child_timestamp' => $qb->createNamedParameter($comment->getLatestChildDateTime(), 'datetime'), |
|
| 566 | + 'object_type' => $qb->createNamedParameter($comment->getObjectType()), |
|
| 567 | + 'object_id' => $qb->createNamedParameter($comment->getObjectId()), |
|
| 568 | + ]) |
|
| 569 | + ->execute(); |
|
| 570 | + |
|
| 571 | + if ($affectedRows > 0) { |
|
| 572 | + $comment->setId((string)$qb->getLastInsertId()); |
|
| 573 | + $this->sendEvent(CommentsEvent::EVENT_ADD, $comment); |
|
| 574 | + } |
|
| 575 | + |
|
| 576 | + return $affectedRows > 0; |
|
| 577 | + } |
|
| 578 | + |
|
| 579 | + /** |
|
| 580 | + * updates a Comment data row |
|
| 581 | + * |
|
| 582 | + * @param IComment $comment |
|
| 583 | + * @return bool |
|
| 584 | + * @throws NotFoundException |
|
| 585 | + */ |
|
| 586 | + protected function update(IComment $comment) { |
|
| 587 | + // for properly working preUpdate Events we need the old comments as is |
|
| 588 | + // in the DB and overcome caching. Also avoid that outdated information stays. |
|
| 589 | + $this->uncache($comment->getId()); |
|
| 590 | + $this->sendEvent(CommentsEvent::EVENT_PRE_UPDATE, $this->get($comment->getId())); |
|
| 591 | + $this->uncache($comment->getId()); |
|
| 592 | + |
|
| 593 | + $qb = $this->dbConn->getQueryBuilder(); |
|
| 594 | + $affectedRows = $qb |
|
| 595 | + ->update('comments') |
|
| 596 | + ->set('parent_id', $qb->createNamedParameter($comment->getParentId())) |
|
| 597 | + ->set('topmost_parent_id', $qb->createNamedParameter($comment->getTopmostParentId())) |
|
| 598 | + ->set('children_count', $qb->createNamedParameter($comment->getChildrenCount())) |
|
| 599 | + ->set('actor_type', $qb->createNamedParameter($comment->getActorType())) |
|
| 600 | + ->set('actor_id', $qb->createNamedParameter($comment->getActorId())) |
|
| 601 | + ->set('message', $qb->createNamedParameter($comment->getMessage())) |
|
| 602 | + ->set('verb', $qb->createNamedParameter($comment->getVerb())) |
|
| 603 | + ->set('creation_timestamp', $qb->createNamedParameter($comment->getCreationDateTime(), 'datetime')) |
|
| 604 | + ->set('latest_child_timestamp', $qb->createNamedParameter($comment->getLatestChildDateTime(), 'datetime')) |
|
| 605 | + ->set('object_type', $qb->createNamedParameter($comment->getObjectType())) |
|
| 606 | + ->set('object_id', $qb->createNamedParameter($comment->getObjectId())) |
|
| 607 | + ->where($qb->expr()->eq('id', $qb->createParameter('id'))) |
|
| 608 | + ->setParameter('id', $comment->getId()) |
|
| 609 | + ->execute(); |
|
| 610 | + |
|
| 611 | + if ($affectedRows === 0) { |
|
| 612 | + throw new NotFoundException('Comment to update does ceased to exist'); |
|
| 613 | + } |
|
| 614 | + |
|
| 615 | + $this->sendEvent(CommentsEvent::EVENT_UPDATE, $comment); |
|
| 616 | + |
|
| 617 | + return $affectedRows > 0; |
|
| 618 | + } |
|
| 619 | + |
|
| 620 | + /** |
|
| 621 | + * removes references to specific actor (e.g. on user delete) of a comment. |
|
| 622 | + * The comment itself must not get lost/deleted. |
|
| 623 | + * |
|
| 624 | + * @param string $actorType the actor type (e.g. 'users') |
|
| 625 | + * @param string $actorId a user id |
|
| 626 | + * @return boolean |
|
| 627 | + * @since 9.0.0 |
|
| 628 | + */ |
|
| 629 | + public function deleteReferencesOfActor($actorType, $actorId) { |
|
| 630 | + $this->checkRoleParameters('Actor', $actorType, $actorId); |
|
| 631 | + |
|
| 632 | + $qb = $this->dbConn->getQueryBuilder(); |
|
| 633 | + $affectedRows = $qb |
|
| 634 | + ->update('comments') |
|
| 635 | + ->set('actor_type', $qb->createNamedParameter(ICommentsManager::DELETED_USER)) |
|
| 636 | + ->set('actor_id', $qb->createNamedParameter(ICommentsManager::DELETED_USER)) |
|
| 637 | + ->where($qb->expr()->eq('actor_type', $qb->createParameter('type'))) |
|
| 638 | + ->andWhere($qb->expr()->eq('actor_id', $qb->createParameter('id'))) |
|
| 639 | + ->setParameter('type', $actorType) |
|
| 640 | + ->setParameter('id', $actorId) |
|
| 641 | + ->execute(); |
|
| 642 | + |
|
| 643 | + $this->commentsCache = []; |
|
| 644 | + |
|
| 645 | + return is_int($affectedRows); |
|
| 646 | + } |
|
| 647 | + |
|
| 648 | + /** |
|
| 649 | + * deletes all comments made of a specific object (e.g. on file delete) |
|
| 650 | + * |
|
| 651 | + * @param string $objectType the object type (e.g. 'files') |
|
| 652 | + * @param string $objectId e.g. the file id |
|
| 653 | + * @return boolean |
|
| 654 | + * @since 9.0.0 |
|
| 655 | + */ |
|
| 656 | + public function deleteCommentsAtObject($objectType, $objectId) { |
|
| 657 | + $this->checkRoleParameters('Object', $objectType, $objectId); |
|
| 658 | + |
|
| 659 | + $qb = $this->dbConn->getQueryBuilder(); |
|
| 660 | + $affectedRows = $qb |
|
| 661 | + ->delete('comments') |
|
| 662 | + ->where($qb->expr()->eq('object_type', $qb->createParameter('type'))) |
|
| 663 | + ->andWhere($qb->expr()->eq('object_id', $qb->createParameter('id'))) |
|
| 664 | + ->setParameter('type', $objectType) |
|
| 665 | + ->setParameter('id', $objectId) |
|
| 666 | + ->execute(); |
|
| 667 | + |
|
| 668 | + $this->commentsCache = []; |
|
| 669 | + |
|
| 670 | + return is_int($affectedRows); |
|
| 671 | + } |
|
| 672 | + |
|
| 673 | + /** |
|
| 674 | + * deletes the read markers for the specified user |
|
| 675 | + * |
|
| 676 | + * @param \OCP\IUser $user |
|
| 677 | + * @return bool |
|
| 678 | + * @since 9.0.0 |
|
| 679 | + */ |
|
| 680 | + public function deleteReadMarksFromUser(IUser $user) { |
|
| 681 | + $qb = $this->dbConn->getQueryBuilder(); |
|
| 682 | + $query = $qb->delete('comments_read_markers') |
|
| 683 | + ->where($qb->expr()->eq('user_id', $qb->createParameter('user_id'))) |
|
| 684 | + ->setParameter('user_id', $user->getUID()); |
|
| 685 | + |
|
| 686 | + try { |
|
| 687 | + $affectedRows = $query->execute(); |
|
| 688 | + } catch (DriverException $e) { |
|
| 689 | + $this->logger->logException($e, ['app' => 'core_comments']); |
|
| 690 | + return false; |
|
| 691 | + } |
|
| 692 | + return ($affectedRows > 0); |
|
| 693 | + } |
|
| 694 | + |
|
| 695 | + /** |
|
| 696 | + * sets the read marker for a given file to the specified date for the |
|
| 697 | + * provided user |
|
| 698 | + * |
|
| 699 | + * @param string $objectType |
|
| 700 | + * @param string $objectId |
|
| 701 | + * @param \DateTime $dateTime |
|
| 702 | + * @param IUser $user |
|
| 703 | + * @since 9.0.0 |
|
| 704 | + * @suppress SqlInjectionChecker |
|
| 705 | + */ |
|
| 706 | + public function setReadMark($objectType, $objectId, \DateTime $dateTime, IUser $user) { |
|
| 707 | + $this->checkRoleParameters('Object', $objectType, $objectId); |
|
| 708 | + |
|
| 709 | + $qb = $this->dbConn->getQueryBuilder(); |
|
| 710 | + $values = [ |
|
| 711 | + 'user_id' => $qb->createNamedParameter($user->getUID()), |
|
| 712 | + 'marker_datetime' => $qb->createNamedParameter($dateTime, 'datetime'), |
|
| 713 | + 'object_type' => $qb->createNamedParameter($objectType), |
|
| 714 | + 'object_id' => $qb->createNamedParameter($objectId), |
|
| 715 | + ]; |
|
| 716 | + |
|
| 717 | + // Strategy: try to update, if this does not return affected rows, do an insert. |
|
| 718 | + $affectedRows = $qb |
|
| 719 | + ->update('comments_read_markers') |
|
| 720 | + ->set('user_id', $values['user_id']) |
|
| 721 | + ->set('marker_datetime', $values['marker_datetime']) |
|
| 722 | + ->set('object_type', $values['object_type']) |
|
| 723 | + ->set('object_id', $values['object_id']) |
|
| 724 | + ->where($qb->expr()->eq('user_id', $qb->createParameter('user_id'))) |
|
| 725 | + ->andWhere($qb->expr()->eq('object_type', $qb->createParameter('object_type'))) |
|
| 726 | + ->andWhere($qb->expr()->eq('object_id', $qb->createParameter('object_id'))) |
|
| 727 | + ->setParameter('user_id', $user->getUID(), IQueryBuilder::PARAM_STR) |
|
| 728 | + ->setParameter('object_type', $objectType, IQueryBuilder::PARAM_STR) |
|
| 729 | + ->setParameter('object_id', $objectId, IQueryBuilder::PARAM_STR) |
|
| 730 | + ->execute(); |
|
| 731 | + |
|
| 732 | + if ($affectedRows > 0) { |
|
| 733 | + return; |
|
| 734 | + } |
|
| 735 | + |
|
| 736 | + $qb->insert('comments_read_markers') |
|
| 737 | + ->values($values) |
|
| 738 | + ->execute(); |
|
| 739 | + } |
|
| 740 | + |
|
| 741 | + /** |
|
| 742 | + * returns the read marker for a given file to the specified date for the |
|
| 743 | + * provided user. It returns null, when the marker is not present, i.e. |
|
| 744 | + * no comments were marked as read. |
|
| 745 | + * |
|
| 746 | + * @param string $objectType |
|
| 747 | + * @param string $objectId |
|
| 748 | + * @param IUser $user |
|
| 749 | + * @return \DateTime|null |
|
| 750 | + * @since 9.0.0 |
|
| 751 | + */ |
|
| 752 | + public function getReadMark($objectType, $objectId, IUser $user) { |
|
| 753 | + $qb = $this->dbConn->getQueryBuilder(); |
|
| 754 | + $resultStatement = $qb->select('marker_datetime') |
|
| 755 | + ->from('comments_read_markers') |
|
| 756 | + ->where($qb->expr()->eq('user_id', $qb->createParameter('user_id'))) |
|
| 757 | + ->andWhere($qb->expr()->eq('object_type', $qb->createParameter('object_type'))) |
|
| 758 | + ->andWhere($qb->expr()->eq('object_id', $qb->createParameter('object_id'))) |
|
| 759 | + ->setParameter('user_id', $user->getUID(), IQueryBuilder::PARAM_STR) |
|
| 760 | + ->setParameter('object_type', $objectType, IQueryBuilder::PARAM_STR) |
|
| 761 | + ->setParameter('object_id', $objectId, IQueryBuilder::PARAM_STR) |
|
| 762 | + ->execute(); |
|
| 763 | + |
|
| 764 | + $data = $resultStatement->fetch(); |
|
| 765 | + $resultStatement->closeCursor(); |
|
| 766 | + if (!$data || is_null($data['marker_datetime'])) { |
|
| 767 | + return null; |
|
| 768 | + } |
|
| 769 | + |
|
| 770 | + return new \DateTime($data['marker_datetime']); |
|
| 771 | + } |
|
| 772 | + |
|
| 773 | + /** |
|
| 774 | + * deletes the read markers on the specified object |
|
| 775 | + * |
|
| 776 | + * @param string $objectType |
|
| 777 | + * @param string $objectId |
|
| 778 | + * @return bool |
|
| 779 | + * @since 9.0.0 |
|
| 780 | + */ |
|
| 781 | + public function deleteReadMarksOnObject($objectType, $objectId) { |
|
| 782 | + $this->checkRoleParameters('Object', $objectType, $objectId); |
|
| 783 | + |
|
| 784 | + $qb = $this->dbConn->getQueryBuilder(); |
|
| 785 | + $query = $qb->delete('comments_read_markers') |
|
| 786 | + ->where($qb->expr()->eq('object_type', $qb->createParameter('object_type'))) |
|
| 787 | + ->andWhere($qb->expr()->eq('object_id', $qb->createParameter('object_id'))) |
|
| 788 | + ->setParameter('object_type', $objectType) |
|
| 789 | + ->setParameter('object_id', $objectId); |
|
| 790 | + |
|
| 791 | + try { |
|
| 792 | + $affectedRows = $query->execute(); |
|
| 793 | + } catch (DriverException $e) { |
|
| 794 | + $this->logger->logException($e, ['app' => 'core_comments']); |
|
| 795 | + return false; |
|
| 796 | + } |
|
| 797 | + return ($affectedRows > 0); |
|
| 798 | + } |
|
| 799 | + |
|
| 800 | + /** |
|
| 801 | + * registers an Entity to the manager, so event notifications can be send |
|
| 802 | + * to consumers of the comments infrastructure |
|
| 803 | + * |
|
| 804 | + * @param \Closure $closure |
|
| 805 | + */ |
|
| 806 | + public function registerEventHandler(\Closure $closure) { |
|
| 807 | + $this->eventHandlerClosures[] = $closure; |
|
| 808 | + $this->eventHandlers = []; |
|
| 809 | + } |
|
| 810 | + |
|
| 811 | + /** |
|
| 812 | + * registers a method that resolves an ID to a display name for a given type |
|
| 813 | + * |
|
| 814 | + * @param string $type |
|
| 815 | + * @param \Closure $closure |
|
| 816 | + * @throws \OutOfBoundsException |
|
| 817 | + * @since 11.0.0 |
|
| 818 | + * |
|
| 819 | + * Only one resolver shall be registered per type. Otherwise a |
|
| 820 | + * \OutOfBoundsException has to thrown. |
|
| 821 | + */ |
|
| 822 | + public function registerDisplayNameResolver($type, \Closure $closure) { |
|
| 823 | + if (!is_string($type)) { |
|
| 824 | + throw new \InvalidArgumentException('String expected.'); |
|
| 825 | + } |
|
| 826 | + if (isset($this->displayNameResolvers[$type])) { |
|
| 827 | + throw new \OutOfBoundsException('Displayname resolver for this type already registered'); |
|
| 828 | + } |
|
| 829 | + $this->displayNameResolvers[$type] = $closure; |
|
| 830 | + } |
|
| 831 | + |
|
| 832 | + /** |
|
| 833 | + * resolves a given ID of a given Type to a display name. |
|
| 834 | + * |
|
| 835 | + * @param string $type |
|
| 836 | + * @param string $id |
|
| 837 | + * @return string |
|
| 838 | + * @throws \OutOfBoundsException |
|
| 839 | + * @since 11.0.0 |
|
| 840 | + * |
|
| 841 | + * If a provided type was not registered, an \OutOfBoundsException shall |
|
| 842 | + * be thrown. It is upon the resolver discretion what to return of the |
|
| 843 | + * provided ID is unknown. It must be ensured that a string is returned. |
|
| 844 | + */ |
|
| 845 | + public function resolveDisplayName($type, $id) { |
|
| 846 | + if (!is_string($type)) { |
|
| 847 | + throw new \InvalidArgumentException('String expected.'); |
|
| 848 | + } |
|
| 849 | + if (!isset($this->displayNameResolvers[$type])) { |
|
| 850 | + throw new \OutOfBoundsException('No Displayname resolver for this type registered'); |
|
| 851 | + } |
|
| 852 | + return (string)$this->displayNameResolvers[$type]($id); |
|
| 853 | + } |
|
| 854 | + |
|
| 855 | + /** |
|
| 856 | + * returns valid, registered entities |
|
| 857 | + * |
|
| 858 | + * @return \OCP\Comments\ICommentsEventHandler[] |
|
| 859 | + */ |
|
| 860 | + private function getEventHandlers() { |
|
| 861 | + if (!empty($this->eventHandlers)) { |
|
| 862 | + return $this->eventHandlers; |
|
| 863 | + } |
|
| 864 | + |
|
| 865 | + $this->eventHandlers = []; |
|
| 866 | + foreach ($this->eventHandlerClosures as $name => $closure) { |
|
| 867 | + $entity = $closure(); |
|
| 868 | + if (!($entity instanceof ICommentsEventHandler)) { |
|
| 869 | + throw new \InvalidArgumentException('The given entity does not implement the ICommentsEntity interface'); |
|
| 870 | + } |
|
| 871 | + $this->eventHandlers[$name] = $entity; |
|
| 872 | + } |
|
| 873 | + |
|
| 874 | + return $this->eventHandlers; |
|
| 875 | + } |
|
| 876 | + |
|
| 877 | + /** |
|
| 878 | + * sends notifications to the registered entities |
|
| 879 | + * |
|
| 880 | + * @param $eventType |
|
| 881 | + * @param IComment $comment |
|
| 882 | + */ |
|
| 883 | + private function sendEvent($eventType, IComment $comment) { |
|
| 884 | + $entities = $this->getEventHandlers(); |
|
| 885 | + $event = new CommentsEvent($eventType, $comment); |
|
| 886 | + foreach ($entities as $entity) { |
|
| 887 | + $entity->handle($event); |
|
| 888 | + } |
|
| 889 | + } |
|
| 890 | 890 | } |
@@ -87,14 +87,14 @@ discard block |
||
| 87 | 87 | * @return array |
| 88 | 88 | */ |
| 89 | 89 | protected function normalizeDatabaseData(array $data) { |
| 90 | - $data['id'] = (string)$data['id']; |
|
| 91 | - $data['parent_id'] = (string)$data['parent_id']; |
|
| 92 | - $data['topmost_parent_id'] = (string)$data['topmost_parent_id']; |
|
| 90 | + $data['id'] = (string) $data['id']; |
|
| 91 | + $data['parent_id'] = (string) $data['parent_id']; |
|
| 92 | + $data['topmost_parent_id'] = (string) $data['topmost_parent_id']; |
|
| 93 | 93 | $data['creation_timestamp'] = new \DateTime($data['creation_timestamp']); |
| 94 | 94 | if (!is_null($data['latest_child_timestamp'])) { |
| 95 | 95 | $data['latest_child_timestamp'] = new \DateTime($data['latest_child_timestamp']); |
| 96 | 96 | } |
| 97 | - $data['children_count'] = (int)$data['children_count']; |
|
| 97 | + $data['children_count'] = (int) $data['children_count']; |
|
| 98 | 98 | return $data; |
| 99 | 99 | } |
| 100 | 100 | |
@@ -171,7 +171,7 @@ discard block |
||
| 171 | 171 | $resultStatement = $query->execute(); |
| 172 | 172 | $data = $resultStatement->fetch(\PDO::FETCH_NUM); |
| 173 | 173 | $resultStatement->closeCursor(); |
| 174 | - $children = (int)$data[0]; |
|
| 174 | + $children = (int) $data[0]; |
|
| 175 | 175 | |
| 176 | 176 | $comment = $this->get($id); |
| 177 | 177 | $comment->setChildrenCount($children); |
@@ -193,7 +193,7 @@ discard block |
||
| 193 | 193 | !is_string($type) || empty($type) |
| 194 | 194 | || !is_string($id) || empty($id) |
| 195 | 195 | ) { |
| 196 | - throw new \InvalidArgumentException($role . ' parameters must be string and not empty'); |
|
| 196 | + throw new \InvalidArgumentException($role.' parameters must be string and not empty'); |
|
| 197 | 197 | } |
| 198 | 198 | } |
| 199 | 199 | |
@@ -207,7 +207,7 @@ discard block |
||
| 207 | 207 | if (empty($id)) { |
| 208 | 208 | return; |
| 209 | 209 | } |
| 210 | - $this->commentsCache[(string)$id] = $comment; |
|
| 210 | + $this->commentsCache[(string) $id] = $comment; |
|
| 211 | 211 | } |
| 212 | 212 | |
| 213 | 213 | /** |
@@ -216,7 +216,7 @@ discard block |
||
| 216 | 216 | * @param mixed $id the comment's id |
| 217 | 217 | */ |
| 218 | 218 | protected function uncache($id) { |
| 219 | - $id = (string)$id; |
|
| 219 | + $id = (string) $id; |
|
| 220 | 220 | if (isset($this->commentsCache[$id])) { |
| 221 | 221 | unset($this->commentsCache[$id]); |
| 222 | 222 | } |
@@ -232,7 +232,7 @@ discard block |
||
| 232 | 232 | * @since 9.0.0 |
| 233 | 233 | */ |
| 234 | 234 | public function get($id) { |
| 235 | - if ((int)$id === 0) { |
|
| 235 | + if ((int) $id === 0) { |
|
| 236 | 236 | throw new \InvalidArgumentException('IDs must be translatable to a number in this implementation.'); |
| 237 | 237 | } |
| 238 | 238 | |
@@ -402,7 +402,7 @@ discard block |
||
| 402 | 402 | $resultStatement = $query->execute(); |
| 403 | 403 | $data = $resultStatement->fetch(\PDO::FETCH_NUM); |
| 404 | 404 | $resultStatement->closeCursor(); |
| 405 | - return (int)$data[0]; |
|
| 405 | + return (int) $data[0]; |
|
| 406 | 406 | } |
| 407 | 407 | |
| 408 | 408 | /** |
@@ -416,7 +416,7 @@ discard block |
||
| 416 | 416 | $qb = $this->dbConn->getQueryBuilder(); |
| 417 | 417 | $query = $qb->select('f.fileid') |
| 418 | 418 | ->selectAlias( |
| 419 | - $qb->createFunction('COUNT(' . $qb->getColumnName('c.id') . ')'), |
|
| 419 | + $qb->createFunction('COUNT('.$qb->getColumnName('c.id').')'), |
|
| 420 | 420 | 'num_ids' |
| 421 | 421 | ) |
| 422 | 422 | ->from('comments', 'c') |
@@ -569,7 +569,7 @@ discard block |
||
| 569 | 569 | ->execute(); |
| 570 | 570 | |
| 571 | 571 | if ($affectedRows > 0) { |
| 572 | - $comment->setId((string)$qb->getLastInsertId()); |
|
| 572 | + $comment->setId((string) $qb->getLastInsertId()); |
|
| 573 | 573 | $this->sendEvent(CommentsEvent::EVENT_ADD, $comment); |
| 574 | 574 | } |
| 575 | 575 | |
@@ -849,7 +849,7 @@ discard block |
||
| 849 | 849 | if (!isset($this->displayNameResolvers[$type])) { |
| 850 | 850 | throw new \OutOfBoundsException('No Displayname resolver for this type registered'); |
| 851 | 851 | } |
| 852 | - return (string)$this->displayNameResolvers[$type]($id); |
|
| 852 | + return (string) $this->displayNameResolvers[$type]($id); |
|
| 853 | 853 | } |
| 854 | 854 | |
| 855 | 855 | /** |
@@ -36,39 +36,39 @@ |
||
| 36 | 36 | */ |
| 37 | 37 | class CheckApp extends Base { |
| 38 | 38 | |
| 39 | - /** |
|
| 40 | - * @var Checker |
|
| 41 | - */ |
|
| 42 | - private $checker; |
|
| 39 | + /** |
|
| 40 | + * @var Checker |
|
| 41 | + */ |
|
| 42 | + private $checker; |
|
| 43 | 43 | |
| 44 | - public function __construct(Checker $checker) { |
|
| 45 | - parent::__construct(); |
|
| 46 | - $this->checker = $checker; |
|
| 47 | - } |
|
| 44 | + public function __construct(Checker $checker) { |
|
| 45 | + parent::__construct(); |
|
| 46 | + $this->checker = $checker; |
|
| 47 | + } |
|
| 48 | 48 | |
| 49 | - /** |
|
| 50 | - * {@inheritdoc } |
|
| 51 | - */ |
|
| 52 | - protected function configure() { |
|
| 53 | - parent::configure(); |
|
| 54 | - $this |
|
| 55 | - ->setName('integrity:check-app') |
|
| 56 | - ->setDescription('Check integrity of an app using a signature.') |
|
| 57 | - ->addArgument('appid', null, InputArgument::REQUIRED, 'Application to check') |
|
| 58 | - ->addOption('path', null, InputOption::VALUE_OPTIONAL, 'Path to application. If none is given it will be guessed.'); |
|
| 59 | - } |
|
| 49 | + /** |
|
| 50 | + * {@inheritdoc } |
|
| 51 | + */ |
|
| 52 | + protected function configure() { |
|
| 53 | + parent::configure(); |
|
| 54 | + $this |
|
| 55 | + ->setName('integrity:check-app') |
|
| 56 | + ->setDescription('Check integrity of an app using a signature.') |
|
| 57 | + ->addArgument('appid', null, InputArgument::REQUIRED, 'Application to check') |
|
| 58 | + ->addOption('path', null, InputOption::VALUE_OPTIONAL, 'Path to application. If none is given it will be guessed.'); |
|
| 59 | + } |
|
| 60 | 60 | |
| 61 | - /** |
|
| 62 | - * {@inheritdoc } |
|
| 63 | - */ |
|
| 64 | - protected function execute(InputInterface $input, OutputInterface $output) { |
|
| 65 | - $appid = $input->getArgument('appid'); |
|
| 66 | - $path = (string)$input->getOption('path'); |
|
| 67 | - $result = $this->checker->verifyAppSignature($appid, $path); |
|
| 68 | - $this->writeArrayInOutputFormat($input, $output, $result); |
|
| 69 | - if (count($result)>0){ |
|
| 70 | - return 1; |
|
| 71 | - } |
|
| 72 | - } |
|
| 61 | + /** |
|
| 62 | + * {@inheritdoc } |
|
| 63 | + */ |
|
| 64 | + protected function execute(InputInterface $input, OutputInterface $output) { |
|
| 65 | + $appid = $input->getArgument('appid'); |
|
| 66 | + $path = (string)$input->getOption('path'); |
|
| 67 | + $result = $this->checker->verifyAppSignature($appid, $path); |
|
| 68 | + $this->writeArrayInOutputFormat($input, $output, $result); |
|
| 69 | + if (count($result)>0){ |
|
| 70 | + return 1; |
|
| 71 | + } |
|
| 72 | + } |
|
| 73 | 73 | |
| 74 | 74 | } |
@@ -63,10 +63,10 @@ |
||
| 63 | 63 | */ |
| 64 | 64 | protected function execute(InputInterface $input, OutputInterface $output) { |
| 65 | 65 | $appid = $input->getArgument('appid'); |
| 66 | - $path = (string)$input->getOption('path'); |
|
| 66 | + $path = (string) $input->getOption('path'); |
|
| 67 | 67 | $result = $this->checker->verifyAppSignature($appid, $path); |
| 68 | 68 | $this->writeArrayInOutputFormat($input, $output, $result); |
| 69 | - if (count($result)>0){ |
|
| 69 | + if (count($result) > 0) { |
|
| 70 | 70 | return 1; |
| 71 | 71 | } |
| 72 | 72 | } |
@@ -30,44 +30,44 @@ |
||
| 30 | 30 | * @since 13.0.0 |
| 31 | 31 | */ |
| 32 | 32 | class SearchResultType { |
| 33 | - /** @var string */ |
|
| 34 | - protected $label; |
|
| 33 | + /** @var string */ |
|
| 34 | + protected $label; |
|
| 35 | 35 | |
| 36 | - /** |
|
| 37 | - * SearchResultType constructor. |
|
| 38 | - * |
|
| 39 | - * @param string $label |
|
| 40 | - * @since 13.0.0 |
|
| 41 | - */ |
|
| 42 | - public function __construct($label) { |
|
| 43 | - $this->label = $this->getValidatedType($label); |
|
| 44 | - } |
|
| 36 | + /** |
|
| 37 | + * SearchResultType constructor. |
|
| 38 | + * |
|
| 39 | + * @param string $label |
|
| 40 | + * @since 13.0.0 |
|
| 41 | + */ |
|
| 42 | + public function __construct($label) { |
|
| 43 | + $this->label = $this->getValidatedType($label); |
|
| 44 | + } |
|
| 45 | 45 | |
| 46 | - /** |
|
| 47 | - * @return string |
|
| 48 | - * @since 13.0.0 |
|
| 49 | - */ |
|
| 50 | - public function getLabel() { |
|
| 51 | - return $this->label; |
|
| 52 | - } |
|
| 46 | + /** |
|
| 47 | + * @return string |
|
| 48 | + * @since 13.0.0 |
|
| 49 | + */ |
|
| 50 | + public function getLabel() { |
|
| 51 | + return $this->label; |
|
| 52 | + } |
|
| 53 | 53 | |
| 54 | - /** |
|
| 55 | - * @param $type |
|
| 56 | - * @return string |
|
| 57 | - * @throws \InvalidArgumentException |
|
| 58 | - * @since 13.0.0 |
|
| 59 | - */ |
|
| 60 | - protected function getValidatedType($type) { |
|
| 61 | - $type = trim((string)$type); |
|
| 54 | + /** |
|
| 55 | + * @param $type |
|
| 56 | + * @return string |
|
| 57 | + * @throws \InvalidArgumentException |
|
| 58 | + * @since 13.0.0 |
|
| 59 | + */ |
|
| 60 | + protected function getValidatedType($type) { |
|
| 61 | + $type = trim((string)$type); |
|
| 62 | 62 | |
| 63 | - if($type === '') { |
|
| 64 | - throw new \InvalidArgumentException('Type must not be empty'); |
|
| 65 | - } |
|
| 63 | + if($type === '') { |
|
| 64 | + throw new \InvalidArgumentException('Type must not be empty'); |
|
| 65 | + } |
|
| 66 | 66 | |
| 67 | - if($type === 'exact') { |
|
| 68 | - throw new \InvalidArgumentException('Provided type is a reserved word'); |
|
| 69 | - } |
|
| 67 | + if($type === 'exact') { |
|
| 68 | + throw new \InvalidArgumentException('Provided type is a reserved word'); |
|
| 69 | + } |
|
| 70 | 70 | |
| 71 | - return $type; |
|
| 72 | - } |
|
| 71 | + return $type; |
|
| 72 | + } |
|
| 73 | 73 | } |
@@ -58,13 +58,13 @@ |
||
| 58 | 58 | * @since 13.0.0 |
| 59 | 59 | */ |
| 60 | 60 | protected function getValidatedType($type) { |
| 61 | - $type = trim((string)$type); |
|
| 61 | + $type = trim((string) $type); |
|
| 62 | 62 | |
| 63 | - if($type === '') { |
|
| 63 | + if ($type === '') { |
|
| 64 | 64 | throw new \InvalidArgumentException('Type must not be empty'); |
| 65 | 65 | } |
| 66 | 66 | |
| 67 | - if($type === 'exact') { |
|
| 67 | + if ($type === 'exact') { |
|
| 68 | 68 | throw new \InvalidArgumentException('Provided type is a reserved word'); |
| 69 | 69 | } |
| 70 | 70 | |
@@ -31,172 +31,172 @@ |
||
| 31 | 31 | * Helper class for large files on 32-bit platforms. |
| 32 | 32 | */ |
| 33 | 33 | class LargeFileHelper { |
| 34 | - /** |
|
| 35 | - * pow(2, 53) as a base-10 string. |
|
| 36 | - * @var string |
|
| 37 | - */ |
|
| 38 | - const POW_2_53 = '9007199254740992'; |
|
| 34 | + /** |
|
| 35 | + * pow(2, 53) as a base-10 string. |
|
| 36 | + * @var string |
|
| 37 | + */ |
|
| 38 | + const POW_2_53 = '9007199254740992'; |
|
| 39 | 39 | |
| 40 | - /** |
|
| 41 | - * pow(2, 53) - 1 as a base-10 string. |
|
| 42 | - * @var string |
|
| 43 | - */ |
|
| 44 | - const POW_2_53_MINUS_1 = '9007199254740991'; |
|
| 40 | + /** |
|
| 41 | + * pow(2, 53) - 1 as a base-10 string. |
|
| 42 | + * @var string |
|
| 43 | + */ |
|
| 44 | + const POW_2_53_MINUS_1 = '9007199254740991'; |
|
| 45 | 45 | |
| 46 | - /** |
|
| 47 | - * @brief Checks whether our assumptions hold on the PHP platform we are on. |
|
| 48 | - * |
|
| 49 | - * @throws \RunTimeException if our assumptions do not hold on the current |
|
| 50 | - * PHP platform. |
|
| 51 | - */ |
|
| 52 | - public function __construct() { |
|
| 53 | - $pow_2_53 = (float)self::POW_2_53_MINUS_1 + 1.0; |
|
| 54 | - if ($this->formatUnsignedInteger($pow_2_53) !== self::POW_2_53) { |
|
| 55 | - throw new \RuntimeException( |
|
| 56 | - 'This class assumes floats to be double precision or "better".' |
|
| 57 | - ); |
|
| 58 | - } |
|
| 59 | - } |
|
| 46 | + /** |
|
| 47 | + * @brief Checks whether our assumptions hold on the PHP platform we are on. |
|
| 48 | + * |
|
| 49 | + * @throws \RunTimeException if our assumptions do not hold on the current |
|
| 50 | + * PHP platform. |
|
| 51 | + */ |
|
| 52 | + public function __construct() { |
|
| 53 | + $pow_2_53 = (float)self::POW_2_53_MINUS_1 + 1.0; |
|
| 54 | + if ($this->formatUnsignedInteger($pow_2_53) !== self::POW_2_53) { |
|
| 55 | + throw new \RuntimeException( |
|
| 56 | + 'This class assumes floats to be double precision or "better".' |
|
| 57 | + ); |
|
| 58 | + } |
|
| 59 | + } |
|
| 60 | 60 | |
| 61 | - /** |
|
| 62 | - * @brief Formats a signed integer or float as an unsigned integer base-10 |
|
| 63 | - * string. Passed strings will be checked for being base-10. |
|
| 64 | - * |
|
| 65 | - * @param int|float|string $number Number containing unsigned integer data |
|
| 66 | - * |
|
| 67 | - * @throws \UnexpectedValueException if $number is not a float, not an int |
|
| 68 | - * and not a base-10 string. |
|
| 69 | - * |
|
| 70 | - * @return string Unsigned integer base-10 string |
|
| 71 | - */ |
|
| 72 | - public function formatUnsignedInteger($number) { |
|
| 73 | - if (is_float($number)) { |
|
| 74 | - // Undo the effect of the php.ini setting 'precision'. |
|
| 75 | - return number_format($number, 0, '', ''); |
|
| 76 | - } else if (is_string($number) && ctype_digit($number)) { |
|
| 77 | - return $number; |
|
| 78 | - } else if (is_int($number)) { |
|
| 79 | - // Interpret signed integer as unsigned integer. |
|
| 80 | - return sprintf('%u', $number); |
|
| 81 | - } else { |
|
| 82 | - throw new \UnexpectedValueException( |
|
| 83 | - 'Expected int, float or base-10 string' |
|
| 84 | - ); |
|
| 85 | - } |
|
| 86 | - } |
|
| 61 | + /** |
|
| 62 | + * @brief Formats a signed integer or float as an unsigned integer base-10 |
|
| 63 | + * string. Passed strings will be checked for being base-10. |
|
| 64 | + * |
|
| 65 | + * @param int|float|string $number Number containing unsigned integer data |
|
| 66 | + * |
|
| 67 | + * @throws \UnexpectedValueException if $number is not a float, not an int |
|
| 68 | + * and not a base-10 string. |
|
| 69 | + * |
|
| 70 | + * @return string Unsigned integer base-10 string |
|
| 71 | + */ |
|
| 72 | + public function formatUnsignedInteger($number) { |
|
| 73 | + if (is_float($number)) { |
|
| 74 | + // Undo the effect of the php.ini setting 'precision'. |
|
| 75 | + return number_format($number, 0, '', ''); |
|
| 76 | + } else if (is_string($number) && ctype_digit($number)) { |
|
| 77 | + return $number; |
|
| 78 | + } else if (is_int($number)) { |
|
| 79 | + // Interpret signed integer as unsigned integer. |
|
| 80 | + return sprintf('%u', $number); |
|
| 81 | + } else { |
|
| 82 | + throw new \UnexpectedValueException( |
|
| 83 | + 'Expected int, float or base-10 string' |
|
| 84 | + ); |
|
| 85 | + } |
|
| 86 | + } |
|
| 87 | 87 | |
| 88 | - /** |
|
| 89 | - * @brief Tries to get the size of a file via various workarounds that |
|
| 90 | - * even work for large files on 32-bit platforms. |
|
| 91 | - * |
|
| 92 | - * @param string $filename Path to the file. |
|
| 93 | - * |
|
| 94 | - * @return null|int|float Number of bytes as number (float or int) or |
|
| 95 | - * null on failure. |
|
| 96 | - */ |
|
| 97 | - public function getFileSize($filename) { |
|
| 98 | - $fileSize = $this->getFileSizeViaCurl($filename); |
|
| 99 | - if (!is_null($fileSize)) { |
|
| 100 | - return $fileSize; |
|
| 101 | - } |
|
| 102 | - $fileSize = $this->getFileSizeViaExec($filename); |
|
| 103 | - if (!is_null($fileSize)) { |
|
| 104 | - return $fileSize; |
|
| 105 | - } |
|
| 106 | - return $this->getFileSizeNative($filename); |
|
| 107 | - } |
|
| 88 | + /** |
|
| 89 | + * @brief Tries to get the size of a file via various workarounds that |
|
| 90 | + * even work for large files on 32-bit platforms. |
|
| 91 | + * |
|
| 92 | + * @param string $filename Path to the file. |
|
| 93 | + * |
|
| 94 | + * @return null|int|float Number of bytes as number (float or int) or |
|
| 95 | + * null on failure. |
|
| 96 | + */ |
|
| 97 | + public function getFileSize($filename) { |
|
| 98 | + $fileSize = $this->getFileSizeViaCurl($filename); |
|
| 99 | + if (!is_null($fileSize)) { |
|
| 100 | + return $fileSize; |
|
| 101 | + } |
|
| 102 | + $fileSize = $this->getFileSizeViaExec($filename); |
|
| 103 | + if (!is_null($fileSize)) { |
|
| 104 | + return $fileSize; |
|
| 105 | + } |
|
| 106 | + return $this->getFileSizeNative($filename); |
|
| 107 | + } |
|
| 108 | 108 | |
| 109 | - /** |
|
| 110 | - * @brief Tries to get the size of a file via a CURL HEAD request. |
|
| 111 | - * |
|
| 112 | - * @param string $fileName Path to the file. |
|
| 113 | - * |
|
| 114 | - * @return null|int|float Number of bytes as number (float or int) or |
|
| 115 | - * null on failure. |
|
| 116 | - */ |
|
| 117 | - public function getFileSizeViaCurl($fileName) { |
|
| 118 | - if (\OC::$server->getIniWrapper()->getString('open_basedir') === '') { |
|
| 119 | - $encodedFileName = rawurlencode($fileName); |
|
| 120 | - $ch = curl_init("file://$encodedFileName"); |
|
| 121 | - curl_setopt($ch, CURLOPT_NOBODY, true); |
|
| 122 | - curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); |
|
| 123 | - curl_setopt($ch, CURLOPT_HEADER, true); |
|
| 124 | - $data = curl_exec($ch); |
|
| 125 | - curl_close($ch); |
|
| 126 | - if ($data !== false) { |
|
| 127 | - $matches = array(); |
|
| 128 | - preg_match('/Content-Length: (\d+)/', $data, $matches); |
|
| 129 | - if (isset($matches[1])) { |
|
| 130 | - return 0 + $matches[1]; |
|
| 131 | - } |
|
| 132 | - } |
|
| 133 | - } |
|
| 134 | - return null; |
|
| 135 | - } |
|
| 109 | + /** |
|
| 110 | + * @brief Tries to get the size of a file via a CURL HEAD request. |
|
| 111 | + * |
|
| 112 | + * @param string $fileName Path to the file. |
|
| 113 | + * |
|
| 114 | + * @return null|int|float Number of bytes as number (float or int) or |
|
| 115 | + * null on failure. |
|
| 116 | + */ |
|
| 117 | + public function getFileSizeViaCurl($fileName) { |
|
| 118 | + if (\OC::$server->getIniWrapper()->getString('open_basedir') === '') { |
|
| 119 | + $encodedFileName = rawurlencode($fileName); |
|
| 120 | + $ch = curl_init("file://$encodedFileName"); |
|
| 121 | + curl_setopt($ch, CURLOPT_NOBODY, true); |
|
| 122 | + curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); |
|
| 123 | + curl_setopt($ch, CURLOPT_HEADER, true); |
|
| 124 | + $data = curl_exec($ch); |
|
| 125 | + curl_close($ch); |
|
| 126 | + if ($data !== false) { |
|
| 127 | + $matches = array(); |
|
| 128 | + preg_match('/Content-Length: (\d+)/', $data, $matches); |
|
| 129 | + if (isset($matches[1])) { |
|
| 130 | + return 0 + $matches[1]; |
|
| 131 | + } |
|
| 132 | + } |
|
| 133 | + } |
|
| 134 | + return null; |
|
| 135 | + } |
|
| 136 | 136 | |
| 137 | - /** |
|
| 138 | - * @brief Tries to get the size of a file via an exec() call. |
|
| 139 | - * |
|
| 140 | - * @param string $filename Path to the file. |
|
| 141 | - * |
|
| 142 | - * @return null|int|float Number of bytes as number (float or int) or |
|
| 143 | - * null on failure. |
|
| 144 | - */ |
|
| 145 | - public function getFileSizeViaExec($filename) { |
|
| 146 | - if (\OC_Helper::is_function_enabled('exec')) { |
|
| 147 | - $os = strtolower(php_uname('s')); |
|
| 148 | - $arg = escapeshellarg($filename); |
|
| 149 | - $result = null; |
|
| 150 | - if (strpos($os, 'linux') !== false) { |
|
| 151 | - $result = $this->exec("stat -c %s $arg"); |
|
| 152 | - } else if (strpos($os, 'bsd') !== false || strpos($os, 'darwin') !== false) { |
|
| 153 | - $result = $this->exec("stat -f %z $arg"); |
|
| 154 | - } |
|
| 155 | - return $result; |
|
| 156 | - } |
|
| 157 | - return null; |
|
| 158 | - } |
|
| 137 | + /** |
|
| 138 | + * @brief Tries to get the size of a file via an exec() call. |
|
| 139 | + * |
|
| 140 | + * @param string $filename Path to the file. |
|
| 141 | + * |
|
| 142 | + * @return null|int|float Number of bytes as number (float or int) or |
|
| 143 | + * null on failure. |
|
| 144 | + */ |
|
| 145 | + public function getFileSizeViaExec($filename) { |
|
| 146 | + if (\OC_Helper::is_function_enabled('exec')) { |
|
| 147 | + $os = strtolower(php_uname('s')); |
|
| 148 | + $arg = escapeshellarg($filename); |
|
| 149 | + $result = null; |
|
| 150 | + if (strpos($os, 'linux') !== false) { |
|
| 151 | + $result = $this->exec("stat -c %s $arg"); |
|
| 152 | + } else if (strpos($os, 'bsd') !== false || strpos($os, 'darwin') !== false) { |
|
| 153 | + $result = $this->exec("stat -f %z $arg"); |
|
| 154 | + } |
|
| 155 | + return $result; |
|
| 156 | + } |
|
| 157 | + return null; |
|
| 158 | + } |
|
| 159 | 159 | |
| 160 | - /** |
|
| 161 | - * @brief Gets the size of a file via a filesize() call and converts |
|
| 162 | - * negative signed int to positive float. As the result of filesize() |
|
| 163 | - * will wrap around after a file size of 2^32 bytes = 4 GiB, this |
|
| 164 | - * should only be used as a last resort. |
|
| 165 | - * |
|
| 166 | - * @param string $filename Path to the file. |
|
| 167 | - * |
|
| 168 | - * @return int|float Number of bytes as number (float or int). |
|
| 169 | - */ |
|
| 170 | - public function getFileSizeNative($filename) { |
|
| 171 | - $result = filesize($filename); |
|
| 172 | - if ($result < 0) { |
|
| 173 | - // For file sizes between 2 GiB and 4 GiB, filesize() will return a |
|
| 174 | - // negative int, as the PHP data type int is signed. Interpret the |
|
| 175 | - // returned int as an unsigned integer and put it into a float. |
|
| 176 | - return (float) sprintf('%u', $result); |
|
| 177 | - } |
|
| 178 | - return $result; |
|
| 179 | - } |
|
| 160 | + /** |
|
| 161 | + * @brief Gets the size of a file via a filesize() call and converts |
|
| 162 | + * negative signed int to positive float. As the result of filesize() |
|
| 163 | + * will wrap around after a file size of 2^32 bytes = 4 GiB, this |
|
| 164 | + * should only be used as a last resort. |
|
| 165 | + * |
|
| 166 | + * @param string $filename Path to the file. |
|
| 167 | + * |
|
| 168 | + * @return int|float Number of bytes as number (float or int). |
|
| 169 | + */ |
|
| 170 | + public function getFileSizeNative($filename) { |
|
| 171 | + $result = filesize($filename); |
|
| 172 | + if ($result < 0) { |
|
| 173 | + // For file sizes between 2 GiB and 4 GiB, filesize() will return a |
|
| 174 | + // negative int, as the PHP data type int is signed. Interpret the |
|
| 175 | + // returned int as an unsigned integer and put it into a float. |
|
| 176 | + return (float) sprintf('%u', $result); |
|
| 177 | + } |
|
| 178 | + return $result; |
|
| 179 | + } |
|
| 180 | 180 | |
| 181 | - /** |
|
| 182 | - * Returns the current mtime for $fullPath |
|
| 183 | - * |
|
| 184 | - * @param string $fullPath |
|
| 185 | - * @return int |
|
| 186 | - */ |
|
| 187 | - public function getFileMtime($fullPath) { |
|
| 188 | - if (\OC_Helper::is_function_enabled('exec')) { |
|
| 189 | - $os = strtolower(php_uname('s')); |
|
| 190 | - if (strpos($os, 'linux') !== false) { |
|
| 191 | - return $this->exec('stat -c %Y ' . escapeshellarg($fullPath)); |
|
| 192 | - } |
|
| 193 | - } |
|
| 181 | + /** |
|
| 182 | + * Returns the current mtime for $fullPath |
|
| 183 | + * |
|
| 184 | + * @param string $fullPath |
|
| 185 | + * @return int |
|
| 186 | + */ |
|
| 187 | + public function getFileMtime($fullPath) { |
|
| 188 | + if (\OC_Helper::is_function_enabled('exec')) { |
|
| 189 | + $os = strtolower(php_uname('s')); |
|
| 190 | + if (strpos($os, 'linux') !== false) { |
|
| 191 | + return $this->exec('stat -c %Y ' . escapeshellarg($fullPath)); |
|
| 192 | + } |
|
| 193 | + } |
|
| 194 | 194 | |
| 195 | - return filemtime($fullPath); |
|
| 196 | - } |
|
| 195 | + return filemtime($fullPath); |
|
| 196 | + } |
|
| 197 | 197 | |
| 198 | - protected function exec($cmd) { |
|
| 199 | - $result = trim(exec($cmd)); |
|
| 200 | - return ctype_digit($result) ? 0 + $result : null; |
|
| 201 | - } |
|
| 198 | + protected function exec($cmd) { |
|
| 199 | + $result = trim(exec($cmd)); |
|
| 200 | + return ctype_digit($result) ? 0 + $result : null; |
|
| 201 | + } |
|
| 202 | 202 | } |
@@ -50,7 +50,7 @@ discard block |
||
| 50 | 50 | * PHP platform. |
| 51 | 51 | */ |
| 52 | 52 | public function __construct() { |
| 53 | - $pow_2_53 = (float)self::POW_2_53_MINUS_1 + 1.0; |
|
| 53 | + $pow_2_53 = (float) self::POW_2_53_MINUS_1 + 1.0; |
|
| 54 | 54 | if ($this->formatUnsignedInteger($pow_2_53) !== self::POW_2_53) { |
| 55 | 55 | throw new \RuntimeException( |
| 56 | 56 | 'This class assumes floats to be double precision or "better".' |
@@ -188,7 +188,7 @@ discard block |
||
| 188 | 188 | if (\OC_Helper::is_function_enabled('exec')) { |
| 189 | 189 | $os = strtolower(php_uname('s')); |
| 190 | 190 | if (strpos($os, 'linux') !== false) { |
| 191 | - return $this->exec('stat -c %Y ' . escapeshellarg($fullPath)); |
|
| 191 | + return $this->exec('stat -c %Y '.escapeshellarg($fullPath)); |
|
| 192 | 192 | } |
| 193 | 193 | } |
| 194 | 194 | |
@@ -28,38 +28,38 @@ |
||
| 28 | 28 | use OCP\ILogger; |
| 29 | 29 | |
| 30 | 30 | class CachingRouter extends Router { |
| 31 | - /** |
|
| 32 | - * @var \OCP\ICache |
|
| 33 | - */ |
|
| 34 | - protected $cache; |
|
| 31 | + /** |
|
| 32 | + * @var \OCP\ICache |
|
| 33 | + */ |
|
| 34 | + protected $cache; |
|
| 35 | 35 | |
| 36 | - /** |
|
| 37 | - * @param \OCP\ICache $cache |
|
| 38 | - * @param ILogger $logger |
|
| 39 | - */ |
|
| 40 | - public function __construct($cache, ILogger $logger) { |
|
| 41 | - $this->cache = $cache; |
|
| 42 | - parent::__construct($logger); |
|
| 43 | - } |
|
| 36 | + /** |
|
| 37 | + * @param \OCP\ICache $cache |
|
| 38 | + * @param ILogger $logger |
|
| 39 | + */ |
|
| 40 | + public function __construct($cache, ILogger $logger) { |
|
| 41 | + $this->cache = $cache; |
|
| 42 | + parent::__construct($logger); |
|
| 43 | + } |
|
| 44 | 44 | |
| 45 | - /** |
|
| 46 | - * Generate url based on $name and $parameters |
|
| 47 | - * |
|
| 48 | - * @param string $name Name of the route to use. |
|
| 49 | - * @param array $parameters Parameters for the route |
|
| 50 | - * @param bool $absolute |
|
| 51 | - * @return string |
|
| 52 | - */ |
|
| 53 | - public function generate($name, $parameters = array(), $absolute = false) { |
|
| 54 | - asort($parameters); |
|
| 55 | - $key = $this->context->getHost() . '#' . $this->context->getBaseUrl() . $name . sha1(json_encode($parameters)) . (int)$absolute; |
|
| 56 | - $cachedKey = $this->cache->get($key); |
|
| 57 | - if ($cachedKey) { |
|
| 58 | - return $cachedKey; |
|
| 59 | - } else { |
|
| 60 | - $url = parent::generate($name, $parameters, $absolute); |
|
| 61 | - $this->cache->set($key, $url, 3600); |
|
| 62 | - return $url; |
|
| 63 | - } |
|
| 64 | - } |
|
| 45 | + /** |
|
| 46 | + * Generate url based on $name and $parameters |
|
| 47 | + * |
|
| 48 | + * @param string $name Name of the route to use. |
|
| 49 | + * @param array $parameters Parameters for the route |
|
| 50 | + * @param bool $absolute |
|
| 51 | + * @return string |
|
| 52 | + */ |
|
| 53 | + public function generate($name, $parameters = array(), $absolute = false) { |
|
| 54 | + asort($parameters); |
|
| 55 | + $key = $this->context->getHost() . '#' . $this->context->getBaseUrl() . $name . sha1(json_encode($parameters)) . (int)$absolute; |
|
| 56 | + $cachedKey = $this->cache->get($key); |
|
| 57 | + if ($cachedKey) { |
|
| 58 | + return $cachedKey; |
|
| 59 | + } else { |
|
| 60 | + $url = parent::generate($name, $parameters, $absolute); |
|
| 61 | + $this->cache->set($key, $url, 3600); |
|
| 62 | + return $url; |
|
| 63 | + } |
|
| 64 | + } |
|
| 65 | 65 | } |
@@ -52,7 +52,7 @@ |
||
| 52 | 52 | */ |
| 53 | 53 | public function generate($name, $parameters = array(), $absolute = false) { |
| 54 | 54 | asort($parameters); |
| 55 | - $key = $this->context->getHost() . '#' . $this->context->getBaseUrl() . $name . sha1(json_encode($parameters)) . (int)$absolute; |
|
| 55 | + $key = $this->context->getHost().'#'.$this->context->getBaseUrl().$name.sha1(json_encode($parameters)).(int) $absolute; |
|
| 56 | 56 | $cachedKey = $this->cache->get($key); |
| 57 | 57 | if ($cachedKey) { |
| 58 | 58 | return $cachedKey; |
@@ -39,240 +39,240 @@ |
||
| 39 | 39 | |
| 40 | 40 | class JSConfigHelper { |
| 41 | 41 | |
| 42 | - /** @var IL10N */ |
|
| 43 | - private $l; |
|
| 42 | + /** @var IL10N */ |
|
| 43 | + private $l; |
|
| 44 | 44 | |
| 45 | - /** @var Defaults */ |
|
| 46 | - private $defaults; |
|
| 45 | + /** @var Defaults */ |
|
| 46 | + private $defaults; |
|
| 47 | 47 | |
| 48 | - /** @var IAppManager */ |
|
| 49 | - private $appManager; |
|
| 48 | + /** @var IAppManager */ |
|
| 49 | + private $appManager; |
|
| 50 | 50 | |
| 51 | - /** @var ISession */ |
|
| 52 | - private $session; |
|
| 51 | + /** @var ISession */ |
|
| 52 | + private $session; |
|
| 53 | 53 | |
| 54 | - /** @var IUser|null */ |
|
| 55 | - private $currentUser; |
|
| 54 | + /** @var IUser|null */ |
|
| 55 | + private $currentUser; |
|
| 56 | 56 | |
| 57 | - /** @var IConfig */ |
|
| 58 | - private $config; |
|
| 57 | + /** @var IConfig */ |
|
| 58 | + private $config; |
|
| 59 | 59 | |
| 60 | - /** @var IGroupManager */ |
|
| 61 | - private $groupManager; |
|
| 60 | + /** @var IGroupManager */ |
|
| 61 | + private $groupManager; |
|
| 62 | 62 | |
| 63 | - /** @var IniGetWrapper */ |
|
| 64 | - private $iniWrapper; |
|
| 63 | + /** @var IniGetWrapper */ |
|
| 64 | + private $iniWrapper; |
|
| 65 | 65 | |
| 66 | - /** @var IURLGenerator */ |
|
| 67 | - private $urlGenerator; |
|
| 66 | + /** @var IURLGenerator */ |
|
| 67 | + private $urlGenerator; |
|
| 68 | 68 | |
| 69 | - /** |
|
| 70 | - * @param IL10N $l |
|
| 71 | - * @param Defaults $defaults |
|
| 72 | - * @param IAppManager $appManager |
|
| 73 | - * @param ISession $session |
|
| 74 | - * @param IUser|null $currentUser |
|
| 75 | - * @param IConfig $config |
|
| 76 | - * @param IGroupManager $groupManager |
|
| 77 | - * @param IniGetWrapper $iniWrapper |
|
| 78 | - * @param IURLGenerator $urlGenerator |
|
| 79 | - */ |
|
| 80 | - public function __construct(IL10N $l, |
|
| 81 | - Defaults $defaults, |
|
| 82 | - IAppManager $appManager, |
|
| 83 | - ISession $session, |
|
| 84 | - $currentUser, |
|
| 85 | - IConfig $config, |
|
| 86 | - IGroupManager $groupManager, |
|
| 87 | - IniGetWrapper $iniWrapper, |
|
| 88 | - IURLGenerator $urlGenerator) { |
|
| 89 | - $this->l = $l; |
|
| 90 | - $this->defaults = $defaults; |
|
| 91 | - $this->appManager = $appManager; |
|
| 92 | - $this->session = $session; |
|
| 93 | - $this->currentUser = $currentUser; |
|
| 94 | - $this->config = $config; |
|
| 95 | - $this->groupManager = $groupManager; |
|
| 96 | - $this->iniWrapper = $iniWrapper; |
|
| 97 | - $this->urlGenerator = $urlGenerator; |
|
| 98 | - } |
|
| 69 | + /** |
|
| 70 | + * @param IL10N $l |
|
| 71 | + * @param Defaults $defaults |
|
| 72 | + * @param IAppManager $appManager |
|
| 73 | + * @param ISession $session |
|
| 74 | + * @param IUser|null $currentUser |
|
| 75 | + * @param IConfig $config |
|
| 76 | + * @param IGroupManager $groupManager |
|
| 77 | + * @param IniGetWrapper $iniWrapper |
|
| 78 | + * @param IURLGenerator $urlGenerator |
|
| 79 | + */ |
|
| 80 | + public function __construct(IL10N $l, |
|
| 81 | + Defaults $defaults, |
|
| 82 | + IAppManager $appManager, |
|
| 83 | + ISession $session, |
|
| 84 | + $currentUser, |
|
| 85 | + IConfig $config, |
|
| 86 | + IGroupManager $groupManager, |
|
| 87 | + IniGetWrapper $iniWrapper, |
|
| 88 | + IURLGenerator $urlGenerator) { |
|
| 89 | + $this->l = $l; |
|
| 90 | + $this->defaults = $defaults; |
|
| 91 | + $this->appManager = $appManager; |
|
| 92 | + $this->session = $session; |
|
| 93 | + $this->currentUser = $currentUser; |
|
| 94 | + $this->config = $config; |
|
| 95 | + $this->groupManager = $groupManager; |
|
| 96 | + $this->iniWrapper = $iniWrapper; |
|
| 97 | + $this->urlGenerator = $urlGenerator; |
|
| 98 | + } |
|
| 99 | 99 | |
| 100 | - public function getConfig() { |
|
| 100 | + public function getConfig() { |
|
| 101 | 101 | |
| 102 | - if ($this->currentUser !== null) { |
|
| 103 | - $uid = $this->currentUser->getUID(); |
|
| 104 | - $userBackend = $this->currentUser->getBackendClassName(); |
|
| 105 | - } else { |
|
| 106 | - $uid = null; |
|
| 107 | - $userBackend = ''; |
|
| 108 | - } |
|
| 102 | + if ($this->currentUser !== null) { |
|
| 103 | + $uid = $this->currentUser->getUID(); |
|
| 104 | + $userBackend = $this->currentUser->getBackendClassName(); |
|
| 105 | + } else { |
|
| 106 | + $uid = null; |
|
| 107 | + $userBackend = ''; |
|
| 108 | + } |
|
| 109 | 109 | |
| 110 | - // Get the config |
|
| 111 | - $apps_paths = []; |
|
| 110 | + // Get the config |
|
| 111 | + $apps_paths = []; |
|
| 112 | 112 | |
| 113 | - if ($this->currentUser === null) { |
|
| 114 | - $apps = $this->appManager->getInstalledApps(); |
|
| 115 | - } else { |
|
| 116 | - $apps = $this->appManager->getEnabledAppsForUser($this->currentUser); |
|
| 117 | - } |
|
| 113 | + if ($this->currentUser === null) { |
|
| 114 | + $apps = $this->appManager->getInstalledApps(); |
|
| 115 | + } else { |
|
| 116 | + $apps = $this->appManager->getEnabledAppsForUser($this->currentUser); |
|
| 117 | + } |
|
| 118 | 118 | |
| 119 | - foreach($apps as $app) { |
|
| 120 | - $apps_paths[$app] = \OC_App::getAppWebPath($app); |
|
| 121 | - } |
|
| 119 | + foreach($apps as $app) { |
|
| 120 | + $apps_paths[$app] = \OC_App::getAppWebPath($app); |
|
| 121 | + } |
|
| 122 | 122 | |
| 123 | 123 | |
| 124 | - $enableLinkPasswordByDefault = $this->config->getAppValue('core', 'shareapi_enable_link_password_by_default', 'no'); |
|
| 125 | - $enableLinkPasswordByDefault = ($enableLinkPasswordByDefault === 'yes') ? true : false; |
|
| 126 | - $defaultExpireDateEnabled = $this->config->getAppValue('core', 'shareapi_default_expire_date', 'no') === 'yes'; |
|
| 127 | - $defaultExpireDate = $enforceDefaultExpireDate = null; |
|
| 128 | - if ($defaultExpireDateEnabled) { |
|
| 129 | - $defaultExpireDate = (int) $this->config->getAppValue('core', 'shareapi_expire_after_n_days', '7'); |
|
| 130 | - $enforceDefaultExpireDate = $this->config->getAppValue('core', 'shareapi_enforce_expire_date', 'no') === 'yes'; |
|
| 131 | - } |
|
| 132 | - $outgoingServer2serverShareEnabled = $this->config->getAppValue('files_sharing', 'outgoing_server2server_share_enabled', 'yes') === 'yes'; |
|
| 124 | + $enableLinkPasswordByDefault = $this->config->getAppValue('core', 'shareapi_enable_link_password_by_default', 'no'); |
|
| 125 | + $enableLinkPasswordByDefault = ($enableLinkPasswordByDefault === 'yes') ? true : false; |
|
| 126 | + $defaultExpireDateEnabled = $this->config->getAppValue('core', 'shareapi_default_expire_date', 'no') === 'yes'; |
|
| 127 | + $defaultExpireDate = $enforceDefaultExpireDate = null; |
|
| 128 | + if ($defaultExpireDateEnabled) { |
|
| 129 | + $defaultExpireDate = (int) $this->config->getAppValue('core', 'shareapi_expire_after_n_days', '7'); |
|
| 130 | + $enforceDefaultExpireDate = $this->config->getAppValue('core', 'shareapi_enforce_expire_date', 'no') === 'yes'; |
|
| 131 | + } |
|
| 132 | + $outgoingServer2serverShareEnabled = $this->config->getAppValue('files_sharing', 'outgoing_server2server_share_enabled', 'yes') === 'yes'; |
|
| 133 | 133 | |
| 134 | - $countOfDataLocation = 0; |
|
| 135 | - $dataLocation = str_replace(\OC::$SERVERROOT .'/', '', $this->config->getSystemValue('datadirectory', ''), $countOfDataLocation); |
|
| 136 | - if($countOfDataLocation !== 1 || !$this->groupManager->isAdmin($uid)) { |
|
| 137 | - $dataLocation = false; |
|
| 138 | - } |
|
| 134 | + $countOfDataLocation = 0; |
|
| 135 | + $dataLocation = str_replace(\OC::$SERVERROOT .'/', '', $this->config->getSystemValue('datadirectory', ''), $countOfDataLocation); |
|
| 136 | + if($countOfDataLocation !== 1 || !$this->groupManager->isAdmin($uid)) { |
|
| 137 | + $dataLocation = false; |
|
| 138 | + } |
|
| 139 | 139 | |
| 140 | - if ($this->currentUser instanceof IUser) { |
|
| 141 | - $lastConfirmTimestamp = $this->session->get('last-password-confirm'); |
|
| 142 | - if (!is_int($lastConfirmTimestamp)) { |
|
| 143 | - $lastConfirmTimestamp = 0; |
|
| 144 | - } |
|
| 145 | - } else { |
|
| 146 | - $lastConfirmTimestamp = 0; |
|
| 147 | - } |
|
| 140 | + if ($this->currentUser instanceof IUser) { |
|
| 141 | + $lastConfirmTimestamp = $this->session->get('last-password-confirm'); |
|
| 142 | + if (!is_int($lastConfirmTimestamp)) { |
|
| 143 | + $lastConfirmTimestamp = 0; |
|
| 144 | + } |
|
| 145 | + } else { |
|
| 146 | + $lastConfirmTimestamp = 0; |
|
| 147 | + } |
|
| 148 | 148 | |
| 149 | - $array = [ |
|
| 150 | - "oc_debug" => $this->config->getSystemValue('debug', false) ? 'true' : 'false', |
|
| 151 | - "oc_isadmin" => $this->groupManager->isAdmin($uid) ? 'true' : 'false', |
|
| 152 | - "backendAllowsPasswordConfirmation" => $userBackend === 'user_saml'? 'false' : 'true', |
|
| 153 | - "oc_dataURL" => is_string($dataLocation) ? "\"".$dataLocation."\"" : 'false', |
|
| 154 | - "oc_webroot" => "\"".\OC::$WEBROOT."\"", |
|
| 155 | - "oc_appswebroots" => str_replace('\\/', '/', json_encode($apps_paths)), // Ugly unescape slashes waiting for better solution |
|
| 156 | - "datepickerFormatDate" => json_encode($this->l->l('jsdate', null)), |
|
| 157 | - 'nc_lastLogin' => $lastConfirmTimestamp, |
|
| 158 | - 'nc_pageLoad' => time(), |
|
| 159 | - "dayNames" => json_encode([ |
|
| 160 | - (string)$this->l->t('Sunday'), |
|
| 161 | - (string)$this->l->t('Monday'), |
|
| 162 | - (string)$this->l->t('Tuesday'), |
|
| 163 | - (string)$this->l->t('Wednesday'), |
|
| 164 | - (string)$this->l->t('Thursday'), |
|
| 165 | - (string)$this->l->t('Friday'), |
|
| 166 | - (string)$this->l->t('Saturday') |
|
| 167 | - ]), |
|
| 168 | - "dayNamesShort" => json_encode([ |
|
| 169 | - (string)$this->l->t('Sun.'), |
|
| 170 | - (string)$this->l->t('Mon.'), |
|
| 171 | - (string)$this->l->t('Tue.'), |
|
| 172 | - (string)$this->l->t('Wed.'), |
|
| 173 | - (string)$this->l->t('Thu.'), |
|
| 174 | - (string)$this->l->t('Fri.'), |
|
| 175 | - (string)$this->l->t('Sat.') |
|
| 176 | - ]), |
|
| 177 | - "dayNamesMin" => json_encode([ |
|
| 178 | - (string)$this->l->t('Su'), |
|
| 179 | - (string)$this->l->t('Mo'), |
|
| 180 | - (string)$this->l->t('Tu'), |
|
| 181 | - (string)$this->l->t('We'), |
|
| 182 | - (string)$this->l->t('Th'), |
|
| 183 | - (string)$this->l->t('Fr'), |
|
| 184 | - (string)$this->l->t('Sa') |
|
| 185 | - ]), |
|
| 186 | - "monthNames" => json_encode([ |
|
| 187 | - (string)$this->l->t('January'), |
|
| 188 | - (string)$this->l->t('February'), |
|
| 189 | - (string)$this->l->t('March'), |
|
| 190 | - (string)$this->l->t('April'), |
|
| 191 | - (string)$this->l->t('May'), |
|
| 192 | - (string)$this->l->t('June'), |
|
| 193 | - (string)$this->l->t('July'), |
|
| 194 | - (string)$this->l->t('August'), |
|
| 195 | - (string)$this->l->t('September'), |
|
| 196 | - (string)$this->l->t('October'), |
|
| 197 | - (string)$this->l->t('November'), |
|
| 198 | - (string)$this->l->t('December') |
|
| 199 | - ]), |
|
| 200 | - "monthNamesShort" => json_encode([ |
|
| 201 | - (string)$this->l->t('Jan.'), |
|
| 202 | - (string)$this->l->t('Feb.'), |
|
| 203 | - (string)$this->l->t('Mar.'), |
|
| 204 | - (string)$this->l->t('Apr.'), |
|
| 205 | - (string)$this->l->t('May.'), |
|
| 206 | - (string)$this->l->t('Jun.'), |
|
| 207 | - (string)$this->l->t('Jul.'), |
|
| 208 | - (string)$this->l->t('Aug.'), |
|
| 209 | - (string)$this->l->t('Sep.'), |
|
| 210 | - (string)$this->l->t('Oct.'), |
|
| 211 | - (string)$this->l->t('Nov.'), |
|
| 212 | - (string)$this->l->t('Dec.') |
|
| 213 | - ]), |
|
| 214 | - "firstDay" => json_encode($this->l->l('firstday', null)) , |
|
| 215 | - "oc_config" => json_encode([ |
|
| 216 | - 'session_lifetime' => min($this->config->getSystemValue('session_lifetime', $this->iniWrapper->getNumeric('session.gc_maxlifetime')), $this->iniWrapper->getNumeric('session.gc_maxlifetime')), |
|
| 217 | - 'session_keepalive' => $this->config->getSystemValue('session_keepalive', true), |
|
| 218 | - 'version' => implode('.', \OCP\Util::getVersion()), |
|
| 219 | - 'versionstring' => \OC_Util::getVersionString(), |
|
| 220 | - 'enable_avatars' => true, // here for legacy reasons - to not crash existing code that relies on this value |
|
| 221 | - 'lost_password_link'=> $this->config->getSystemValue('lost_password_link', null), |
|
| 222 | - 'modRewriteWorking' => ($this->config->getSystemValue('htaccess.IgnoreFrontController', false) === true || getenv('front_controller_active') === 'true'), |
|
| 223 | - 'sharing.maxAutocompleteResults' => (int)$this->config->getSystemValue('sharing.maxAutocompleteResults', 0), |
|
| 224 | - 'sharing.minSearchStringLength' => (int)$this->config->getSystemValue('sharing.minSearchStringLength', 0), |
|
| 225 | - 'blacklist_files_regex' => \OCP\Files\FileInfo::BLACKLIST_FILES_REGEX, |
|
| 226 | - ]), |
|
| 227 | - "oc_appconfig" => json_encode([ |
|
| 228 | - 'core' => [ |
|
| 229 | - 'defaultExpireDateEnabled' => $defaultExpireDateEnabled, |
|
| 230 | - 'defaultExpireDate' => $defaultExpireDate, |
|
| 231 | - 'defaultExpireDateEnforced' => $enforceDefaultExpireDate, |
|
| 232 | - 'enforcePasswordForPublicLink' => \OCP\Util::isPublicLinkPasswordRequired(), |
|
| 233 | - 'enableLinkPasswordByDefault' => $enableLinkPasswordByDefault, |
|
| 234 | - 'sharingDisabledForUser' => \OCP\Util::isSharingDisabledForUser(), |
|
| 235 | - 'resharingAllowed' => \OC\Share\Share::isResharingAllowed(), |
|
| 236 | - 'remoteShareAllowed' => $outgoingServer2serverShareEnabled, |
|
| 237 | - 'federatedCloudShareDoc' => $this->urlGenerator->linkToDocs('user-sharing-federated'), |
|
| 238 | - 'allowGroupSharing' => \OC::$server->getShareManager()->allowGroupSharing() |
|
| 239 | - ] |
|
| 240 | - ]), |
|
| 241 | - "oc_defaults" => json_encode([ |
|
| 242 | - 'entity' => $this->defaults->getEntity(), |
|
| 243 | - 'name' => $this->defaults->getName(), |
|
| 244 | - 'title' => $this->defaults->getTitle(), |
|
| 245 | - 'baseUrl' => $this->defaults->getBaseUrl(), |
|
| 246 | - 'syncClientUrl' => $this->defaults->getSyncClientUrl(), |
|
| 247 | - 'docBaseUrl' => $this->defaults->getDocBaseUrl(), |
|
| 248 | - 'docPlaceholderUrl' => $this->defaults->buildDocLinkToKey('PLACEHOLDER'), |
|
| 249 | - 'slogan' => $this->defaults->getSlogan(), |
|
| 250 | - 'logoClaim' => '', |
|
| 251 | - 'shortFooter' => $this->defaults->getShortFooter(), |
|
| 252 | - 'longFooter' => $this->defaults->getLongFooter(), |
|
| 253 | - 'folder' => \OC_Util::getTheme(), |
|
| 254 | - ]), |
|
| 255 | - ]; |
|
| 149 | + $array = [ |
|
| 150 | + "oc_debug" => $this->config->getSystemValue('debug', false) ? 'true' : 'false', |
|
| 151 | + "oc_isadmin" => $this->groupManager->isAdmin($uid) ? 'true' : 'false', |
|
| 152 | + "backendAllowsPasswordConfirmation" => $userBackend === 'user_saml'? 'false' : 'true', |
|
| 153 | + "oc_dataURL" => is_string($dataLocation) ? "\"".$dataLocation."\"" : 'false', |
|
| 154 | + "oc_webroot" => "\"".\OC::$WEBROOT."\"", |
|
| 155 | + "oc_appswebroots" => str_replace('\\/', '/', json_encode($apps_paths)), // Ugly unescape slashes waiting for better solution |
|
| 156 | + "datepickerFormatDate" => json_encode($this->l->l('jsdate', null)), |
|
| 157 | + 'nc_lastLogin' => $lastConfirmTimestamp, |
|
| 158 | + 'nc_pageLoad' => time(), |
|
| 159 | + "dayNames" => json_encode([ |
|
| 160 | + (string)$this->l->t('Sunday'), |
|
| 161 | + (string)$this->l->t('Monday'), |
|
| 162 | + (string)$this->l->t('Tuesday'), |
|
| 163 | + (string)$this->l->t('Wednesday'), |
|
| 164 | + (string)$this->l->t('Thursday'), |
|
| 165 | + (string)$this->l->t('Friday'), |
|
| 166 | + (string)$this->l->t('Saturday') |
|
| 167 | + ]), |
|
| 168 | + "dayNamesShort" => json_encode([ |
|
| 169 | + (string)$this->l->t('Sun.'), |
|
| 170 | + (string)$this->l->t('Mon.'), |
|
| 171 | + (string)$this->l->t('Tue.'), |
|
| 172 | + (string)$this->l->t('Wed.'), |
|
| 173 | + (string)$this->l->t('Thu.'), |
|
| 174 | + (string)$this->l->t('Fri.'), |
|
| 175 | + (string)$this->l->t('Sat.') |
|
| 176 | + ]), |
|
| 177 | + "dayNamesMin" => json_encode([ |
|
| 178 | + (string)$this->l->t('Su'), |
|
| 179 | + (string)$this->l->t('Mo'), |
|
| 180 | + (string)$this->l->t('Tu'), |
|
| 181 | + (string)$this->l->t('We'), |
|
| 182 | + (string)$this->l->t('Th'), |
|
| 183 | + (string)$this->l->t('Fr'), |
|
| 184 | + (string)$this->l->t('Sa') |
|
| 185 | + ]), |
|
| 186 | + "monthNames" => json_encode([ |
|
| 187 | + (string)$this->l->t('January'), |
|
| 188 | + (string)$this->l->t('February'), |
|
| 189 | + (string)$this->l->t('March'), |
|
| 190 | + (string)$this->l->t('April'), |
|
| 191 | + (string)$this->l->t('May'), |
|
| 192 | + (string)$this->l->t('June'), |
|
| 193 | + (string)$this->l->t('July'), |
|
| 194 | + (string)$this->l->t('August'), |
|
| 195 | + (string)$this->l->t('September'), |
|
| 196 | + (string)$this->l->t('October'), |
|
| 197 | + (string)$this->l->t('November'), |
|
| 198 | + (string)$this->l->t('December') |
|
| 199 | + ]), |
|
| 200 | + "monthNamesShort" => json_encode([ |
|
| 201 | + (string)$this->l->t('Jan.'), |
|
| 202 | + (string)$this->l->t('Feb.'), |
|
| 203 | + (string)$this->l->t('Mar.'), |
|
| 204 | + (string)$this->l->t('Apr.'), |
|
| 205 | + (string)$this->l->t('May.'), |
|
| 206 | + (string)$this->l->t('Jun.'), |
|
| 207 | + (string)$this->l->t('Jul.'), |
|
| 208 | + (string)$this->l->t('Aug.'), |
|
| 209 | + (string)$this->l->t('Sep.'), |
|
| 210 | + (string)$this->l->t('Oct.'), |
|
| 211 | + (string)$this->l->t('Nov.'), |
|
| 212 | + (string)$this->l->t('Dec.') |
|
| 213 | + ]), |
|
| 214 | + "firstDay" => json_encode($this->l->l('firstday', null)) , |
|
| 215 | + "oc_config" => json_encode([ |
|
| 216 | + 'session_lifetime' => min($this->config->getSystemValue('session_lifetime', $this->iniWrapper->getNumeric('session.gc_maxlifetime')), $this->iniWrapper->getNumeric('session.gc_maxlifetime')), |
|
| 217 | + 'session_keepalive' => $this->config->getSystemValue('session_keepalive', true), |
|
| 218 | + 'version' => implode('.', \OCP\Util::getVersion()), |
|
| 219 | + 'versionstring' => \OC_Util::getVersionString(), |
|
| 220 | + 'enable_avatars' => true, // here for legacy reasons - to not crash existing code that relies on this value |
|
| 221 | + 'lost_password_link'=> $this->config->getSystemValue('lost_password_link', null), |
|
| 222 | + 'modRewriteWorking' => ($this->config->getSystemValue('htaccess.IgnoreFrontController', false) === true || getenv('front_controller_active') === 'true'), |
|
| 223 | + 'sharing.maxAutocompleteResults' => (int)$this->config->getSystemValue('sharing.maxAutocompleteResults', 0), |
|
| 224 | + 'sharing.minSearchStringLength' => (int)$this->config->getSystemValue('sharing.minSearchStringLength', 0), |
|
| 225 | + 'blacklist_files_regex' => \OCP\Files\FileInfo::BLACKLIST_FILES_REGEX, |
|
| 226 | + ]), |
|
| 227 | + "oc_appconfig" => json_encode([ |
|
| 228 | + 'core' => [ |
|
| 229 | + 'defaultExpireDateEnabled' => $defaultExpireDateEnabled, |
|
| 230 | + 'defaultExpireDate' => $defaultExpireDate, |
|
| 231 | + 'defaultExpireDateEnforced' => $enforceDefaultExpireDate, |
|
| 232 | + 'enforcePasswordForPublicLink' => \OCP\Util::isPublicLinkPasswordRequired(), |
|
| 233 | + 'enableLinkPasswordByDefault' => $enableLinkPasswordByDefault, |
|
| 234 | + 'sharingDisabledForUser' => \OCP\Util::isSharingDisabledForUser(), |
|
| 235 | + 'resharingAllowed' => \OC\Share\Share::isResharingAllowed(), |
|
| 236 | + 'remoteShareAllowed' => $outgoingServer2serverShareEnabled, |
|
| 237 | + 'federatedCloudShareDoc' => $this->urlGenerator->linkToDocs('user-sharing-federated'), |
|
| 238 | + 'allowGroupSharing' => \OC::$server->getShareManager()->allowGroupSharing() |
|
| 239 | + ] |
|
| 240 | + ]), |
|
| 241 | + "oc_defaults" => json_encode([ |
|
| 242 | + 'entity' => $this->defaults->getEntity(), |
|
| 243 | + 'name' => $this->defaults->getName(), |
|
| 244 | + 'title' => $this->defaults->getTitle(), |
|
| 245 | + 'baseUrl' => $this->defaults->getBaseUrl(), |
|
| 246 | + 'syncClientUrl' => $this->defaults->getSyncClientUrl(), |
|
| 247 | + 'docBaseUrl' => $this->defaults->getDocBaseUrl(), |
|
| 248 | + 'docPlaceholderUrl' => $this->defaults->buildDocLinkToKey('PLACEHOLDER'), |
|
| 249 | + 'slogan' => $this->defaults->getSlogan(), |
|
| 250 | + 'logoClaim' => '', |
|
| 251 | + 'shortFooter' => $this->defaults->getShortFooter(), |
|
| 252 | + 'longFooter' => $this->defaults->getLongFooter(), |
|
| 253 | + 'folder' => \OC_Util::getTheme(), |
|
| 254 | + ]), |
|
| 255 | + ]; |
|
| 256 | 256 | |
| 257 | - if ($this->currentUser !== null) { |
|
| 258 | - $array['oc_userconfig'] = json_encode([ |
|
| 259 | - 'avatar' => [ |
|
| 260 | - 'version' => (int)$this->config->getUserValue($uid, 'avatar', 'version', 0), |
|
| 261 | - 'generated' => $this->config->getUserValue($uid, 'avatar', 'generated', 'true') === 'true', |
|
| 262 | - ] |
|
| 263 | - ]); |
|
| 264 | - } |
|
| 257 | + if ($this->currentUser !== null) { |
|
| 258 | + $array['oc_userconfig'] = json_encode([ |
|
| 259 | + 'avatar' => [ |
|
| 260 | + 'version' => (int)$this->config->getUserValue($uid, 'avatar', 'version', 0), |
|
| 261 | + 'generated' => $this->config->getUserValue($uid, 'avatar', 'generated', 'true') === 'true', |
|
| 262 | + ] |
|
| 263 | + ]); |
|
| 264 | + } |
|
| 265 | 265 | |
| 266 | - // Allow hooks to modify the output values |
|
| 267 | - \OC_Hook::emit('\OCP\Config', 'js', array('array' => &$array)); |
|
| 266 | + // Allow hooks to modify the output values |
|
| 267 | + \OC_Hook::emit('\OCP\Config', 'js', array('array' => &$array)); |
|
| 268 | 268 | |
| 269 | - $result = ''; |
|
| 269 | + $result = ''; |
|
| 270 | 270 | |
| 271 | - // Echo it |
|
| 272 | - foreach ($array as $setting => $value) { |
|
| 273 | - $result .= 'var '. $setting . '='. $value . ';' . PHP_EOL; |
|
| 274 | - } |
|
| 271 | + // Echo it |
|
| 272 | + foreach ($array as $setting => $value) { |
|
| 273 | + $result .= 'var '. $setting . '='. $value . ';' . PHP_EOL; |
|
| 274 | + } |
|
| 275 | 275 | |
| 276 | - return $result; |
|
| 277 | - } |
|
| 276 | + return $result; |
|
| 277 | + } |
|
| 278 | 278 | } |
@@ -116,7 +116,7 @@ discard block |
||
| 116 | 116 | $apps = $this->appManager->getEnabledAppsForUser($this->currentUser); |
| 117 | 117 | } |
| 118 | 118 | |
| 119 | - foreach($apps as $app) { |
|
| 119 | + foreach ($apps as $app) { |
|
| 120 | 120 | $apps_paths[$app] = \OC_App::getAppWebPath($app); |
| 121 | 121 | } |
| 122 | 122 | |
@@ -132,8 +132,8 @@ discard block |
||
| 132 | 132 | $outgoingServer2serverShareEnabled = $this->config->getAppValue('files_sharing', 'outgoing_server2server_share_enabled', 'yes') === 'yes'; |
| 133 | 133 | |
| 134 | 134 | $countOfDataLocation = 0; |
| 135 | - $dataLocation = str_replace(\OC::$SERVERROOT .'/', '', $this->config->getSystemValue('datadirectory', ''), $countOfDataLocation); |
|
| 136 | - if($countOfDataLocation !== 1 || !$this->groupManager->isAdmin($uid)) { |
|
| 135 | + $dataLocation = str_replace(\OC::$SERVERROOT.'/', '', $this->config->getSystemValue('datadirectory', ''), $countOfDataLocation); |
|
| 136 | + if ($countOfDataLocation !== 1 || !$this->groupManager->isAdmin($uid)) { |
|
| 137 | 137 | $dataLocation = false; |
| 138 | 138 | } |
| 139 | 139 | |
@@ -149,7 +149,7 @@ discard block |
||
| 149 | 149 | $array = [ |
| 150 | 150 | "oc_debug" => $this->config->getSystemValue('debug', false) ? 'true' : 'false', |
| 151 | 151 | "oc_isadmin" => $this->groupManager->isAdmin($uid) ? 'true' : 'false', |
| 152 | - "backendAllowsPasswordConfirmation" => $userBackend === 'user_saml'? 'false' : 'true', |
|
| 152 | + "backendAllowsPasswordConfirmation" => $userBackend === 'user_saml' ? 'false' : 'true', |
|
| 153 | 153 | "oc_dataURL" => is_string($dataLocation) ? "\"".$dataLocation."\"" : 'false', |
| 154 | 154 | "oc_webroot" => "\"".\OC::$WEBROOT."\"", |
| 155 | 155 | "oc_appswebroots" => str_replace('\\/', '/', json_encode($apps_paths)), // Ugly unescape slashes waiting for better solution |
@@ -157,61 +157,61 @@ discard block |
||
| 157 | 157 | 'nc_lastLogin' => $lastConfirmTimestamp, |
| 158 | 158 | 'nc_pageLoad' => time(), |
| 159 | 159 | "dayNames" => json_encode([ |
| 160 | - (string)$this->l->t('Sunday'), |
|
| 161 | - (string)$this->l->t('Monday'), |
|
| 162 | - (string)$this->l->t('Tuesday'), |
|
| 163 | - (string)$this->l->t('Wednesday'), |
|
| 164 | - (string)$this->l->t('Thursday'), |
|
| 165 | - (string)$this->l->t('Friday'), |
|
| 166 | - (string)$this->l->t('Saturday') |
|
| 160 | + (string) $this->l->t('Sunday'), |
|
| 161 | + (string) $this->l->t('Monday'), |
|
| 162 | + (string) $this->l->t('Tuesday'), |
|
| 163 | + (string) $this->l->t('Wednesday'), |
|
| 164 | + (string) $this->l->t('Thursday'), |
|
| 165 | + (string) $this->l->t('Friday'), |
|
| 166 | + (string) $this->l->t('Saturday') |
|
| 167 | 167 | ]), |
| 168 | 168 | "dayNamesShort" => json_encode([ |
| 169 | - (string)$this->l->t('Sun.'), |
|
| 170 | - (string)$this->l->t('Mon.'), |
|
| 171 | - (string)$this->l->t('Tue.'), |
|
| 172 | - (string)$this->l->t('Wed.'), |
|
| 173 | - (string)$this->l->t('Thu.'), |
|
| 174 | - (string)$this->l->t('Fri.'), |
|
| 175 | - (string)$this->l->t('Sat.') |
|
| 169 | + (string) $this->l->t('Sun.'), |
|
| 170 | + (string) $this->l->t('Mon.'), |
|
| 171 | + (string) $this->l->t('Tue.'), |
|
| 172 | + (string) $this->l->t('Wed.'), |
|
| 173 | + (string) $this->l->t('Thu.'), |
|
| 174 | + (string) $this->l->t('Fri.'), |
|
| 175 | + (string) $this->l->t('Sat.') |
|
| 176 | 176 | ]), |
| 177 | 177 | "dayNamesMin" => json_encode([ |
| 178 | - (string)$this->l->t('Su'), |
|
| 179 | - (string)$this->l->t('Mo'), |
|
| 180 | - (string)$this->l->t('Tu'), |
|
| 181 | - (string)$this->l->t('We'), |
|
| 182 | - (string)$this->l->t('Th'), |
|
| 183 | - (string)$this->l->t('Fr'), |
|
| 184 | - (string)$this->l->t('Sa') |
|
| 178 | + (string) $this->l->t('Su'), |
|
| 179 | + (string) $this->l->t('Mo'), |
|
| 180 | + (string) $this->l->t('Tu'), |
|
| 181 | + (string) $this->l->t('We'), |
|
| 182 | + (string) $this->l->t('Th'), |
|
| 183 | + (string) $this->l->t('Fr'), |
|
| 184 | + (string) $this->l->t('Sa') |
|
| 185 | 185 | ]), |
| 186 | 186 | "monthNames" => json_encode([ |
| 187 | - (string)$this->l->t('January'), |
|
| 188 | - (string)$this->l->t('February'), |
|
| 189 | - (string)$this->l->t('March'), |
|
| 190 | - (string)$this->l->t('April'), |
|
| 191 | - (string)$this->l->t('May'), |
|
| 192 | - (string)$this->l->t('June'), |
|
| 193 | - (string)$this->l->t('July'), |
|
| 194 | - (string)$this->l->t('August'), |
|
| 195 | - (string)$this->l->t('September'), |
|
| 196 | - (string)$this->l->t('October'), |
|
| 197 | - (string)$this->l->t('November'), |
|
| 198 | - (string)$this->l->t('December') |
|
| 187 | + (string) $this->l->t('January'), |
|
| 188 | + (string) $this->l->t('February'), |
|
| 189 | + (string) $this->l->t('March'), |
|
| 190 | + (string) $this->l->t('April'), |
|
| 191 | + (string) $this->l->t('May'), |
|
| 192 | + (string) $this->l->t('June'), |
|
| 193 | + (string) $this->l->t('July'), |
|
| 194 | + (string) $this->l->t('August'), |
|
| 195 | + (string) $this->l->t('September'), |
|
| 196 | + (string) $this->l->t('October'), |
|
| 197 | + (string) $this->l->t('November'), |
|
| 198 | + (string) $this->l->t('December') |
|
| 199 | 199 | ]), |
| 200 | 200 | "monthNamesShort" => json_encode([ |
| 201 | - (string)$this->l->t('Jan.'), |
|
| 202 | - (string)$this->l->t('Feb.'), |
|
| 203 | - (string)$this->l->t('Mar.'), |
|
| 204 | - (string)$this->l->t('Apr.'), |
|
| 205 | - (string)$this->l->t('May.'), |
|
| 206 | - (string)$this->l->t('Jun.'), |
|
| 207 | - (string)$this->l->t('Jul.'), |
|
| 208 | - (string)$this->l->t('Aug.'), |
|
| 209 | - (string)$this->l->t('Sep.'), |
|
| 210 | - (string)$this->l->t('Oct.'), |
|
| 211 | - (string)$this->l->t('Nov.'), |
|
| 212 | - (string)$this->l->t('Dec.') |
|
| 201 | + (string) $this->l->t('Jan.'), |
|
| 202 | + (string) $this->l->t('Feb.'), |
|
| 203 | + (string) $this->l->t('Mar.'), |
|
| 204 | + (string) $this->l->t('Apr.'), |
|
| 205 | + (string) $this->l->t('May.'), |
|
| 206 | + (string) $this->l->t('Jun.'), |
|
| 207 | + (string) $this->l->t('Jul.'), |
|
| 208 | + (string) $this->l->t('Aug.'), |
|
| 209 | + (string) $this->l->t('Sep.'), |
|
| 210 | + (string) $this->l->t('Oct.'), |
|
| 211 | + (string) $this->l->t('Nov.'), |
|
| 212 | + (string) $this->l->t('Dec.') |
|
| 213 | 213 | ]), |
| 214 | - "firstDay" => json_encode($this->l->l('firstday', null)) , |
|
| 214 | + "firstDay" => json_encode($this->l->l('firstday', null)), |
|
| 215 | 215 | "oc_config" => json_encode([ |
| 216 | 216 | 'session_lifetime' => min($this->config->getSystemValue('session_lifetime', $this->iniWrapper->getNumeric('session.gc_maxlifetime')), $this->iniWrapper->getNumeric('session.gc_maxlifetime')), |
| 217 | 217 | 'session_keepalive' => $this->config->getSystemValue('session_keepalive', true), |
@@ -220,8 +220,8 @@ discard block |
||
| 220 | 220 | 'enable_avatars' => true, // here for legacy reasons - to not crash existing code that relies on this value |
| 221 | 221 | 'lost_password_link'=> $this->config->getSystemValue('lost_password_link', null), |
| 222 | 222 | 'modRewriteWorking' => ($this->config->getSystemValue('htaccess.IgnoreFrontController', false) === true || getenv('front_controller_active') === 'true'), |
| 223 | - 'sharing.maxAutocompleteResults' => (int)$this->config->getSystemValue('sharing.maxAutocompleteResults', 0), |
|
| 224 | - 'sharing.minSearchStringLength' => (int)$this->config->getSystemValue('sharing.minSearchStringLength', 0), |
|
| 223 | + 'sharing.maxAutocompleteResults' => (int) $this->config->getSystemValue('sharing.maxAutocompleteResults', 0), |
|
| 224 | + 'sharing.minSearchStringLength' => (int) $this->config->getSystemValue('sharing.minSearchStringLength', 0), |
|
| 225 | 225 | 'blacklist_files_regex' => \OCP\Files\FileInfo::BLACKLIST_FILES_REGEX, |
| 226 | 226 | ]), |
| 227 | 227 | "oc_appconfig" => json_encode([ |
@@ -257,7 +257,7 @@ discard block |
||
| 257 | 257 | if ($this->currentUser !== null) { |
| 258 | 258 | $array['oc_userconfig'] = json_encode([ |
| 259 | 259 | 'avatar' => [ |
| 260 | - 'version' => (int)$this->config->getUserValue($uid, 'avatar', 'version', 0), |
|
| 260 | + 'version' => (int) $this->config->getUserValue($uid, 'avatar', 'version', 0), |
|
| 261 | 261 | 'generated' => $this->config->getUserValue($uid, 'avatar', 'generated', 'true') === 'true', |
| 262 | 262 | ] |
| 263 | 263 | ]); |
@@ -270,7 +270,7 @@ discard block |
||
| 270 | 270 | |
| 271 | 271 | // Echo it |
| 272 | 272 | foreach ($array as $setting => $value) { |
| 273 | - $result .= 'var '. $setting . '='. $value . ';' . PHP_EOL; |
|
| 273 | + $result .= 'var '.$setting.'='.$value.';'.PHP_EOL; |
|
| 274 | 274 | } |
| 275 | 275 | |
| 276 | 276 | return $result; |
@@ -48,396 +48,396 @@ |
||
| 48 | 48 | * |
| 49 | 49 | */ |
| 50 | 50 | class OC_Files { |
| 51 | - const FILE = 1; |
|
| 52 | - const ZIP_FILES = 2; |
|
| 53 | - const ZIP_DIR = 3; |
|
| 54 | - |
|
| 55 | - const UPLOAD_MIN_LIMIT_BYTES = 1048576; // 1 MiB |
|
| 56 | - |
|
| 57 | - |
|
| 58 | - private static $multipartBoundary = ''; |
|
| 59 | - |
|
| 60 | - /** |
|
| 61 | - * @return string |
|
| 62 | - */ |
|
| 63 | - private static function getBoundary() { |
|
| 64 | - if (empty(self::$multipartBoundary)) { |
|
| 65 | - self::$multipartBoundary = md5(mt_rand()); |
|
| 66 | - } |
|
| 67 | - return self::$multipartBoundary; |
|
| 68 | - } |
|
| 69 | - |
|
| 70 | - /** |
|
| 71 | - * @param string $filename |
|
| 72 | - * @param string $name |
|
| 73 | - * @param array $rangeArray ('from'=>int,'to'=>int), ... |
|
| 74 | - */ |
|
| 75 | - private static function sendHeaders($filename, $name, array $rangeArray) { |
|
| 76 | - OC_Response::setContentDispositionHeader($name, 'attachment'); |
|
| 77 | - header('Content-Transfer-Encoding: binary', true); |
|
| 78 | - OC_Response::disableCaching(); |
|
| 79 | - $fileSize = \OC\Files\Filesystem::filesize($filename); |
|
| 80 | - $type = \OC::$server->getMimeTypeDetector()->getSecureMimeType(\OC\Files\Filesystem::getMimeType($filename)); |
|
| 81 | - if ($fileSize > -1) { |
|
| 82 | - if (!empty($rangeArray)) { |
|
| 83 | - header('HTTP/1.1 206 Partial Content', true); |
|
| 84 | - header('Accept-Ranges: bytes', true); |
|
| 85 | - if (count($rangeArray) > 1) { |
|
| 86 | - $type = 'multipart/byteranges; boundary='.self::getBoundary(); |
|
| 87 | - // no Content-Length header here |
|
| 88 | - } |
|
| 89 | - else { |
|
| 90 | - header(sprintf('Content-Range: bytes %d-%d/%d', $rangeArray[0]['from'], $rangeArray[0]['to'], $fileSize), true); |
|
| 91 | - OC_Response::setContentLengthHeader($rangeArray[0]['to'] - $rangeArray[0]['from'] + 1); |
|
| 92 | - } |
|
| 93 | - } |
|
| 94 | - else { |
|
| 95 | - OC_Response::setContentLengthHeader($fileSize); |
|
| 96 | - } |
|
| 97 | - } |
|
| 98 | - header('Content-Type: '.$type, true); |
|
| 99 | - } |
|
| 100 | - |
|
| 101 | - /** |
|
| 102 | - * return the content of a file or return a zip file containing multiple files |
|
| 103 | - * |
|
| 104 | - * @param string $dir |
|
| 105 | - * @param string $files ; separated list of files to download |
|
| 106 | - * @param array $params ; 'head' boolean to only send header of the request ; 'range' http range header |
|
| 107 | - */ |
|
| 108 | - public static function get($dir, $files, $params = null) { |
|
| 109 | - |
|
| 110 | - $view = \OC\Files\Filesystem::getView(); |
|
| 111 | - $getType = self::FILE; |
|
| 112 | - $filename = $dir; |
|
| 113 | - try { |
|
| 114 | - |
|
| 115 | - if (is_array($files) && count($files) === 1) { |
|
| 116 | - $files = $files[0]; |
|
| 117 | - } |
|
| 118 | - |
|
| 119 | - if (!is_array($files)) { |
|
| 120 | - $filename = $dir . '/' . $files; |
|
| 121 | - if (!$view->is_dir($filename)) { |
|
| 122 | - self::getSingleFile($view, $dir, $files, is_null($params) ? array() : $params); |
|
| 123 | - return; |
|
| 124 | - } |
|
| 125 | - } |
|
| 126 | - |
|
| 127 | - $name = 'download'; |
|
| 128 | - if (is_array($files)) { |
|
| 129 | - $getType = self::ZIP_FILES; |
|
| 130 | - $basename = basename($dir); |
|
| 131 | - if ($basename) { |
|
| 132 | - $name = $basename; |
|
| 133 | - } |
|
| 134 | - |
|
| 135 | - $filename = $dir . '/' . $name; |
|
| 136 | - } else { |
|
| 137 | - $filename = $dir . '/' . $files; |
|
| 138 | - $getType = self::ZIP_DIR; |
|
| 139 | - // downloading root ? |
|
| 140 | - if ($files !== '') { |
|
| 141 | - $name = $files; |
|
| 142 | - } |
|
| 143 | - } |
|
| 144 | - |
|
| 145 | - $streamer = new Streamer(); |
|
| 146 | - OC_Util::obEnd(); |
|
| 147 | - |
|
| 148 | - self::lockFiles($view, $dir, $files); |
|
| 149 | - |
|
| 150 | - $streamer->sendHeaders($name); |
|
| 151 | - $executionTime = (int)OC::$server->getIniWrapper()->getNumeric('max_execution_time'); |
|
| 152 | - if (strpos(@ini_get('disable_functions'), 'set_time_limit') === false) { |
|
| 153 | - @set_time_limit(0); |
|
| 154 | - } |
|
| 155 | - ignore_user_abort(true); |
|
| 156 | - if ($getType === self::ZIP_FILES) { |
|
| 157 | - foreach ($files as $file) { |
|
| 158 | - $file = $dir . '/' . $file; |
|
| 159 | - if (\OC\Files\Filesystem::is_file($file)) { |
|
| 160 | - $fileSize = \OC\Files\Filesystem::filesize($file); |
|
| 161 | - $fileTime = \OC\Files\Filesystem::filemtime($file); |
|
| 162 | - $fh = \OC\Files\Filesystem::fopen($file, 'r'); |
|
| 163 | - $streamer->addFileFromStream($fh, basename($file), $fileSize, $fileTime); |
|
| 164 | - fclose($fh); |
|
| 165 | - } elseif (\OC\Files\Filesystem::is_dir($file)) { |
|
| 166 | - $streamer->addDirRecursive($file); |
|
| 167 | - } |
|
| 168 | - } |
|
| 169 | - } elseif ($getType === self::ZIP_DIR) { |
|
| 170 | - $file = $dir . '/' . $files; |
|
| 171 | - $streamer->addDirRecursive($file); |
|
| 172 | - } |
|
| 173 | - $streamer->finalize(); |
|
| 174 | - set_time_limit($executionTime); |
|
| 175 | - self::unlockAllTheFiles($dir, $files, $getType, $view, $filename); |
|
| 176 | - } catch (\OCP\Lock\LockedException $ex) { |
|
| 177 | - self::unlockAllTheFiles($dir, $files, $getType, $view, $filename); |
|
| 178 | - OC::$server->getLogger()->logException($ex); |
|
| 179 | - $l = \OC::$server->getL10N('core'); |
|
| 180 | - $hint = method_exists($ex, 'getHint') ? $ex->getHint() : ''; |
|
| 181 | - \OC_Template::printErrorPage($l->t('File is currently busy, please try again later'), $hint); |
|
| 182 | - } catch (\OCP\Files\ForbiddenException $ex) { |
|
| 183 | - self::unlockAllTheFiles($dir, $files, $getType, $view, $filename); |
|
| 184 | - OC::$server->getLogger()->logException($ex); |
|
| 185 | - $l = \OC::$server->getL10N('core'); |
|
| 186 | - \OC_Template::printErrorPage($l->t('Can\'t read file'), $ex->getMessage()); |
|
| 187 | - } catch (\Exception $ex) { |
|
| 188 | - self::unlockAllTheFiles($dir, $files, $getType, $view, $filename); |
|
| 189 | - OC::$server->getLogger()->logException($ex); |
|
| 190 | - $l = \OC::$server->getL10N('core'); |
|
| 191 | - $hint = method_exists($ex, 'getHint') ? $ex->getHint() : ''; |
|
| 192 | - \OC_Template::printErrorPage($l->t('Can\'t read file'), $hint); |
|
| 193 | - } |
|
| 194 | - } |
|
| 195 | - |
|
| 196 | - /** |
|
| 197 | - * @param string $rangeHeaderPos |
|
| 198 | - * @param int $fileSize |
|
| 199 | - * @return array $rangeArray ('from'=>int,'to'=>int), ... |
|
| 200 | - */ |
|
| 201 | - private static function parseHttpRangeHeader($rangeHeaderPos, $fileSize) { |
|
| 202 | - $rArray=explode(',', $rangeHeaderPos); |
|
| 203 | - $minOffset = 0; |
|
| 204 | - $ind = 0; |
|
| 205 | - |
|
| 206 | - $rangeArray = array(); |
|
| 207 | - |
|
| 208 | - foreach ($rArray as $value) { |
|
| 209 | - $ranges = explode('-', $value); |
|
| 210 | - if (is_numeric($ranges[0])) { |
|
| 211 | - if ($ranges[0] < $minOffset) { // case: bytes=500-700,601-999 |
|
| 212 | - $ranges[0] = $minOffset; |
|
| 213 | - } |
|
| 214 | - if ($ind > 0 && $rangeArray[$ind-1]['to']+1 == $ranges[0]) { // case: bytes=500-600,601-999 |
|
| 215 | - $ind--; |
|
| 216 | - $ranges[0] = $rangeArray[$ind]['from']; |
|
| 217 | - } |
|
| 218 | - } |
|
| 219 | - |
|
| 220 | - if (is_numeric($ranges[0]) && is_numeric($ranges[1]) && $ranges[0] < $fileSize && $ranges[0] <= $ranges[1]) { |
|
| 221 | - // case: x-x |
|
| 222 | - if ($ranges[1] >= $fileSize) { |
|
| 223 | - $ranges[1] = $fileSize-1; |
|
| 224 | - } |
|
| 225 | - $rangeArray[$ind++] = array( 'from' => $ranges[0], 'to' => $ranges[1], 'size' => $fileSize ); |
|
| 226 | - $minOffset = $ranges[1] + 1; |
|
| 227 | - if ($minOffset >= $fileSize) { |
|
| 228 | - break; |
|
| 229 | - } |
|
| 230 | - } |
|
| 231 | - elseif (is_numeric($ranges[0]) && $ranges[0] < $fileSize) { |
|
| 232 | - // case: x- |
|
| 233 | - $rangeArray[$ind++] = array( 'from' => $ranges[0], 'to' => $fileSize-1, 'size' => $fileSize ); |
|
| 234 | - break; |
|
| 235 | - } |
|
| 236 | - elseif (is_numeric($ranges[1])) { |
|
| 237 | - // case: -x |
|
| 238 | - if ($ranges[1] > $fileSize) { |
|
| 239 | - $ranges[1] = $fileSize; |
|
| 240 | - } |
|
| 241 | - $rangeArray[$ind++] = array( 'from' => $fileSize-$ranges[1], 'to' => $fileSize-1, 'size' => $fileSize ); |
|
| 242 | - break; |
|
| 243 | - } |
|
| 244 | - } |
|
| 245 | - return $rangeArray; |
|
| 246 | - } |
|
| 247 | - |
|
| 248 | - /** |
|
| 249 | - * @param View $view |
|
| 250 | - * @param string $name |
|
| 251 | - * @param string $dir |
|
| 252 | - * @param array $params ; 'head' boolean to only send header of the request ; 'range' http range header |
|
| 253 | - */ |
|
| 254 | - private static function getSingleFile($view, $dir, $name, $params) { |
|
| 255 | - $filename = $dir . '/' . $name; |
|
| 256 | - OC_Util::obEnd(); |
|
| 257 | - $view->lockFile($filename, ILockingProvider::LOCK_SHARED); |
|
| 51 | + const FILE = 1; |
|
| 52 | + const ZIP_FILES = 2; |
|
| 53 | + const ZIP_DIR = 3; |
|
| 54 | + |
|
| 55 | + const UPLOAD_MIN_LIMIT_BYTES = 1048576; // 1 MiB |
|
| 56 | + |
|
| 57 | + |
|
| 58 | + private static $multipartBoundary = ''; |
|
| 59 | + |
|
| 60 | + /** |
|
| 61 | + * @return string |
|
| 62 | + */ |
|
| 63 | + private static function getBoundary() { |
|
| 64 | + if (empty(self::$multipartBoundary)) { |
|
| 65 | + self::$multipartBoundary = md5(mt_rand()); |
|
| 66 | + } |
|
| 67 | + return self::$multipartBoundary; |
|
| 68 | + } |
|
| 69 | + |
|
| 70 | + /** |
|
| 71 | + * @param string $filename |
|
| 72 | + * @param string $name |
|
| 73 | + * @param array $rangeArray ('from'=>int,'to'=>int), ... |
|
| 74 | + */ |
|
| 75 | + private static function sendHeaders($filename, $name, array $rangeArray) { |
|
| 76 | + OC_Response::setContentDispositionHeader($name, 'attachment'); |
|
| 77 | + header('Content-Transfer-Encoding: binary', true); |
|
| 78 | + OC_Response::disableCaching(); |
|
| 79 | + $fileSize = \OC\Files\Filesystem::filesize($filename); |
|
| 80 | + $type = \OC::$server->getMimeTypeDetector()->getSecureMimeType(\OC\Files\Filesystem::getMimeType($filename)); |
|
| 81 | + if ($fileSize > -1) { |
|
| 82 | + if (!empty($rangeArray)) { |
|
| 83 | + header('HTTP/1.1 206 Partial Content', true); |
|
| 84 | + header('Accept-Ranges: bytes', true); |
|
| 85 | + if (count($rangeArray) > 1) { |
|
| 86 | + $type = 'multipart/byteranges; boundary='.self::getBoundary(); |
|
| 87 | + // no Content-Length header here |
|
| 88 | + } |
|
| 89 | + else { |
|
| 90 | + header(sprintf('Content-Range: bytes %d-%d/%d', $rangeArray[0]['from'], $rangeArray[0]['to'], $fileSize), true); |
|
| 91 | + OC_Response::setContentLengthHeader($rangeArray[0]['to'] - $rangeArray[0]['from'] + 1); |
|
| 92 | + } |
|
| 93 | + } |
|
| 94 | + else { |
|
| 95 | + OC_Response::setContentLengthHeader($fileSize); |
|
| 96 | + } |
|
| 97 | + } |
|
| 98 | + header('Content-Type: '.$type, true); |
|
| 99 | + } |
|
| 100 | + |
|
| 101 | + /** |
|
| 102 | + * return the content of a file or return a zip file containing multiple files |
|
| 103 | + * |
|
| 104 | + * @param string $dir |
|
| 105 | + * @param string $files ; separated list of files to download |
|
| 106 | + * @param array $params ; 'head' boolean to only send header of the request ; 'range' http range header |
|
| 107 | + */ |
|
| 108 | + public static function get($dir, $files, $params = null) { |
|
| 109 | + |
|
| 110 | + $view = \OC\Files\Filesystem::getView(); |
|
| 111 | + $getType = self::FILE; |
|
| 112 | + $filename = $dir; |
|
| 113 | + try { |
|
| 114 | + |
|
| 115 | + if (is_array($files) && count($files) === 1) { |
|
| 116 | + $files = $files[0]; |
|
| 117 | + } |
|
| 118 | + |
|
| 119 | + if (!is_array($files)) { |
|
| 120 | + $filename = $dir . '/' . $files; |
|
| 121 | + if (!$view->is_dir($filename)) { |
|
| 122 | + self::getSingleFile($view, $dir, $files, is_null($params) ? array() : $params); |
|
| 123 | + return; |
|
| 124 | + } |
|
| 125 | + } |
|
| 126 | + |
|
| 127 | + $name = 'download'; |
|
| 128 | + if (is_array($files)) { |
|
| 129 | + $getType = self::ZIP_FILES; |
|
| 130 | + $basename = basename($dir); |
|
| 131 | + if ($basename) { |
|
| 132 | + $name = $basename; |
|
| 133 | + } |
|
| 134 | + |
|
| 135 | + $filename = $dir . '/' . $name; |
|
| 136 | + } else { |
|
| 137 | + $filename = $dir . '/' . $files; |
|
| 138 | + $getType = self::ZIP_DIR; |
|
| 139 | + // downloading root ? |
|
| 140 | + if ($files !== '') { |
|
| 141 | + $name = $files; |
|
| 142 | + } |
|
| 143 | + } |
|
| 144 | + |
|
| 145 | + $streamer = new Streamer(); |
|
| 146 | + OC_Util::obEnd(); |
|
| 147 | + |
|
| 148 | + self::lockFiles($view, $dir, $files); |
|
| 149 | + |
|
| 150 | + $streamer->sendHeaders($name); |
|
| 151 | + $executionTime = (int)OC::$server->getIniWrapper()->getNumeric('max_execution_time'); |
|
| 152 | + if (strpos(@ini_get('disable_functions'), 'set_time_limit') === false) { |
|
| 153 | + @set_time_limit(0); |
|
| 154 | + } |
|
| 155 | + ignore_user_abort(true); |
|
| 156 | + if ($getType === self::ZIP_FILES) { |
|
| 157 | + foreach ($files as $file) { |
|
| 158 | + $file = $dir . '/' . $file; |
|
| 159 | + if (\OC\Files\Filesystem::is_file($file)) { |
|
| 160 | + $fileSize = \OC\Files\Filesystem::filesize($file); |
|
| 161 | + $fileTime = \OC\Files\Filesystem::filemtime($file); |
|
| 162 | + $fh = \OC\Files\Filesystem::fopen($file, 'r'); |
|
| 163 | + $streamer->addFileFromStream($fh, basename($file), $fileSize, $fileTime); |
|
| 164 | + fclose($fh); |
|
| 165 | + } elseif (\OC\Files\Filesystem::is_dir($file)) { |
|
| 166 | + $streamer->addDirRecursive($file); |
|
| 167 | + } |
|
| 168 | + } |
|
| 169 | + } elseif ($getType === self::ZIP_DIR) { |
|
| 170 | + $file = $dir . '/' . $files; |
|
| 171 | + $streamer->addDirRecursive($file); |
|
| 172 | + } |
|
| 173 | + $streamer->finalize(); |
|
| 174 | + set_time_limit($executionTime); |
|
| 175 | + self::unlockAllTheFiles($dir, $files, $getType, $view, $filename); |
|
| 176 | + } catch (\OCP\Lock\LockedException $ex) { |
|
| 177 | + self::unlockAllTheFiles($dir, $files, $getType, $view, $filename); |
|
| 178 | + OC::$server->getLogger()->logException($ex); |
|
| 179 | + $l = \OC::$server->getL10N('core'); |
|
| 180 | + $hint = method_exists($ex, 'getHint') ? $ex->getHint() : ''; |
|
| 181 | + \OC_Template::printErrorPage($l->t('File is currently busy, please try again later'), $hint); |
|
| 182 | + } catch (\OCP\Files\ForbiddenException $ex) { |
|
| 183 | + self::unlockAllTheFiles($dir, $files, $getType, $view, $filename); |
|
| 184 | + OC::$server->getLogger()->logException($ex); |
|
| 185 | + $l = \OC::$server->getL10N('core'); |
|
| 186 | + \OC_Template::printErrorPage($l->t('Can\'t read file'), $ex->getMessage()); |
|
| 187 | + } catch (\Exception $ex) { |
|
| 188 | + self::unlockAllTheFiles($dir, $files, $getType, $view, $filename); |
|
| 189 | + OC::$server->getLogger()->logException($ex); |
|
| 190 | + $l = \OC::$server->getL10N('core'); |
|
| 191 | + $hint = method_exists($ex, 'getHint') ? $ex->getHint() : ''; |
|
| 192 | + \OC_Template::printErrorPage($l->t('Can\'t read file'), $hint); |
|
| 193 | + } |
|
| 194 | + } |
|
| 195 | + |
|
| 196 | + /** |
|
| 197 | + * @param string $rangeHeaderPos |
|
| 198 | + * @param int $fileSize |
|
| 199 | + * @return array $rangeArray ('from'=>int,'to'=>int), ... |
|
| 200 | + */ |
|
| 201 | + private static function parseHttpRangeHeader($rangeHeaderPos, $fileSize) { |
|
| 202 | + $rArray=explode(',', $rangeHeaderPos); |
|
| 203 | + $minOffset = 0; |
|
| 204 | + $ind = 0; |
|
| 205 | + |
|
| 206 | + $rangeArray = array(); |
|
| 207 | + |
|
| 208 | + foreach ($rArray as $value) { |
|
| 209 | + $ranges = explode('-', $value); |
|
| 210 | + if (is_numeric($ranges[0])) { |
|
| 211 | + if ($ranges[0] < $minOffset) { // case: bytes=500-700,601-999 |
|
| 212 | + $ranges[0] = $minOffset; |
|
| 213 | + } |
|
| 214 | + if ($ind > 0 && $rangeArray[$ind-1]['to']+1 == $ranges[0]) { // case: bytes=500-600,601-999 |
|
| 215 | + $ind--; |
|
| 216 | + $ranges[0] = $rangeArray[$ind]['from']; |
|
| 217 | + } |
|
| 218 | + } |
|
| 219 | + |
|
| 220 | + if (is_numeric($ranges[0]) && is_numeric($ranges[1]) && $ranges[0] < $fileSize && $ranges[0] <= $ranges[1]) { |
|
| 221 | + // case: x-x |
|
| 222 | + if ($ranges[1] >= $fileSize) { |
|
| 223 | + $ranges[1] = $fileSize-1; |
|
| 224 | + } |
|
| 225 | + $rangeArray[$ind++] = array( 'from' => $ranges[0], 'to' => $ranges[1], 'size' => $fileSize ); |
|
| 226 | + $minOffset = $ranges[1] + 1; |
|
| 227 | + if ($minOffset >= $fileSize) { |
|
| 228 | + break; |
|
| 229 | + } |
|
| 230 | + } |
|
| 231 | + elseif (is_numeric($ranges[0]) && $ranges[0] < $fileSize) { |
|
| 232 | + // case: x- |
|
| 233 | + $rangeArray[$ind++] = array( 'from' => $ranges[0], 'to' => $fileSize-1, 'size' => $fileSize ); |
|
| 234 | + break; |
|
| 235 | + } |
|
| 236 | + elseif (is_numeric($ranges[1])) { |
|
| 237 | + // case: -x |
|
| 238 | + if ($ranges[1] > $fileSize) { |
|
| 239 | + $ranges[1] = $fileSize; |
|
| 240 | + } |
|
| 241 | + $rangeArray[$ind++] = array( 'from' => $fileSize-$ranges[1], 'to' => $fileSize-1, 'size' => $fileSize ); |
|
| 242 | + break; |
|
| 243 | + } |
|
| 244 | + } |
|
| 245 | + return $rangeArray; |
|
| 246 | + } |
|
| 247 | + |
|
| 248 | + /** |
|
| 249 | + * @param View $view |
|
| 250 | + * @param string $name |
|
| 251 | + * @param string $dir |
|
| 252 | + * @param array $params ; 'head' boolean to only send header of the request ; 'range' http range header |
|
| 253 | + */ |
|
| 254 | + private static function getSingleFile($view, $dir, $name, $params) { |
|
| 255 | + $filename = $dir . '/' . $name; |
|
| 256 | + OC_Util::obEnd(); |
|
| 257 | + $view->lockFile($filename, ILockingProvider::LOCK_SHARED); |
|
| 258 | 258 | |
| 259 | - $rangeArray = array(); |
|
| 259 | + $rangeArray = array(); |
|
| 260 | 260 | |
| 261 | - if (isset($params['range']) && substr($params['range'], 0, 6) === 'bytes=') { |
|
| 262 | - $rangeArray = self::parseHttpRangeHeader(substr($params['range'], 6), |
|
| 263 | - \OC\Files\Filesystem::filesize($filename)); |
|
| 264 | - } |
|
| 261 | + if (isset($params['range']) && substr($params['range'], 0, 6) === 'bytes=') { |
|
| 262 | + $rangeArray = self::parseHttpRangeHeader(substr($params['range'], 6), |
|
| 263 | + \OC\Files\Filesystem::filesize($filename)); |
|
| 264 | + } |
|
| 265 | 265 | |
| 266 | - if (\OC\Files\Filesystem::isReadable($filename)) { |
|
| 267 | - self::sendHeaders($filename, $name, $rangeArray); |
|
| 268 | - } elseif (!\OC\Files\Filesystem::file_exists($filename)) { |
|
| 269 | - header("HTTP/1.1 404 Not Found"); |
|
| 270 | - $tmpl = new OC_Template('', '404', 'guest'); |
|
| 271 | - $tmpl->printPage(); |
|
| 272 | - exit(); |
|
| 273 | - } else { |
|
| 274 | - header("HTTP/1.1 403 Forbidden"); |
|
| 275 | - die('403 Forbidden'); |
|
| 276 | - } |
|
| 277 | - if (isset($params['head']) && $params['head']) { |
|
| 278 | - return; |
|
| 279 | - } |
|
| 280 | - if (!empty($rangeArray)) { |
|
| 281 | - try { |
|
| 282 | - if (count($rangeArray) == 1) { |
|
| 283 | - $view->readfilePart($filename, $rangeArray[0]['from'], $rangeArray[0]['to']); |
|
| 284 | - } |
|
| 285 | - else { |
|
| 286 | - // check if file is seekable (if not throw UnseekableException) |
|
| 287 | - // we have to check it before body contents |
|
| 288 | - $view->readfilePart($filename, $rangeArray[0]['size'], $rangeArray[0]['size']); |
|
| 289 | - |
|
| 290 | - $type = \OC::$server->getMimeTypeDetector()->getSecureMimeType(\OC\Files\Filesystem::getMimeType($filename)); |
|
| 291 | - |
|
| 292 | - foreach ($rangeArray as $range) { |
|
| 293 | - echo "\r\n--".self::getBoundary()."\r\n". |
|
| 294 | - "Content-type: ".$type."\r\n". |
|
| 295 | - "Content-range: bytes ".$range['from']."-".$range['to']."/".$range['size']."\r\n\r\n"; |
|
| 296 | - $view->readfilePart($filename, $range['from'], $range['to']); |
|
| 297 | - } |
|
| 298 | - echo "\r\n--".self::getBoundary()."--\r\n"; |
|
| 299 | - } |
|
| 300 | - } catch (\OCP\Files\UnseekableException $ex) { |
|
| 301 | - // file is unseekable |
|
| 302 | - header_remove('Accept-Ranges'); |
|
| 303 | - header_remove('Content-Range'); |
|
| 304 | - header("HTTP/1.1 200 OK"); |
|
| 305 | - self::sendHeaders($filename, $name, array()); |
|
| 306 | - $view->readfile($filename); |
|
| 307 | - } |
|
| 308 | - } |
|
| 309 | - else { |
|
| 310 | - $view->readfile($filename); |
|
| 311 | - } |
|
| 312 | - } |
|
| 313 | - |
|
| 314 | - /** |
|
| 315 | - * @param View $view |
|
| 316 | - * @param string $dir |
|
| 317 | - * @param string[]|string $files |
|
| 318 | - */ |
|
| 319 | - public static function lockFiles($view, $dir, $files) { |
|
| 320 | - if (!is_array($files)) { |
|
| 321 | - $file = $dir . '/' . $files; |
|
| 322 | - $files = [$file]; |
|
| 323 | - } |
|
| 324 | - foreach ($files as $file) { |
|
| 325 | - $file = $dir . '/' . $file; |
|
| 326 | - $view->lockFile($file, ILockingProvider::LOCK_SHARED); |
|
| 327 | - if ($view->is_dir($file)) { |
|
| 328 | - $contents = $view->getDirectoryContent($file); |
|
| 329 | - $contents = array_map(function($fileInfo) use ($file) { |
|
| 330 | - /** @var \OCP\Files\FileInfo $fileInfo */ |
|
| 331 | - return $file . '/' . $fileInfo->getName(); |
|
| 332 | - }, $contents); |
|
| 333 | - self::lockFiles($view, $dir, $contents); |
|
| 334 | - } |
|
| 335 | - } |
|
| 336 | - } |
|
| 337 | - |
|
| 338 | - /** |
|
| 339 | - * set the maximum upload size limit for apache hosts using .htaccess |
|
| 340 | - * |
|
| 341 | - * @param int $size file size in bytes |
|
| 342 | - * @param array $files override '.htaccess' and '.user.ini' locations |
|
| 343 | - * @return bool|int false on failure, size on success |
|
| 344 | - */ |
|
| 345 | - public static function setUploadLimit($size, $files = []) { |
|
| 346 | - //don't allow user to break his config |
|
| 347 | - $size = (int)$size; |
|
| 348 | - if ($size < self::UPLOAD_MIN_LIMIT_BYTES) { |
|
| 349 | - return false; |
|
| 350 | - } |
|
| 351 | - $size = OC_Helper::phpFileSize($size); |
|
| 352 | - |
|
| 353 | - $phpValueKeys = array( |
|
| 354 | - 'upload_max_filesize', |
|
| 355 | - 'post_max_size' |
|
| 356 | - ); |
|
| 357 | - |
|
| 358 | - // default locations if not overridden by $files |
|
| 359 | - $files = array_merge([ |
|
| 360 | - '.htaccess' => OC::$SERVERROOT . '/.htaccess', |
|
| 361 | - '.user.ini' => OC::$SERVERROOT . '/.user.ini' |
|
| 362 | - ], $files); |
|
| 363 | - |
|
| 364 | - $updateFiles = [ |
|
| 365 | - $files['.htaccess'] => [ |
|
| 366 | - 'pattern' => '/php_value %1$s (\S)*/', |
|
| 367 | - 'setting' => 'php_value %1$s %2$s' |
|
| 368 | - ], |
|
| 369 | - $files['.user.ini'] => [ |
|
| 370 | - 'pattern' => '/%1$s=(\S)*/', |
|
| 371 | - 'setting' => '%1$s=%2$s' |
|
| 372 | - ] |
|
| 373 | - ]; |
|
| 374 | - |
|
| 375 | - $success = true; |
|
| 376 | - |
|
| 377 | - foreach ($updateFiles as $filename => $patternMap) { |
|
| 378 | - // suppress warnings from fopen() |
|
| 379 | - $handle = @fopen($filename, 'r+'); |
|
| 380 | - if (!$handle) { |
|
| 381 | - \OCP\Util::writeLog('files', |
|
| 382 | - 'Can\'t write upload limit to ' . $filename . '. Please check the file permissions', |
|
| 383 | - \OCP\Util::WARN); |
|
| 384 | - $success = false; |
|
| 385 | - continue; // try to update as many files as possible |
|
| 386 | - } |
|
| 387 | - |
|
| 388 | - $content = ''; |
|
| 389 | - while (!feof($handle)) { |
|
| 390 | - $content .= fread($handle, 1000); |
|
| 391 | - } |
|
| 392 | - |
|
| 393 | - foreach ($phpValueKeys as $key) { |
|
| 394 | - $pattern = vsprintf($patternMap['pattern'], [$key]); |
|
| 395 | - $setting = vsprintf($patternMap['setting'], [$key, $size]); |
|
| 396 | - $hasReplaced = 0; |
|
| 397 | - $newContent = preg_replace($pattern, $setting, $content, 2, $hasReplaced); |
|
| 398 | - if ($newContent !== null) { |
|
| 399 | - $content = $newContent; |
|
| 400 | - } |
|
| 401 | - if ($hasReplaced === 0) { |
|
| 402 | - $content .= "\n" . $setting; |
|
| 403 | - } |
|
| 404 | - } |
|
| 405 | - |
|
| 406 | - // write file back |
|
| 407 | - ftruncate($handle, 0); |
|
| 408 | - rewind($handle); |
|
| 409 | - fwrite($handle, $content); |
|
| 410 | - |
|
| 411 | - fclose($handle); |
|
| 412 | - } |
|
| 413 | - |
|
| 414 | - if ($success) { |
|
| 415 | - return OC_Helper::computerFileSize($size); |
|
| 416 | - } |
|
| 417 | - return false; |
|
| 418 | - } |
|
| 419 | - |
|
| 420 | - /** |
|
| 421 | - * @param string $dir |
|
| 422 | - * @param $files |
|
| 423 | - * @param integer $getType |
|
| 424 | - * @param View $view |
|
| 425 | - * @param string $filename |
|
| 426 | - */ |
|
| 427 | - private static function unlockAllTheFiles($dir, $files, $getType, $view, $filename) { |
|
| 428 | - if ($getType === self::FILE) { |
|
| 429 | - $view->unlockFile($filename, ILockingProvider::LOCK_SHARED); |
|
| 430 | - } |
|
| 431 | - if ($getType === self::ZIP_FILES) { |
|
| 432 | - foreach ($files as $file) { |
|
| 433 | - $file = $dir . '/' . $file; |
|
| 434 | - $view->unlockFile($file, ILockingProvider::LOCK_SHARED); |
|
| 435 | - } |
|
| 436 | - } |
|
| 437 | - if ($getType === self::ZIP_DIR) { |
|
| 438 | - $file = $dir . '/' . $files; |
|
| 439 | - $view->unlockFile($file, ILockingProvider::LOCK_SHARED); |
|
| 440 | - } |
|
| 441 | - } |
|
| 266 | + if (\OC\Files\Filesystem::isReadable($filename)) { |
|
| 267 | + self::sendHeaders($filename, $name, $rangeArray); |
|
| 268 | + } elseif (!\OC\Files\Filesystem::file_exists($filename)) { |
|
| 269 | + header("HTTP/1.1 404 Not Found"); |
|
| 270 | + $tmpl = new OC_Template('', '404', 'guest'); |
|
| 271 | + $tmpl->printPage(); |
|
| 272 | + exit(); |
|
| 273 | + } else { |
|
| 274 | + header("HTTP/1.1 403 Forbidden"); |
|
| 275 | + die('403 Forbidden'); |
|
| 276 | + } |
|
| 277 | + if (isset($params['head']) && $params['head']) { |
|
| 278 | + return; |
|
| 279 | + } |
|
| 280 | + if (!empty($rangeArray)) { |
|
| 281 | + try { |
|
| 282 | + if (count($rangeArray) == 1) { |
|
| 283 | + $view->readfilePart($filename, $rangeArray[0]['from'], $rangeArray[0]['to']); |
|
| 284 | + } |
|
| 285 | + else { |
|
| 286 | + // check if file is seekable (if not throw UnseekableException) |
|
| 287 | + // we have to check it before body contents |
|
| 288 | + $view->readfilePart($filename, $rangeArray[0]['size'], $rangeArray[0]['size']); |
|
| 289 | + |
|
| 290 | + $type = \OC::$server->getMimeTypeDetector()->getSecureMimeType(\OC\Files\Filesystem::getMimeType($filename)); |
|
| 291 | + |
|
| 292 | + foreach ($rangeArray as $range) { |
|
| 293 | + echo "\r\n--".self::getBoundary()."\r\n". |
|
| 294 | + "Content-type: ".$type."\r\n". |
|
| 295 | + "Content-range: bytes ".$range['from']."-".$range['to']."/".$range['size']."\r\n\r\n"; |
|
| 296 | + $view->readfilePart($filename, $range['from'], $range['to']); |
|
| 297 | + } |
|
| 298 | + echo "\r\n--".self::getBoundary()."--\r\n"; |
|
| 299 | + } |
|
| 300 | + } catch (\OCP\Files\UnseekableException $ex) { |
|
| 301 | + // file is unseekable |
|
| 302 | + header_remove('Accept-Ranges'); |
|
| 303 | + header_remove('Content-Range'); |
|
| 304 | + header("HTTP/1.1 200 OK"); |
|
| 305 | + self::sendHeaders($filename, $name, array()); |
|
| 306 | + $view->readfile($filename); |
|
| 307 | + } |
|
| 308 | + } |
|
| 309 | + else { |
|
| 310 | + $view->readfile($filename); |
|
| 311 | + } |
|
| 312 | + } |
|
| 313 | + |
|
| 314 | + /** |
|
| 315 | + * @param View $view |
|
| 316 | + * @param string $dir |
|
| 317 | + * @param string[]|string $files |
|
| 318 | + */ |
|
| 319 | + public static function lockFiles($view, $dir, $files) { |
|
| 320 | + if (!is_array($files)) { |
|
| 321 | + $file = $dir . '/' . $files; |
|
| 322 | + $files = [$file]; |
|
| 323 | + } |
|
| 324 | + foreach ($files as $file) { |
|
| 325 | + $file = $dir . '/' . $file; |
|
| 326 | + $view->lockFile($file, ILockingProvider::LOCK_SHARED); |
|
| 327 | + if ($view->is_dir($file)) { |
|
| 328 | + $contents = $view->getDirectoryContent($file); |
|
| 329 | + $contents = array_map(function($fileInfo) use ($file) { |
|
| 330 | + /** @var \OCP\Files\FileInfo $fileInfo */ |
|
| 331 | + return $file . '/' . $fileInfo->getName(); |
|
| 332 | + }, $contents); |
|
| 333 | + self::lockFiles($view, $dir, $contents); |
|
| 334 | + } |
|
| 335 | + } |
|
| 336 | + } |
|
| 337 | + |
|
| 338 | + /** |
|
| 339 | + * set the maximum upload size limit for apache hosts using .htaccess |
|
| 340 | + * |
|
| 341 | + * @param int $size file size in bytes |
|
| 342 | + * @param array $files override '.htaccess' and '.user.ini' locations |
|
| 343 | + * @return bool|int false on failure, size on success |
|
| 344 | + */ |
|
| 345 | + public static function setUploadLimit($size, $files = []) { |
|
| 346 | + //don't allow user to break his config |
|
| 347 | + $size = (int)$size; |
|
| 348 | + if ($size < self::UPLOAD_MIN_LIMIT_BYTES) { |
|
| 349 | + return false; |
|
| 350 | + } |
|
| 351 | + $size = OC_Helper::phpFileSize($size); |
|
| 352 | + |
|
| 353 | + $phpValueKeys = array( |
|
| 354 | + 'upload_max_filesize', |
|
| 355 | + 'post_max_size' |
|
| 356 | + ); |
|
| 357 | + |
|
| 358 | + // default locations if not overridden by $files |
|
| 359 | + $files = array_merge([ |
|
| 360 | + '.htaccess' => OC::$SERVERROOT . '/.htaccess', |
|
| 361 | + '.user.ini' => OC::$SERVERROOT . '/.user.ini' |
|
| 362 | + ], $files); |
|
| 363 | + |
|
| 364 | + $updateFiles = [ |
|
| 365 | + $files['.htaccess'] => [ |
|
| 366 | + 'pattern' => '/php_value %1$s (\S)*/', |
|
| 367 | + 'setting' => 'php_value %1$s %2$s' |
|
| 368 | + ], |
|
| 369 | + $files['.user.ini'] => [ |
|
| 370 | + 'pattern' => '/%1$s=(\S)*/', |
|
| 371 | + 'setting' => '%1$s=%2$s' |
|
| 372 | + ] |
|
| 373 | + ]; |
|
| 374 | + |
|
| 375 | + $success = true; |
|
| 376 | + |
|
| 377 | + foreach ($updateFiles as $filename => $patternMap) { |
|
| 378 | + // suppress warnings from fopen() |
|
| 379 | + $handle = @fopen($filename, 'r+'); |
|
| 380 | + if (!$handle) { |
|
| 381 | + \OCP\Util::writeLog('files', |
|
| 382 | + 'Can\'t write upload limit to ' . $filename . '. Please check the file permissions', |
|
| 383 | + \OCP\Util::WARN); |
|
| 384 | + $success = false; |
|
| 385 | + continue; // try to update as many files as possible |
|
| 386 | + } |
|
| 387 | + |
|
| 388 | + $content = ''; |
|
| 389 | + while (!feof($handle)) { |
|
| 390 | + $content .= fread($handle, 1000); |
|
| 391 | + } |
|
| 392 | + |
|
| 393 | + foreach ($phpValueKeys as $key) { |
|
| 394 | + $pattern = vsprintf($patternMap['pattern'], [$key]); |
|
| 395 | + $setting = vsprintf($patternMap['setting'], [$key, $size]); |
|
| 396 | + $hasReplaced = 0; |
|
| 397 | + $newContent = preg_replace($pattern, $setting, $content, 2, $hasReplaced); |
|
| 398 | + if ($newContent !== null) { |
|
| 399 | + $content = $newContent; |
|
| 400 | + } |
|
| 401 | + if ($hasReplaced === 0) { |
|
| 402 | + $content .= "\n" . $setting; |
|
| 403 | + } |
|
| 404 | + } |
|
| 405 | + |
|
| 406 | + // write file back |
|
| 407 | + ftruncate($handle, 0); |
|
| 408 | + rewind($handle); |
|
| 409 | + fwrite($handle, $content); |
|
| 410 | + |
|
| 411 | + fclose($handle); |
|
| 412 | + } |
|
| 413 | + |
|
| 414 | + if ($success) { |
|
| 415 | + return OC_Helper::computerFileSize($size); |
|
| 416 | + } |
|
| 417 | + return false; |
|
| 418 | + } |
|
| 419 | + |
|
| 420 | + /** |
|
| 421 | + * @param string $dir |
|
| 422 | + * @param $files |
|
| 423 | + * @param integer $getType |
|
| 424 | + * @param View $view |
|
| 425 | + * @param string $filename |
|
| 426 | + */ |
|
| 427 | + private static function unlockAllTheFiles($dir, $files, $getType, $view, $filename) { |
|
| 428 | + if ($getType === self::FILE) { |
|
| 429 | + $view->unlockFile($filename, ILockingProvider::LOCK_SHARED); |
|
| 430 | + } |
|
| 431 | + if ($getType === self::ZIP_FILES) { |
|
| 432 | + foreach ($files as $file) { |
|
| 433 | + $file = $dir . '/' . $file; |
|
| 434 | + $view->unlockFile($file, ILockingProvider::LOCK_SHARED); |
|
| 435 | + } |
|
| 436 | + } |
|
| 437 | + if ($getType === self::ZIP_DIR) { |
|
| 438 | + $file = $dir . '/' . $files; |
|
| 439 | + $view->unlockFile($file, ILockingProvider::LOCK_SHARED); |
|
| 440 | + } |
|
| 441 | + } |
|
| 442 | 442 | |
| 443 | 443 | } |
@@ -117,7 +117,7 @@ discard block |
||
| 117 | 117 | } |
| 118 | 118 | |
| 119 | 119 | if (!is_array($files)) { |
| 120 | - $filename = $dir . '/' . $files; |
|
| 120 | + $filename = $dir.'/'.$files; |
|
| 121 | 121 | if (!$view->is_dir($filename)) { |
| 122 | 122 | self::getSingleFile($view, $dir, $files, is_null($params) ? array() : $params); |
| 123 | 123 | return; |
@@ -132,9 +132,9 @@ discard block |
||
| 132 | 132 | $name = $basename; |
| 133 | 133 | } |
| 134 | 134 | |
| 135 | - $filename = $dir . '/' . $name; |
|
| 135 | + $filename = $dir.'/'.$name; |
|
| 136 | 136 | } else { |
| 137 | - $filename = $dir . '/' . $files; |
|
| 137 | + $filename = $dir.'/'.$files; |
|
| 138 | 138 | $getType = self::ZIP_DIR; |
| 139 | 139 | // downloading root ? |
| 140 | 140 | if ($files !== '') { |
@@ -148,14 +148,14 @@ discard block |
||
| 148 | 148 | self::lockFiles($view, $dir, $files); |
| 149 | 149 | |
| 150 | 150 | $streamer->sendHeaders($name); |
| 151 | - $executionTime = (int)OC::$server->getIniWrapper()->getNumeric('max_execution_time'); |
|
| 151 | + $executionTime = (int) OC::$server->getIniWrapper()->getNumeric('max_execution_time'); |
|
| 152 | 152 | if (strpos(@ini_get('disable_functions'), 'set_time_limit') === false) { |
| 153 | 153 | @set_time_limit(0); |
| 154 | 154 | } |
| 155 | 155 | ignore_user_abort(true); |
| 156 | 156 | if ($getType === self::ZIP_FILES) { |
| 157 | 157 | foreach ($files as $file) { |
| 158 | - $file = $dir . '/' . $file; |
|
| 158 | + $file = $dir.'/'.$file; |
|
| 159 | 159 | if (\OC\Files\Filesystem::is_file($file)) { |
| 160 | 160 | $fileSize = \OC\Files\Filesystem::filesize($file); |
| 161 | 161 | $fileTime = \OC\Files\Filesystem::filemtime($file); |
@@ -167,7 +167,7 @@ discard block |
||
| 167 | 167 | } |
| 168 | 168 | } |
| 169 | 169 | } elseif ($getType === self::ZIP_DIR) { |
| 170 | - $file = $dir . '/' . $files; |
|
| 170 | + $file = $dir.'/'.$files; |
|
| 171 | 171 | $streamer->addDirRecursive($file); |
| 172 | 172 | } |
| 173 | 173 | $streamer->finalize(); |
@@ -199,7 +199,7 @@ discard block |
||
| 199 | 199 | * @return array $rangeArray ('from'=>int,'to'=>int), ... |
| 200 | 200 | */ |
| 201 | 201 | private static function parseHttpRangeHeader($rangeHeaderPos, $fileSize) { |
| 202 | - $rArray=explode(',', $rangeHeaderPos); |
|
| 202 | + $rArray = explode(',', $rangeHeaderPos); |
|
| 203 | 203 | $minOffset = 0; |
| 204 | 204 | $ind = 0; |
| 205 | 205 | |
@@ -211,7 +211,7 @@ discard block |
||
| 211 | 211 | if ($ranges[0] < $minOffset) { // case: bytes=500-700,601-999 |
| 212 | 212 | $ranges[0] = $minOffset; |
| 213 | 213 | } |
| 214 | - if ($ind > 0 && $rangeArray[$ind-1]['to']+1 == $ranges[0]) { // case: bytes=500-600,601-999 |
|
| 214 | + if ($ind > 0 && $rangeArray[$ind - 1]['to'] + 1 == $ranges[0]) { // case: bytes=500-600,601-999 |
|
| 215 | 215 | $ind--; |
| 216 | 216 | $ranges[0] = $rangeArray[$ind]['from']; |
| 217 | 217 | } |
@@ -220,9 +220,9 @@ discard block |
||
| 220 | 220 | if (is_numeric($ranges[0]) && is_numeric($ranges[1]) && $ranges[0] < $fileSize && $ranges[0] <= $ranges[1]) { |
| 221 | 221 | // case: x-x |
| 222 | 222 | if ($ranges[1] >= $fileSize) { |
| 223 | - $ranges[1] = $fileSize-1; |
|
| 223 | + $ranges[1] = $fileSize - 1; |
|
| 224 | 224 | } |
| 225 | - $rangeArray[$ind++] = array( 'from' => $ranges[0], 'to' => $ranges[1], 'size' => $fileSize ); |
|
| 225 | + $rangeArray[$ind++] = array('from' => $ranges[0], 'to' => $ranges[1], 'size' => $fileSize); |
|
| 226 | 226 | $minOffset = $ranges[1] + 1; |
| 227 | 227 | if ($minOffset >= $fileSize) { |
| 228 | 228 | break; |
@@ -230,7 +230,7 @@ discard block |
||
| 230 | 230 | } |
| 231 | 231 | elseif (is_numeric($ranges[0]) && $ranges[0] < $fileSize) { |
| 232 | 232 | // case: x- |
| 233 | - $rangeArray[$ind++] = array( 'from' => $ranges[0], 'to' => $fileSize-1, 'size' => $fileSize ); |
|
| 233 | + $rangeArray[$ind++] = array('from' => $ranges[0], 'to' => $fileSize - 1, 'size' => $fileSize); |
|
| 234 | 234 | break; |
| 235 | 235 | } |
| 236 | 236 | elseif (is_numeric($ranges[1])) { |
@@ -238,7 +238,7 @@ discard block |
||
| 238 | 238 | if ($ranges[1] > $fileSize) { |
| 239 | 239 | $ranges[1] = $fileSize; |
| 240 | 240 | } |
| 241 | - $rangeArray[$ind++] = array( 'from' => $fileSize-$ranges[1], 'to' => $fileSize-1, 'size' => $fileSize ); |
|
| 241 | + $rangeArray[$ind++] = array('from' => $fileSize - $ranges[1], 'to' => $fileSize - 1, 'size' => $fileSize); |
|
| 242 | 242 | break; |
| 243 | 243 | } |
| 244 | 244 | } |
@@ -252,7 +252,7 @@ discard block |
||
| 252 | 252 | * @param array $params ; 'head' boolean to only send header of the request ; 'range' http range header |
| 253 | 253 | */ |
| 254 | 254 | private static function getSingleFile($view, $dir, $name, $params) { |
| 255 | - $filename = $dir . '/' . $name; |
|
| 255 | + $filename = $dir.'/'.$name; |
|
| 256 | 256 | OC_Util::obEnd(); |
| 257 | 257 | $view->lockFile($filename, ILockingProvider::LOCK_SHARED); |
| 258 | 258 | |
@@ -318,17 +318,17 @@ discard block |
||
| 318 | 318 | */ |
| 319 | 319 | public static function lockFiles($view, $dir, $files) { |
| 320 | 320 | if (!is_array($files)) { |
| 321 | - $file = $dir . '/' . $files; |
|
| 321 | + $file = $dir.'/'.$files; |
|
| 322 | 322 | $files = [$file]; |
| 323 | 323 | } |
| 324 | 324 | foreach ($files as $file) { |
| 325 | - $file = $dir . '/' . $file; |
|
| 325 | + $file = $dir.'/'.$file; |
|
| 326 | 326 | $view->lockFile($file, ILockingProvider::LOCK_SHARED); |
| 327 | 327 | if ($view->is_dir($file)) { |
| 328 | 328 | $contents = $view->getDirectoryContent($file); |
| 329 | 329 | $contents = array_map(function($fileInfo) use ($file) { |
| 330 | 330 | /** @var \OCP\Files\FileInfo $fileInfo */ |
| 331 | - return $file . '/' . $fileInfo->getName(); |
|
| 331 | + return $file.'/'.$fileInfo->getName(); |
|
| 332 | 332 | }, $contents); |
| 333 | 333 | self::lockFiles($view, $dir, $contents); |
| 334 | 334 | } |
@@ -344,7 +344,7 @@ discard block |
||
| 344 | 344 | */ |
| 345 | 345 | public static function setUploadLimit($size, $files = []) { |
| 346 | 346 | //don't allow user to break his config |
| 347 | - $size = (int)$size; |
|
| 347 | + $size = (int) $size; |
|
| 348 | 348 | if ($size < self::UPLOAD_MIN_LIMIT_BYTES) { |
| 349 | 349 | return false; |
| 350 | 350 | } |
@@ -357,8 +357,8 @@ discard block |
||
| 357 | 357 | |
| 358 | 358 | // default locations if not overridden by $files |
| 359 | 359 | $files = array_merge([ |
| 360 | - '.htaccess' => OC::$SERVERROOT . '/.htaccess', |
|
| 361 | - '.user.ini' => OC::$SERVERROOT . '/.user.ini' |
|
| 360 | + '.htaccess' => OC::$SERVERROOT.'/.htaccess', |
|
| 361 | + '.user.ini' => OC::$SERVERROOT.'/.user.ini' |
|
| 362 | 362 | ], $files); |
| 363 | 363 | |
| 364 | 364 | $updateFiles = [ |
@@ -379,7 +379,7 @@ discard block |
||
| 379 | 379 | $handle = @fopen($filename, 'r+'); |
| 380 | 380 | if (!$handle) { |
| 381 | 381 | \OCP\Util::writeLog('files', |
| 382 | - 'Can\'t write upload limit to ' . $filename . '. Please check the file permissions', |
|
| 382 | + 'Can\'t write upload limit to '.$filename.'. Please check the file permissions', |
|
| 383 | 383 | \OCP\Util::WARN); |
| 384 | 384 | $success = false; |
| 385 | 385 | continue; // try to update as many files as possible |
@@ -399,7 +399,7 @@ discard block |
||
| 399 | 399 | $content = $newContent; |
| 400 | 400 | } |
| 401 | 401 | if ($hasReplaced === 0) { |
| 402 | - $content .= "\n" . $setting; |
|
| 402 | + $content .= "\n".$setting; |
|
| 403 | 403 | } |
| 404 | 404 | } |
| 405 | 405 | |
@@ -430,12 +430,12 @@ discard block |
||
| 430 | 430 | } |
| 431 | 431 | if ($getType === self::ZIP_FILES) { |
| 432 | 432 | foreach ($files as $file) { |
| 433 | - $file = $dir . '/' . $file; |
|
| 433 | + $file = $dir.'/'.$file; |
|
| 434 | 434 | $view->unlockFile($file, ILockingProvider::LOCK_SHARED); |
| 435 | 435 | } |
| 436 | 436 | } |
| 437 | 437 | if ($getType === self::ZIP_DIR) { |
| 438 | - $file = $dir . '/' . $files; |
|
| 438 | + $file = $dir.'/'.$files; |
|
| 439 | 439 | $view->unlockFile($file, ILockingProvider::LOCK_SHARED); |
| 440 | 440 | } |
| 441 | 441 | } |
@@ -36,7 +36,7 @@ discard block |
||
| 36 | 36 | * @param string $string the string which will be escaped and printed |
| 37 | 37 | */ |
| 38 | 38 | function p($string) { |
| 39 | - print(\OCP\Util::sanitizeHTML($string)); |
|
| 39 | + print(\OCP\Util::sanitizeHTML($string)); |
|
| 40 | 40 | } |
| 41 | 41 | |
| 42 | 42 | |
@@ -46,14 +46,14 @@ discard block |
||
| 46 | 46 | * @param string $opts, additional optional options |
| 47 | 47 | */ |
| 48 | 48 | function emit_css_tag($href, $opts = '') { |
| 49 | - $s='<link rel="stylesheet"'; |
|
| 50 | - if (!empty($href)) { |
|
| 51 | - $s.=' href="' . $href .'"'; |
|
| 52 | - } |
|
| 53 | - if (!empty($opts)) { |
|
| 54 | - $s.=' '.$opts; |
|
| 55 | - } |
|
| 56 | - print_unescaped($s.">\n"); |
|
| 49 | + $s='<link rel="stylesheet"'; |
|
| 50 | + if (!empty($href)) { |
|
| 51 | + $s.=' href="' . $href .'"'; |
|
| 52 | + } |
|
| 53 | + if (!empty($opts)) { |
|
| 54 | + $s.=' '.$opts; |
|
| 55 | + } |
|
| 56 | + print_unescaped($s.">\n"); |
|
| 57 | 57 | } |
| 58 | 58 | |
| 59 | 59 | /** |
@@ -61,12 +61,12 @@ discard block |
||
| 61 | 61 | * @param array $obj all the script information from template |
| 62 | 62 | */ |
| 63 | 63 | function emit_css_loading_tags($obj) { |
| 64 | - foreach($obj['cssfiles'] as $css) { |
|
| 65 | - emit_css_tag($css); |
|
| 66 | - } |
|
| 67 | - foreach($obj['printcssfiles'] as $css) { |
|
| 68 | - emit_css_tag($css, 'media="print"'); |
|
| 69 | - } |
|
| 64 | + foreach($obj['cssfiles'] as $css) { |
|
| 65 | + emit_css_tag($css); |
|
| 66 | + } |
|
| 67 | + foreach($obj['printcssfiles'] as $css) { |
|
| 68 | + emit_css_tag($css, 'media="print"'); |
|
| 69 | + } |
|
| 70 | 70 | } |
| 71 | 71 | |
| 72 | 72 | /** |
@@ -75,20 +75,20 @@ discard block |
||
| 75 | 75 | * @param string $script_content the inline script content, ignored when empty |
| 76 | 76 | */ |
| 77 | 77 | function emit_script_tag($src, $script_content='') { |
| 78 | - $defer_str=' defer'; |
|
| 79 | - $s='<script nonce="' . \OC::$server->getContentSecurityPolicyNonceManager()->getNonce() . '"'; |
|
| 80 | - if (!empty($src)) { |
|
| 81 | - // emit script tag for deferred loading from $src |
|
| 82 | - $s.=$defer_str.' src="' . $src .'">'; |
|
| 83 | - } else if (!empty($script_content)) { |
|
| 84 | - // emit script tag for inline script from $script_content without defer (see MDN) |
|
| 85 | - $s.=">\n".$script_content."\n"; |
|
| 86 | - } else { |
|
| 87 | - // no $src nor $src_content, really useless empty tag |
|
| 88 | - $s.='>'; |
|
| 89 | - } |
|
| 90 | - $s.='</script>'; |
|
| 91 | - print_unescaped($s."\n"); |
|
| 78 | + $defer_str=' defer'; |
|
| 79 | + $s='<script nonce="' . \OC::$server->getContentSecurityPolicyNonceManager()->getNonce() . '"'; |
|
| 80 | + if (!empty($src)) { |
|
| 81 | + // emit script tag for deferred loading from $src |
|
| 82 | + $s.=$defer_str.' src="' . $src .'">'; |
|
| 83 | + } else if (!empty($script_content)) { |
|
| 84 | + // emit script tag for inline script from $script_content without defer (see MDN) |
|
| 85 | + $s.=">\n".$script_content."\n"; |
|
| 86 | + } else { |
|
| 87 | + // no $src nor $src_content, really useless empty tag |
|
| 88 | + $s.='>'; |
|
| 89 | + } |
|
| 90 | + $s.='</script>'; |
|
| 91 | + print_unescaped($s."\n"); |
|
| 92 | 92 | } |
| 93 | 93 | |
| 94 | 94 | /** |
@@ -96,12 +96,12 @@ discard block |
||
| 96 | 96 | * @param array $obj all the script information from template |
| 97 | 97 | */ |
| 98 | 98 | function emit_script_loading_tags($obj) { |
| 99 | - foreach($obj['jsfiles'] as $jsfile) { |
|
| 100 | - emit_script_tag($jsfile, ''); |
|
| 101 | - } |
|
| 102 | - if (!empty($obj['inline_ocjs'])) { |
|
| 103 | - emit_script_tag('', $obj['inline_ocjs']); |
|
| 104 | - } |
|
| 99 | + foreach($obj['jsfiles'] as $jsfile) { |
|
| 100 | + emit_script_tag($jsfile, ''); |
|
| 101 | + } |
|
| 102 | + if (!empty($obj['inline_ocjs'])) { |
|
| 103 | + emit_script_tag('', $obj['inline_ocjs']); |
|
| 104 | + } |
|
| 105 | 105 | } |
| 106 | 106 | |
| 107 | 107 | /** |
@@ -110,7 +110,7 @@ discard block |
||
| 110 | 110 | * @param string|array $string the string which will be printed as it is |
| 111 | 111 | */ |
| 112 | 112 | function print_unescaped($string) { |
| 113 | - print($string); |
|
| 113 | + print($string); |
|
| 114 | 114 | } |
| 115 | 115 | |
| 116 | 116 | /** |
@@ -120,13 +120,13 @@ discard block |
||
| 120 | 120 | * if an array is given it will add all scripts |
| 121 | 121 | */ |
| 122 | 122 | function script($app, $file = null) { |
| 123 | - if(is_array($file)) { |
|
| 124 | - foreach($file as $f) { |
|
| 125 | - OC_Util::addScript($app, $f); |
|
| 126 | - } |
|
| 127 | - } else { |
|
| 128 | - OC_Util::addScript($app, $file); |
|
| 129 | - } |
|
| 123 | + if(is_array($file)) { |
|
| 124 | + foreach($file as $f) { |
|
| 125 | + OC_Util::addScript($app, $f); |
|
| 126 | + } |
|
| 127 | + } else { |
|
| 128 | + OC_Util::addScript($app, $file); |
|
| 129 | + } |
|
| 130 | 130 | } |
| 131 | 131 | |
| 132 | 132 | /** |
@@ -136,13 +136,13 @@ discard block |
||
| 136 | 136 | * if an array is given it will add all scripts |
| 137 | 137 | */ |
| 138 | 138 | function vendor_script($app, $file = null) { |
| 139 | - if(is_array($file)) { |
|
| 140 | - foreach($file as $f) { |
|
| 141 | - OC_Util::addVendorScript($app, $f); |
|
| 142 | - } |
|
| 143 | - } else { |
|
| 144 | - OC_Util::addVendorScript($app, $file); |
|
| 145 | - } |
|
| 139 | + if(is_array($file)) { |
|
| 140 | + foreach($file as $f) { |
|
| 141 | + OC_Util::addVendorScript($app, $f); |
|
| 142 | + } |
|
| 143 | + } else { |
|
| 144 | + OC_Util::addVendorScript($app, $file); |
|
| 145 | + } |
|
| 146 | 146 | } |
| 147 | 147 | |
| 148 | 148 | /** |
@@ -152,13 +152,13 @@ discard block |
||
| 152 | 152 | * if an array is given it will add all styles |
| 153 | 153 | */ |
| 154 | 154 | function style($app, $file = null) { |
| 155 | - if(is_array($file)) { |
|
| 156 | - foreach($file as $f) { |
|
| 157 | - OC_Util::addStyle($app, $f); |
|
| 158 | - } |
|
| 159 | - } else { |
|
| 160 | - OC_Util::addStyle($app, $file); |
|
| 161 | - } |
|
| 155 | + if(is_array($file)) { |
|
| 156 | + foreach($file as $f) { |
|
| 157 | + OC_Util::addStyle($app, $f); |
|
| 158 | + } |
|
| 159 | + } else { |
|
| 160 | + OC_Util::addStyle($app, $file); |
|
| 161 | + } |
|
| 162 | 162 | } |
| 163 | 163 | |
| 164 | 164 | /** |
@@ -168,13 +168,13 @@ discard block |
||
| 168 | 168 | * if an array is given it will add all styles |
| 169 | 169 | */ |
| 170 | 170 | function vendor_style($app, $file = null) { |
| 171 | - if(is_array($file)) { |
|
| 172 | - foreach($file as $f) { |
|
| 173 | - OC_Util::addVendorStyle($app, $f); |
|
| 174 | - } |
|
| 175 | - } else { |
|
| 176 | - OC_Util::addVendorStyle($app, $file); |
|
| 177 | - } |
|
| 171 | + if(is_array($file)) { |
|
| 172 | + foreach($file as $f) { |
|
| 173 | + OC_Util::addVendorStyle($app, $f); |
|
| 174 | + } |
|
| 175 | + } else { |
|
| 176 | + OC_Util::addVendorStyle($app, $file); |
|
| 177 | + } |
|
| 178 | 178 | } |
| 179 | 179 | |
| 180 | 180 | /** |
@@ -183,7 +183,7 @@ discard block |
||
| 183 | 183 | * if an array is given it will add all styles |
| 184 | 184 | */ |
| 185 | 185 | function translation($app) { |
| 186 | - OC_Util::addTranslations($app); |
|
| 186 | + OC_Util::addTranslations($app); |
|
| 187 | 187 | } |
| 188 | 188 | |
| 189 | 189 | /** |
@@ -193,15 +193,15 @@ discard block |
||
| 193 | 193 | * if an array is given it will add all components |
| 194 | 194 | */ |
| 195 | 195 | function component($app, $file) { |
| 196 | - if(is_array($file)) { |
|
| 197 | - foreach($file as $f) { |
|
| 198 | - $url = link_to($app, 'component/' . $f . '.html'); |
|
| 199 | - OC_Util::addHeader('link', array('rel' => 'import', 'href' => $url)); |
|
| 200 | - } |
|
| 201 | - } else { |
|
| 202 | - $url = link_to($app, 'component/' . $file . '.html'); |
|
| 203 | - OC_Util::addHeader('link', array('rel' => 'import', 'href' => $url)); |
|
| 204 | - } |
|
| 196 | + if(is_array($file)) { |
|
| 197 | + foreach($file as $f) { |
|
| 198 | + $url = link_to($app, 'component/' . $f . '.html'); |
|
| 199 | + OC_Util::addHeader('link', array('rel' => 'import', 'href' => $url)); |
|
| 200 | + } |
|
| 201 | + } else { |
|
| 202 | + $url = link_to($app, 'component/' . $file . '.html'); |
|
| 203 | + OC_Util::addHeader('link', array('rel' => 'import', 'href' => $url)); |
|
| 204 | + } |
|
| 205 | 205 | } |
| 206 | 206 | |
| 207 | 207 | /** |
@@ -214,7 +214,7 @@ discard block |
||
| 214 | 214 | * For further information have a look at \OCP\IURLGenerator::linkTo |
| 215 | 215 | */ |
| 216 | 216 | function link_to( $app, $file, $args = array() ) { |
| 217 | - return \OC::$server->getURLGenerator()->linkTo($app, $file, $args); |
|
| 217 | + return \OC::$server->getURLGenerator()->linkTo($app, $file, $args); |
|
| 218 | 218 | } |
| 219 | 219 | |
| 220 | 220 | /** |
@@ -222,7 +222,7 @@ discard block |
||
| 222 | 222 | * @return string url to the online documentation |
| 223 | 223 | */ |
| 224 | 224 | function link_to_docs($key) { |
| 225 | - return \OC::$server->getURLGenerator()->linkToDocs($key); |
|
| 225 | + return \OC::$server->getURLGenerator()->linkToDocs($key); |
|
| 226 | 226 | } |
| 227 | 227 | |
| 228 | 228 | /** |
@@ -234,7 +234,7 @@ discard block |
||
| 234 | 234 | * For further information have a look at \OCP\IURLGenerator::imagePath |
| 235 | 235 | */ |
| 236 | 236 | function image_path( $app, $image ) { |
| 237 | - return \OC::$server->getURLGenerator()->imagePath( $app, $image ); |
|
| 237 | + return \OC::$server->getURLGenerator()->imagePath( $app, $image ); |
|
| 238 | 238 | } |
| 239 | 239 | |
| 240 | 240 | /** |
@@ -243,7 +243,7 @@ discard block |
||
| 243 | 243 | * @return string link to the image |
| 244 | 244 | */ |
| 245 | 245 | function mimetype_icon( $mimetype ) { |
| 246 | - return \OC::$server->getMimeTypeDetector()->mimeTypeIcon( $mimetype ); |
|
| 246 | + return \OC::$server->getMimeTypeDetector()->mimeTypeIcon( $mimetype ); |
|
| 247 | 247 | } |
| 248 | 248 | |
| 249 | 249 | /** |
@@ -253,7 +253,7 @@ discard block |
||
| 253 | 253 | * @return string link to the preview |
| 254 | 254 | */ |
| 255 | 255 | function preview_icon( $path ) { |
| 256 | - return \OC::$server->getURLGenerator()->linkToRoute('core.Preview.getPreview', ['x' => 32, 'y' => 32, 'file' => $path]); |
|
| 256 | + return \OC::$server->getURLGenerator()->linkToRoute('core.Preview.getPreview', ['x' => 32, 'y' => 32, 'file' => $path]); |
|
| 257 | 257 | } |
| 258 | 258 | |
| 259 | 259 | /** |
@@ -262,7 +262,7 @@ discard block |
||
| 262 | 262 | * @return string |
| 263 | 263 | */ |
| 264 | 264 | function publicPreview_icon ( $path, $token ) { |
| 265 | - return \OC::$server->getURLGenerator()->linkToRoute('files_sharing.PublicPreview.getPreview', ['x' => 32, 'y' => 32, 'file' => $path, 't' => $token]); |
|
| 265 | + return \OC::$server->getURLGenerator()->linkToRoute('files_sharing.PublicPreview.getPreview', ['x' => 32, 'y' => 32, 'file' => $path, 't' => $token]); |
|
| 266 | 266 | } |
| 267 | 267 | |
| 268 | 268 | /** |
@@ -273,7 +273,7 @@ discard block |
||
| 273 | 273 | * For further information have a look at OC_Helper::humanFileSize |
| 274 | 274 | */ |
| 275 | 275 | function human_file_size( $bytes ) { |
| 276 | - return OC_Helper::humanFileSize( $bytes ); |
|
| 276 | + return OC_Helper::humanFileSize( $bytes ); |
|
| 277 | 277 | } |
| 278 | 278 | |
| 279 | 279 | /** |
@@ -282,9 +282,9 @@ discard block |
||
| 282 | 282 | * @return int timestamp without time value |
| 283 | 283 | */ |
| 284 | 284 | function strip_time($timestamp){ |
| 285 | - $date = new \DateTime("@{$timestamp}"); |
|
| 286 | - $date->setTime(0, 0, 0); |
|
| 287 | - return (int)$date->format('U'); |
|
| 285 | + $date = new \DateTime("@{$timestamp}"); |
|
| 286 | + $date->setTime(0, 0, 0); |
|
| 287 | + return (int)$date->format('U'); |
|
| 288 | 288 | } |
| 289 | 289 | |
| 290 | 290 | /** |
@@ -296,39 +296,39 @@ discard block |
||
| 296 | 296 | * @return string timestamp |
| 297 | 297 | */ |
| 298 | 298 | function relative_modified_date($timestamp, $fromTime = null, $dateOnly = false) { |
| 299 | - /** @var \OC\DateTimeFormatter $formatter */ |
|
| 300 | - $formatter = \OC::$server->query('DateTimeFormatter'); |
|
| 299 | + /** @var \OC\DateTimeFormatter $formatter */ |
|
| 300 | + $formatter = \OC::$server->query('DateTimeFormatter'); |
|
| 301 | 301 | |
| 302 | - if ($dateOnly){ |
|
| 303 | - return $formatter->formatDateSpan($timestamp, $fromTime); |
|
| 304 | - } |
|
| 305 | - return $formatter->formatTimeSpan($timestamp, $fromTime); |
|
| 302 | + if ($dateOnly){ |
|
| 303 | + return $formatter->formatDateSpan($timestamp, $fromTime); |
|
| 304 | + } |
|
| 305 | + return $formatter->formatTimeSpan($timestamp, $fromTime); |
|
| 306 | 306 | } |
| 307 | 307 | |
| 308 | 308 | function html_select_options($options, $selected, $params=array()) { |
| 309 | - if (!is_array($selected)) { |
|
| 310 | - $selected=array($selected); |
|
| 311 | - } |
|
| 312 | - if (isset($params['combine']) && $params['combine']) { |
|
| 313 | - $options = array_combine($options, $options); |
|
| 314 | - } |
|
| 315 | - $value_name = $label_name = false; |
|
| 316 | - if (isset($params['value'])) { |
|
| 317 | - $value_name = $params['value']; |
|
| 318 | - } |
|
| 319 | - if (isset($params['label'])) { |
|
| 320 | - $label_name = $params['label']; |
|
| 321 | - } |
|
| 322 | - $html = ''; |
|
| 323 | - foreach($options as $value => $label) { |
|
| 324 | - if ($value_name && is_array($label)) { |
|
| 325 | - $value = $label[$value_name]; |
|
| 326 | - } |
|
| 327 | - if ($label_name && is_array($label)) { |
|
| 328 | - $label = $label[$label_name]; |
|
| 329 | - } |
|
| 330 | - $select = in_array($value, $selected) ? ' selected="selected"' : ''; |
|
| 331 | - $html .= '<option value="' . \OCP\Util::sanitizeHTML($value) . '"' . $select . '>' . \OCP\Util::sanitizeHTML($label) . '</option>'."\n"; |
|
| 332 | - } |
|
| 333 | - return $html; |
|
| 309 | + if (!is_array($selected)) { |
|
| 310 | + $selected=array($selected); |
|
| 311 | + } |
|
| 312 | + if (isset($params['combine']) && $params['combine']) { |
|
| 313 | + $options = array_combine($options, $options); |
|
| 314 | + } |
|
| 315 | + $value_name = $label_name = false; |
|
| 316 | + if (isset($params['value'])) { |
|
| 317 | + $value_name = $params['value']; |
|
| 318 | + } |
|
| 319 | + if (isset($params['label'])) { |
|
| 320 | + $label_name = $params['label']; |
|
| 321 | + } |
|
| 322 | + $html = ''; |
|
| 323 | + foreach($options as $value => $label) { |
|
| 324 | + if ($value_name && is_array($label)) { |
|
| 325 | + $value = $label[$value_name]; |
|
| 326 | + } |
|
| 327 | + if ($label_name && is_array($label)) { |
|
| 328 | + $label = $label[$label_name]; |
|
| 329 | + } |
|
| 330 | + $select = in_array($value, $selected) ? ' selected="selected"' : ''; |
|
| 331 | + $html .= '<option value="' . \OCP\Util::sanitizeHTML($value) . '"' . $select . '>' . \OCP\Util::sanitizeHTML($label) . '</option>'."\n"; |
|
| 332 | + } |
|
| 333 | + return $html; |
|
| 334 | 334 | } |
@@ -46,12 +46,12 @@ discard block |
||
| 46 | 46 | * @param string $opts, additional optional options |
| 47 | 47 | */ |
| 48 | 48 | function emit_css_tag($href, $opts = '') { |
| 49 | - $s='<link rel="stylesheet"'; |
|
| 49 | + $s = '<link rel="stylesheet"'; |
|
| 50 | 50 | if (!empty($href)) { |
| 51 | - $s.=' href="' . $href .'"'; |
|
| 51 | + $s .= ' href="'.$href.'"'; |
|
| 52 | 52 | } |
| 53 | 53 | if (!empty($opts)) { |
| 54 | - $s.=' '.$opts; |
|
| 54 | + $s .= ' '.$opts; |
|
| 55 | 55 | } |
| 56 | 56 | print_unescaped($s.">\n"); |
| 57 | 57 | } |
@@ -61,10 +61,10 @@ discard block |
||
| 61 | 61 | * @param array $obj all the script information from template |
| 62 | 62 | */ |
| 63 | 63 | function emit_css_loading_tags($obj) { |
| 64 | - foreach($obj['cssfiles'] as $css) { |
|
| 64 | + foreach ($obj['cssfiles'] as $css) { |
|
| 65 | 65 | emit_css_tag($css); |
| 66 | 66 | } |
| 67 | - foreach($obj['printcssfiles'] as $css) { |
|
| 67 | + foreach ($obj['printcssfiles'] as $css) { |
|
| 68 | 68 | emit_css_tag($css, 'media="print"'); |
| 69 | 69 | } |
| 70 | 70 | } |
@@ -74,20 +74,20 @@ discard block |
||
| 74 | 74 | * @param string $src the source URL, ignored when empty |
| 75 | 75 | * @param string $script_content the inline script content, ignored when empty |
| 76 | 76 | */ |
| 77 | -function emit_script_tag($src, $script_content='') { |
|
| 78 | - $defer_str=' defer'; |
|
| 79 | - $s='<script nonce="' . \OC::$server->getContentSecurityPolicyNonceManager()->getNonce() . '"'; |
|
| 77 | +function emit_script_tag($src, $script_content = '') { |
|
| 78 | + $defer_str = ' defer'; |
|
| 79 | + $s = '<script nonce="'.\OC::$server->getContentSecurityPolicyNonceManager()->getNonce().'"'; |
|
| 80 | 80 | if (!empty($src)) { |
| 81 | 81 | // emit script tag for deferred loading from $src |
| 82 | - $s.=$defer_str.' src="' . $src .'">'; |
|
| 82 | + $s .= $defer_str.' src="'.$src.'">'; |
|
| 83 | 83 | } else if (!empty($script_content)) { |
| 84 | 84 | // emit script tag for inline script from $script_content without defer (see MDN) |
| 85 | - $s.=">\n".$script_content."\n"; |
|
| 85 | + $s .= ">\n".$script_content."\n"; |
|
| 86 | 86 | } else { |
| 87 | 87 | // no $src nor $src_content, really useless empty tag |
| 88 | - $s.='>'; |
|
| 88 | + $s .= '>'; |
|
| 89 | 89 | } |
| 90 | - $s.='</script>'; |
|
| 90 | + $s .= '</script>'; |
|
| 91 | 91 | print_unescaped($s."\n"); |
| 92 | 92 | } |
| 93 | 93 | |
@@ -96,7 +96,7 @@ discard block |
||
| 96 | 96 | * @param array $obj all the script information from template |
| 97 | 97 | */ |
| 98 | 98 | function emit_script_loading_tags($obj) { |
| 99 | - foreach($obj['jsfiles'] as $jsfile) { |
|
| 99 | + foreach ($obj['jsfiles'] as $jsfile) { |
|
| 100 | 100 | emit_script_tag($jsfile, ''); |
| 101 | 101 | } |
| 102 | 102 | if (!empty($obj['inline_ocjs'])) { |
@@ -120,8 +120,8 @@ discard block |
||
| 120 | 120 | * if an array is given it will add all scripts |
| 121 | 121 | */ |
| 122 | 122 | function script($app, $file = null) { |
| 123 | - if(is_array($file)) { |
|
| 124 | - foreach($file as $f) { |
|
| 123 | + if (is_array($file)) { |
|
| 124 | + foreach ($file as $f) { |
|
| 125 | 125 | OC_Util::addScript($app, $f); |
| 126 | 126 | } |
| 127 | 127 | } else { |
@@ -136,8 +136,8 @@ discard block |
||
| 136 | 136 | * if an array is given it will add all scripts |
| 137 | 137 | */ |
| 138 | 138 | function vendor_script($app, $file = null) { |
| 139 | - if(is_array($file)) { |
|
| 140 | - foreach($file as $f) { |
|
| 139 | + if (is_array($file)) { |
|
| 140 | + foreach ($file as $f) { |
|
| 141 | 141 | OC_Util::addVendorScript($app, $f); |
| 142 | 142 | } |
| 143 | 143 | } else { |
@@ -152,8 +152,8 @@ discard block |
||
| 152 | 152 | * if an array is given it will add all styles |
| 153 | 153 | */ |
| 154 | 154 | function style($app, $file = null) { |
| 155 | - if(is_array($file)) { |
|
| 156 | - foreach($file as $f) { |
|
| 155 | + if (is_array($file)) { |
|
| 156 | + foreach ($file as $f) { |
|
| 157 | 157 | OC_Util::addStyle($app, $f); |
| 158 | 158 | } |
| 159 | 159 | } else { |
@@ -168,8 +168,8 @@ discard block |
||
| 168 | 168 | * if an array is given it will add all styles |
| 169 | 169 | */ |
| 170 | 170 | function vendor_style($app, $file = null) { |
| 171 | - if(is_array($file)) { |
|
| 172 | - foreach($file as $f) { |
|
| 171 | + if (is_array($file)) { |
|
| 172 | + foreach ($file as $f) { |
|
| 173 | 173 | OC_Util::addVendorStyle($app, $f); |
| 174 | 174 | } |
| 175 | 175 | } else { |
@@ -193,13 +193,13 @@ discard block |
||
| 193 | 193 | * if an array is given it will add all components |
| 194 | 194 | */ |
| 195 | 195 | function component($app, $file) { |
| 196 | - if(is_array($file)) { |
|
| 197 | - foreach($file as $f) { |
|
| 198 | - $url = link_to($app, 'component/' . $f . '.html'); |
|
| 196 | + if (is_array($file)) { |
|
| 197 | + foreach ($file as $f) { |
|
| 198 | + $url = link_to($app, 'component/'.$f.'.html'); |
|
| 199 | 199 | OC_Util::addHeader('link', array('rel' => 'import', 'href' => $url)); |
| 200 | 200 | } |
| 201 | 201 | } else { |
| 202 | - $url = link_to($app, 'component/' . $file . '.html'); |
|
| 202 | + $url = link_to($app, 'component/'.$file.'.html'); |
|
| 203 | 203 | OC_Util::addHeader('link', array('rel' => 'import', 'href' => $url)); |
| 204 | 204 | } |
| 205 | 205 | } |
@@ -213,7 +213,7 @@ discard block |
||
| 213 | 213 | * |
| 214 | 214 | * For further information have a look at \OCP\IURLGenerator::linkTo |
| 215 | 215 | */ |
| 216 | -function link_to( $app, $file, $args = array() ) { |
|
| 216 | +function link_to($app, $file, $args = array()) { |
|
| 217 | 217 | return \OC::$server->getURLGenerator()->linkTo($app, $file, $args); |
| 218 | 218 | } |
| 219 | 219 | |
@@ -233,8 +233,8 @@ discard block |
||
| 233 | 233 | * |
| 234 | 234 | * For further information have a look at \OCP\IURLGenerator::imagePath |
| 235 | 235 | */ |
| 236 | -function image_path( $app, $image ) { |
|
| 237 | - return \OC::$server->getURLGenerator()->imagePath( $app, $image ); |
|
| 236 | +function image_path($app, $image) { |
|
| 237 | + return \OC::$server->getURLGenerator()->imagePath($app, $image); |
|
| 238 | 238 | } |
| 239 | 239 | |
| 240 | 240 | /** |
@@ -242,8 +242,8 @@ discard block |
||
| 242 | 242 | * @param string $mimetype mimetype |
| 243 | 243 | * @return string link to the image |
| 244 | 244 | */ |
| 245 | -function mimetype_icon( $mimetype ) { |
|
| 246 | - return \OC::$server->getMimeTypeDetector()->mimeTypeIcon( $mimetype ); |
|
| 245 | +function mimetype_icon($mimetype) { |
|
| 246 | + return \OC::$server->getMimeTypeDetector()->mimeTypeIcon($mimetype); |
|
| 247 | 247 | } |
| 248 | 248 | |
| 249 | 249 | /** |
@@ -252,7 +252,7 @@ discard block |
||
| 252 | 252 | * @param string $path path of file |
| 253 | 253 | * @return string link to the preview |
| 254 | 254 | */ |
| 255 | -function preview_icon( $path ) { |
|
| 255 | +function preview_icon($path) { |
|
| 256 | 256 | return \OC::$server->getURLGenerator()->linkToRoute('core.Preview.getPreview', ['x' => 32, 'y' => 32, 'file' => $path]); |
| 257 | 257 | } |
| 258 | 258 | |
@@ -261,7 +261,7 @@ discard block |
||
| 261 | 261 | * @param string $token |
| 262 | 262 | * @return string |
| 263 | 263 | */ |
| 264 | -function publicPreview_icon ( $path, $token ) { |
|
| 264 | +function publicPreview_icon($path, $token) { |
|
| 265 | 265 | return \OC::$server->getURLGenerator()->linkToRoute('files_sharing.PublicPreview.getPreview', ['x' => 32, 'y' => 32, 'file' => $path, 't' => $token]); |
| 266 | 266 | } |
| 267 | 267 | |
@@ -272,8 +272,8 @@ discard block |
||
| 272 | 272 | * |
| 273 | 273 | * For further information have a look at OC_Helper::humanFileSize |
| 274 | 274 | */ |
| 275 | -function human_file_size( $bytes ) { |
|
| 276 | - return OC_Helper::humanFileSize( $bytes ); |
|
| 275 | +function human_file_size($bytes) { |
|
| 276 | + return OC_Helper::humanFileSize($bytes); |
|
| 277 | 277 | } |
| 278 | 278 | |
| 279 | 279 | /** |
@@ -281,10 +281,10 @@ discard block |
||
| 281 | 281 | * @param int $timestamp UNIX timestamp to strip |
| 282 | 282 | * @return int timestamp without time value |
| 283 | 283 | */ |
| 284 | -function strip_time($timestamp){ |
|
| 284 | +function strip_time($timestamp) { |
|
| 285 | 285 | $date = new \DateTime("@{$timestamp}"); |
| 286 | 286 | $date->setTime(0, 0, 0); |
| 287 | - return (int)$date->format('U'); |
|
| 287 | + return (int) $date->format('U'); |
|
| 288 | 288 | } |
| 289 | 289 | |
| 290 | 290 | /** |
@@ -299,15 +299,15 @@ discard block |
||
| 299 | 299 | /** @var \OC\DateTimeFormatter $formatter */ |
| 300 | 300 | $formatter = \OC::$server->query('DateTimeFormatter'); |
| 301 | 301 | |
| 302 | - if ($dateOnly){ |
|
| 302 | + if ($dateOnly) { |
|
| 303 | 303 | return $formatter->formatDateSpan($timestamp, $fromTime); |
| 304 | 304 | } |
| 305 | 305 | return $formatter->formatTimeSpan($timestamp, $fromTime); |
| 306 | 306 | } |
| 307 | 307 | |
| 308 | -function html_select_options($options, $selected, $params=array()) { |
|
| 308 | +function html_select_options($options, $selected, $params = array()) { |
|
| 309 | 309 | if (!is_array($selected)) { |
| 310 | - $selected=array($selected); |
|
| 310 | + $selected = array($selected); |
|
| 311 | 311 | } |
| 312 | 312 | if (isset($params['combine']) && $params['combine']) { |
| 313 | 313 | $options = array_combine($options, $options); |
@@ -320,7 +320,7 @@ discard block |
||
| 320 | 320 | $label_name = $params['label']; |
| 321 | 321 | } |
| 322 | 322 | $html = ''; |
| 323 | - foreach($options as $value => $label) { |
|
| 323 | + foreach ($options as $value => $label) { |
|
| 324 | 324 | if ($value_name && is_array($label)) { |
| 325 | 325 | $value = $label[$value_name]; |
| 326 | 326 | } |
@@ -328,7 +328,7 @@ discard block |
||
| 328 | 328 | $label = $label[$label_name]; |
| 329 | 329 | } |
| 330 | 330 | $select = in_array($value, $selected) ? ' selected="selected"' : ''; |
| 331 | - $html .= '<option value="' . \OCP\Util::sanitizeHTML($value) . '"' . $select . '>' . \OCP\Util::sanitizeHTML($label) . '</option>'."\n"; |
|
| 331 | + $html .= '<option value="'.\OCP\Util::sanitizeHTML($value).'"'.$select.'>'.\OCP\Util::sanitizeHTML($label).'</option>'."\n"; |
|
| 332 | 332 | } |
| 333 | 333 | return $html; |
| 334 | 334 | } |
@@ -49,607 +49,607 @@ |
||
| 49 | 49 | * Collection of useful functions |
| 50 | 50 | */ |
| 51 | 51 | class OC_Helper { |
| 52 | - private static $templateManager; |
|
| 53 | - |
|
| 54 | - /** |
|
| 55 | - * Creates an absolute url for public use |
|
| 56 | - * @param string $service id |
|
| 57 | - * @param bool $add_slash |
|
| 58 | - * @return string the url |
|
| 59 | - * |
|
| 60 | - * Returns a absolute url to the given service. |
|
| 61 | - */ |
|
| 62 | - public static function linkToPublic($service, $add_slash = false) { |
|
| 63 | - if ($service === 'files') { |
|
| 64 | - $url = OC::$server->getURLGenerator()->getAbsoluteURL('/s'); |
|
| 65 | - } else { |
|
| 66 | - $url = OC::$server->getURLGenerator()->getAbsoluteURL(OC::$server->getURLGenerator()->linkTo('', 'public.php').'?service='.$service); |
|
| 67 | - } |
|
| 68 | - return $url . (($add_slash && $service[strlen($service) - 1] != '/') ? '/' : ''); |
|
| 69 | - } |
|
| 70 | - |
|
| 71 | - /** |
|
| 72 | - * Make a human file size |
|
| 73 | - * @param int $bytes file size in bytes |
|
| 74 | - * @return string a human readable file size |
|
| 75 | - * |
|
| 76 | - * Makes 2048 to 2 kB. |
|
| 77 | - */ |
|
| 78 | - public static function humanFileSize($bytes) { |
|
| 79 | - if ($bytes < 0) { |
|
| 80 | - return "?"; |
|
| 81 | - } |
|
| 82 | - if ($bytes < 1024) { |
|
| 83 | - return "$bytes B"; |
|
| 84 | - } |
|
| 85 | - $bytes = round($bytes / 1024, 0); |
|
| 86 | - if ($bytes < 1024) { |
|
| 87 | - return "$bytes KB"; |
|
| 88 | - } |
|
| 89 | - $bytes = round($bytes / 1024, 1); |
|
| 90 | - if ($bytes < 1024) { |
|
| 91 | - return "$bytes MB"; |
|
| 92 | - } |
|
| 93 | - $bytes = round($bytes / 1024, 1); |
|
| 94 | - if ($bytes < 1024) { |
|
| 95 | - return "$bytes GB"; |
|
| 96 | - } |
|
| 97 | - $bytes = round($bytes / 1024, 1); |
|
| 98 | - if ($bytes < 1024) { |
|
| 99 | - return "$bytes TB"; |
|
| 100 | - } |
|
| 101 | - |
|
| 102 | - $bytes = round($bytes / 1024, 1); |
|
| 103 | - return "$bytes PB"; |
|
| 104 | - } |
|
| 105 | - |
|
| 106 | - /** |
|
| 107 | - * Make a php file size |
|
| 108 | - * @param int $bytes file size in bytes |
|
| 109 | - * @return string a php parseable file size |
|
| 110 | - * |
|
| 111 | - * Makes 2048 to 2k and 2^41 to 2048G |
|
| 112 | - */ |
|
| 113 | - public static function phpFileSize($bytes) { |
|
| 114 | - if ($bytes < 0) { |
|
| 115 | - return "?"; |
|
| 116 | - } |
|
| 117 | - if ($bytes < 1024) { |
|
| 118 | - return $bytes . "B"; |
|
| 119 | - } |
|
| 120 | - $bytes = round($bytes / 1024, 1); |
|
| 121 | - if ($bytes < 1024) { |
|
| 122 | - return $bytes . "K"; |
|
| 123 | - } |
|
| 124 | - $bytes = round($bytes / 1024, 1); |
|
| 125 | - if ($bytes < 1024) { |
|
| 126 | - return $bytes . "M"; |
|
| 127 | - } |
|
| 128 | - $bytes = round($bytes / 1024, 1); |
|
| 129 | - return $bytes . "G"; |
|
| 130 | - } |
|
| 131 | - |
|
| 132 | - /** |
|
| 133 | - * Make a computer file size |
|
| 134 | - * @param string $str file size in human readable format |
|
| 135 | - * @return float|bool a file size in bytes |
|
| 136 | - * |
|
| 137 | - * Makes 2kB to 2048. |
|
| 138 | - * |
|
| 139 | - * Inspired by: http://www.php.net/manual/en/function.filesize.php#92418 |
|
| 140 | - */ |
|
| 141 | - public static function computerFileSize($str) { |
|
| 142 | - $str = strtolower($str); |
|
| 143 | - if (is_numeric($str)) { |
|
| 144 | - return (float)$str; |
|
| 145 | - } |
|
| 146 | - |
|
| 147 | - $bytes_array = array( |
|
| 148 | - 'b' => 1, |
|
| 149 | - 'k' => 1024, |
|
| 150 | - 'kb' => 1024, |
|
| 151 | - 'mb' => 1024 * 1024, |
|
| 152 | - 'm' => 1024 * 1024, |
|
| 153 | - 'gb' => 1024 * 1024 * 1024, |
|
| 154 | - 'g' => 1024 * 1024 * 1024, |
|
| 155 | - 'tb' => 1024 * 1024 * 1024 * 1024, |
|
| 156 | - 't' => 1024 * 1024 * 1024 * 1024, |
|
| 157 | - 'pb' => 1024 * 1024 * 1024 * 1024 * 1024, |
|
| 158 | - 'p' => 1024 * 1024 * 1024 * 1024 * 1024, |
|
| 159 | - ); |
|
| 160 | - |
|
| 161 | - $bytes = (float)$str; |
|
| 162 | - |
|
| 163 | - if (preg_match('#([kmgtp]?b?)$#si', $str, $matches) && !empty($bytes_array[$matches[1]])) { |
|
| 164 | - $bytes *= $bytes_array[$matches[1]]; |
|
| 165 | - } else { |
|
| 166 | - return false; |
|
| 167 | - } |
|
| 168 | - |
|
| 169 | - $bytes = round($bytes); |
|
| 170 | - |
|
| 171 | - return $bytes; |
|
| 172 | - } |
|
| 173 | - |
|
| 174 | - /** |
|
| 175 | - * Recursive copying of folders |
|
| 176 | - * @param string $src source folder |
|
| 177 | - * @param string $dest target folder |
|
| 178 | - * |
|
| 179 | - */ |
|
| 180 | - static function copyr($src, $dest) { |
|
| 181 | - if (is_dir($src)) { |
|
| 182 | - if (!is_dir($dest)) { |
|
| 183 | - mkdir($dest); |
|
| 184 | - } |
|
| 185 | - $files = scandir($src); |
|
| 186 | - foreach ($files as $file) { |
|
| 187 | - if ($file != "." && $file != "..") { |
|
| 188 | - self::copyr("$src/$file", "$dest/$file"); |
|
| 189 | - } |
|
| 190 | - } |
|
| 191 | - } elseif (file_exists($src) && !\OC\Files\Filesystem::isFileBlacklisted($src)) { |
|
| 192 | - copy($src, $dest); |
|
| 193 | - } |
|
| 194 | - } |
|
| 195 | - |
|
| 196 | - /** |
|
| 197 | - * Recursive deletion of folders |
|
| 198 | - * @param string $dir path to the folder |
|
| 199 | - * @param bool $deleteSelf if set to false only the content of the folder will be deleted |
|
| 200 | - * @return bool |
|
| 201 | - */ |
|
| 202 | - static function rmdirr($dir, $deleteSelf = true) { |
|
| 203 | - if (is_dir($dir)) { |
|
| 204 | - $files = new RecursiveIteratorIterator( |
|
| 205 | - new RecursiveDirectoryIterator($dir, RecursiveDirectoryIterator::SKIP_DOTS), |
|
| 206 | - RecursiveIteratorIterator::CHILD_FIRST |
|
| 207 | - ); |
|
| 208 | - |
|
| 209 | - foreach ($files as $fileInfo) { |
|
| 210 | - /** @var SplFileInfo $fileInfo */ |
|
| 211 | - if ($fileInfo->isLink()) { |
|
| 212 | - unlink($fileInfo->getPathname()); |
|
| 213 | - } else if ($fileInfo->isDir()) { |
|
| 214 | - rmdir($fileInfo->getRealPath()); |
|
| 215 | - } else { |
|
| 216 | - unlink($fileInfo->getRealPath()); |
|
| 217 | - } |
|
| 218 | - } |
|
| 219 | - if ($deleteSelf) { |
|
| 220 | - rmdir($dir); |
|
| 221 | - } |
|
| 222 | - } elseif (file_exists($dir)) { |
|
| 223 | - if ($deleteSelf) { |
|
| 224 | - unlink($dir); |
|
| 225 | - } |
|
| 226 | - } |
|
| 227 | - if (!$deleteSelf) { |
|
| 228 | - return true; |
|
| 229 | - } |
|
| 230 | - |
|
| 231 | - return !file_exists($dir); |
|
| 232 | - } |
|
| 233 | - |
|
| 234 | - /** |
|
| 235 | - * @return \OC\Files\Type\TemplateManager |
|
| 236 | - */ |
|
| 237 | - static public function getFileTemplateManager() { |
|
| 238 | - if (!self::$templateManager) { |
|
| 239 | - self::$templateManager = new \OC\Files\Type\TemplateManager(); |
|
| 240 | - } |
|
| 241 | - return self::$templateManager; |
|
| 242 | - } |
|
| 243 | - |
|
| 244 | - /** |
|
| 245 | - * detect if a given program is found in the search PATH |
|
| 246 | - * |
|
| 247 | - * @param string $name |
|
| 248 | - * @param bool $path |
|
| 249 | - * @internal param string $program name |
|
| 250 | - * @internal param string $optional search path, defaults to $PATH |
|
| 251 | - * @return bool true if executable program found in path |
|
| 252 | - */ |
|
| 253 | - public static function canExecute($name, $path = false) { |
|
| 254 | - // path defaults to PATH from environment if not set |
|
| 255 | - if ($path === false) { |
|
| 256 | - $path = getenv("PATH"); |
|
| 257 | - } |
|
| 258 | - // we look for an executable file of that name |
|
| 259 | - $exts = [""]; |
|
| 260 | - $check_fn = "is_executable"; |
|
| 261 | - // Default check will be done with $path directories : |
|
| 262 | - $dirs = explode(PATH_SEPARATOR, $path); |
|
| 263 | - // WARNING : We have to check if open_basedir is enabled : |
|
| 264 | - $obd = OC::$server->getIniWrapper()->getString('open_basedir'); |
|
| 265 | - if ($obd != "none") { |
|
| 266 | - $obd_values = explode(PATH_SEPARATOR, $obd); |
|
| 267 | - if (count($obd_values) > 0 and $obd_values[0]) { |
|
| 268 | - // open_basedir is in effect ! |
|
| 269 | - // We need to check if the program is in one of these dirs : |
|
| 270 | - $dirs = $obd_values; |
|
| 271 | - } |
|
| 272 | - } |
|
| 273 | - foreach ($dirs as $dir) { |
|
| 274 | - foreach ($exts as $ext) { |
|
| 275 | - if ($check_fn("$dir/$name" . $ext)) |
|
| 276 | - return true; |
|
| 277 | - } |
|
| 278 | - } |
|
| 279 | - return false; |
|
| 280 | - } |
|
| 281 | - |
|
| 282 | - /** |
|
| 283 | - * copy the contents of one stream to another |
|
| 284 | - * |
|
| 285 | - * @param resource $source |
|
| 286 | - * @param resource $target |
|
| 287 | - * @return array the number of bytes copied and result |
|
| 288 | - */ |
|
| 289 | - public static function streamCopy($source, $target) { |
|
| 290 | - if (!$source or !$target) { |
|
| 291 | - return array(0, false); |
|
| 292 | - } |
|
| 293 | - $bufSize = 8192; |
|
| 294 | - $result = true; |
|
| 295 | - $count = 0; |
|
| 296 | - while (!feof($source)) { |
|
| 297 | - $buf = fread($source, $bufSize); |
|
| 298 | - $bytesWritten = fwrite($target, $buf); |
|
| 299 | - if ($bytesWritten !== false) { |
|
| 300 | - $count += $bytesWritten; |
|
| 301 | - } |
|
| 302 | - // note: strlen is expensive so only use it when necessary, |
|
| 303 | - // on the last block |
|
| 304 | - if ($bytesWritten === false |
|
| 305 | - || ($bytesWritten < $bufSize && $bytesWritten < strlen($buf)) |
|
| 306 | - ) { |
|
| 307 | - // write error, could be disk full ? |
|
| 308 | - $result = false; |
|
| 309 | - break; |
|
| 310 | - } |
|
| 311 | - } |
|
| 312 | - return array($count, $result); |
|
| 313 | - } |
|
| 314 | - |
|
| 315 | - /** |
|
| 316 | - * Adds a suffix to the name in case the file exists |
|
| 317 | - * |
|
| 318 | - * @param string $path |
|
| 319 | - * @param string $filename |
|
| 320 | - * @return string |
|
| 321 | - */ |
|
| 322 | - public static function buildNotExistingFileName($path, $filename) { |
|
| 323 | - $view = \OC\Files\Filesystem::getView(); |
|
| 324 | - return self::buildNotExistingFileNameForView($path, $filename, $view); |
|
| 325 | - } |
|
| 326 | - |
|
| 327 | - /** |
|
| 328 | - * Adds a suffix to the name in case the file exists |
|
| 329 | - * |
|
| 330 | - * @param string $path |
|
| 331 | - * @param string $filename |
|
| 332 | - * @return string |
|
| 333 | - */ |
|
| 334 | - public static function buildNotExistingFileNameForView($path, $filename, \OC\Files\View $view) { |
|
| 335 | - if ($path === '/') { |
|
| 336 | - $path = ''; |
|
| 337 | - } |
|
| 338 | - if ($pos = strrpos($filename, '.')) { |
|
| 339 | - $name = substr($filename, 0, $pos); |
|
| 340 | - $ext = substr($filename, $pos); |
|
| 341 | - } else { |
|
| 342 | - $name = $filename; |
|
| 343 | - $ext = ''; |
|
| 344 | - } |
|
| 345 | - |
|
| 346 | - $newpath = $path . '/' . $filename; |
|
| 347 | - if ($view->file_exists($newpath)) { |
|
| 348 | - if (preg_match_all('/\((\d+)\)/', $name, $matches, PREG_OFFSET_CAPTURE)) { |
|
| 349 | - //Replace the last "(number)" with "(number+1)" |
|
| 350 | - $last_match = count($matches[0]) - 1; |
|
| 351 | - $counter = $matches[1][$last_match][0] + 1; |
|
| 352 | - $offset = $matches[0][$last_match][1]; |
|
| 353 | - $match_length = strlen($matches[0][$last_match][0]); |
|
| 354 | - } else { |
|
| 355 | - $counter = 2; |
|
| 356 | - $match_length = 0; |
|
| 357 | - $offset = false; |
|
| 358 | - } |
|
| 359 | - do { |
|
| 360 | - if ($offset) { |
|
| 361 | - //Replace the last "(number)" with "(number+1)" |
|
| 362 | - $newname = substr_replace($name, '(' . $counter . ')', $offset, $match_length); |
|
| 363 | - } else { |
|
| 364 | - $newname = $name . ' (' . $counter . ')'; |
|
| 365 | - } |
|
| 366 | - $newpath = $path . '/' . $newname . $ext; |
|
| 367 | - $counter++; |
|
| 368 | - } while ($view->file_exists($newpath)); |
|
| 369 | - } |
|
| 370 | - |
|
| 371 | - return $newpath; |
|
| 372 | - } |
|
| 373 | - |
|
| 374 | - /** |
|
| 375 | - * Returns an array with all keys from input lowercased or uppercased. Numbered indices are left as is. |
|
| 376 | - * |
|
| 377 | - * @param array $input The array to work on |
|
| 378 | - * @param int $case Either MB_CASE_UPPER or MB_CASE_LOWER (default) |
|
| 379 | - * @param string $encoding The encoding parameter is the character encoding. Defaults to UTF-8 |
|
| 380 | - * @return array |
|
| 381 | - * |
|
| 382 | - * Returns an array with all keys from input lowercased or uppercased. Numbered indices are left as is. |
|
| 383 | - * based on http://www.php.net/manual/en/function.array-change-key-case.php#107715 |
|
| 384 | - * |
|
| 385 | - */ |
|
| 386 | - public static function mb_array_change_key_case($input, $case = MB_CASE_LOWER, $encoding = 'UTF-8') { |
|
| 387 | - $case = ($case != MB_CASE_UPPER) ? MB_CASE_LOWER : MB_CASE_UPPER; |
|
| 388 | - $ret = array(); |
|
| 389 | - foreach ($input as $k => $v) { |
|
| 390 | - $ret[mb_convert_case($k, $case, $encoding)] = $v; |
|
| 391 | - } |
|
| 392 | - return $ret; |
|
| 393 | - } |
|
| 394 | - |
|
| 395 | - /** |
|
| 396 | - * performs a search in a nested array |
|
| 397 | - * @param array $haystack the array to be searched |
|
| 398 | - * @param string $needle the search string |
|
| 399 | - * @param mixed $index optional, only search this key name |
|
| 400 | - * @return mixed the key of the matching field, otherwise false |
|
| 401 | - * |
|
| 402 | - * performs a search in a nested array |
|
| 403 | - * |
|
| 404 | - * taken from http://www.php.net/manual/en/function.array-search.php#97645 |
|
| 405 | - */ |
|
| 406 | - public static function recursiveArraySearch($haystack, $needle, $index = null) { |
|
| 407 | - $aIt = new RecursiveArrayIterator($haystack); |
|
| 408 | - $it = new RecursiveIteratorIterator($aIt); |
|
| 409 | - |
|
| 410 | - while ($it->valid()) { |
|
| 411 | - if (((isset($index) AND ($it->key() == $index)) OR (!isset($index))) AND ($it->current() == $needle)) { |
|
| 412 | - return $aIt->key(); |
|
| 413 | - } |
|
| 414 | - |
|
| 415 | - $it->next(); |
|
| 416 | - } |
|
| 417 | - |
|
| 418 | - return false; |
|
| 419 | - } |
|
| 420 | - |
|
| 421 | - /** |
|
| 422 | - * calculates the maximum upload size respecting system settings, free space and user quota |
|
| 423 | - * |
|
| 424 | - * @param string $dir the current folder where the user currently operates |
|
| 425 | - * @param int $freeSpace the number of bytes free on the storage holding $dir, if not set this will be received from the storage directly |
|
| 426 | - * @return int number of bytes representing |
|
| 427 | - */ |
|
| 428 | - public static function maxUploadFilesize($dir, $freeSpace = null) { |
|
| 429 | - if (is_null($freeSpace) || $freeSpace < 0){ |
|
| 430 | - $freeSpace = self::freeSpace($dir); |
|
| 431 | - } |
|
| 432 | - return min($freeSpace, self::uploadLimit()); |
|
| 433 | - } |
|
| 434 | - |
|
| 435 | - /** |
|
| 436 | - * Calculate free space left within user quota |
|
| 437 | - * |
|
| 438 | - * @param string $dir the current folder where the user currently operates |
|
| 439 | - * @return int number of bytes representing |
|
| 440 | - */ |
|
| 441 | - public static function freeSpace($dir) { |
|
| 442 | - $freeSpace = \OC\Files\Filesystem::free_space($dir); |
|
| 443 | - if ($freeSpace < \OCP\Files\FileInfo::SPACE_UNLIMITED) { |
|
| 444 | - $freeSpace = max($freeSpace, 0); |
|
| 445 | - return $freeSpace; |
|
| 446 | - } else { |
|
| 447 | - return (INF > 0)? INF: PHP_INT_MAX; // work around https://bugs.php.net/bug.php?id=69188 |
|
| 448 | - } |
|
| 449 | - } |
|
| 450 | - |
|
| 451 | - /** |
|
| 452 | - * Calculate PHP upload limit |
|
| 453 | - * |
|
| 454 | - * @return int PHP upload file size limit |
|
| 455 | - */ |
|
| 456 | - public static function uploadLimit() { |
|
| 457 | - $ini = \OC::$server->getIniWrapper(); |
|
| 458 | - $upload_max_filesize = OCP\Util::computerFileSize($ini->get('upload_max_filesize')); |
|
| 459 | - $post_max_size = OCP\Util::computerFileSize($ini->get('post_max_size')); |
|
| 460 | - if ((int)$upload_max_filesize === 0 and (int)$post_max_size === 0) { |
|
| 461 | - return INF; |
|
| 462 | - } elseif ((int)$upload_max_filesize === 0 or (int)$post_max_size === 0) { |
|
| 463 | - return max($upload_max_filesize, $post_max_size); //only the non 0 value counts |
|
| 464 | - } else { |
|
| 465 | - return min($upload_max_filesize, $post_max_size); |
|
| 466 | - } |
|
| 467 | - } |
|
| 468 | - |
|
| 469 | - /** |
|
| 470 | - * Checks if a function is available |
|
| 471 | - * |
|
| 472 | - * @param string $function_name |
|
| 473 | - * @return bool |
|
| 474 | - */ |
|
| 475 | - public static function is_function_enabled($function_name) { |
|
| 476 | - if (!function_exists($function_name)) { |
|
| 477 | - return false; |
|
| 478 | - } |
|
| 479 | - $ini = \OC::$server->getIniWrapper(); |
|
| 480 | - $disabled = explode(',', $ini->get('disable_functions') ?: ''); |
|
| 481 | - $disabled = array_map('trim', $disabled); |
|
| 482 | - if (in_array($function_name, $disabled)) { |
|
| 483 | - return false; |
|
| 484 | - } |
|
| 485 | - $disabled = explode(',', $ini->get('suhosin.executor.func.blacklist') ?: ''); |
|
| 486 | - $disabled = array_map('trim', $disabled); |
|
| 487 | - if (in_array($function_name, $disabled)) { |
|
| 488 | - return false; |
|
| 489 | - } |
|
| 490 | - return true; |
|
| 491 | - } |
|
| 492 | - |
|
| 493 | - /** |
|
| 494 | - * Try to find a program |
|
| 495 | - * |
|
| 496 | - * @param string $program |
|
| 497 | - * @return null|string |
|
| 498 | - */ |
|
| 499 | - public static function findBinaryPath($program) { |
|
| 500 | - $memcache = \OC::$server->getMemCacheFactory()->createDistributed('findBinaryPath'); |
|
| 501 | - if ($memcache->hasKey($program)) { |
|
| 502 | - return $memcache->get($program); |
|
| 503 | - } |
|
| 504 | - $result = null; |
|
| 505 | - if (self::is_function_enabled('exec')) { |
|
| 506 | - $exeSniffer = new ExecutableFinder(); |
|
| 507 | - // Returns null if nothing is found |
|
| 508 | - $result = $exeSniffer->find($program); |
|
| 509 | - if (empty($result)) { |
|
| 510 | - $paths = getenv('PATH'); |
|
| 511 | - if (empty($paths)) { |
|
| 512 | - $paths = '/usr/local/bin /usr/bin /opt/bin /bin'; |
|
| 513 | - } else { |
|
| 514 | - $paths = str_replace(':',' ',getenv('PATH')); |
|
| 515 | - } |
|
| 516 | - $command = 'find ' . $paths . ' -name ' . escapeshellarg($program) . ' 2> /dev/null'; |
|
| 517 | - exec($command, $output, $returnCode); |
|
| 518 | - if (count($output) > 0) { |
|
| 519 | - $result = escapeshellcmd($output[0]); |
|
| 520 | - } |
|
| 521 | - } |
|
| 522 | - } |
|
| 523 | - // store the value for 5 minutes |
|
| 524 | - $memcache->set($program, $result, 300); |
|
| 525 | - return $result; |
|
| 526 | - } |
|
| 527 | - |
|
| 528 | - /** |
|
| 529 | - * Calculate the disc space for the given path |
|
| 530 | - * |
|
| 531 | - * @param string $path |
|
| 532 | - * @param \OCP\Files\FileInfo $rootInfo (optional) |
|
| 533 | - * @return array |
|
| 534 | - * @throws \OCP\Files\NotFoundException |
|
| 535 | - */ |
|
| 536 | - public static function getStorageInfo($path, $rootInfo = null) { |
|
| 537 | - // return storage info without adding mount points |
|
| 538 | - $includeExtStorage = \OC::$server->getSystemConfig()->getValue('quota_include_external_storage', false); |
|
| 539 | - |
|
| 540 | - if (!$rootInfo) { |
|
| 541 | - $rootInfo = \OC\Files\Filesystem::getFileInfo($path, $includeExtStorage ? 'ext' : false); |
|
| 542 | - } |
|
| 543 | - if (!$rootInfo instanceof \OCP\Files\FileInfo) { |
|
| 544 | - throw new \OCP\Files\NotFoundException(); |
|
| 545 | - } |
|
| 546 | - $used = $rootInfo->getSize(); |
|
| 547 | - if ($used < 0) { |
|
| 548 | - $used = 0; |
|
| 549 | - } |
|
| 550 | - $quota = \OCP\Files\FileInfo::SPACE_UNLIMITED; |
|
| 551 | - $storage = $rootInfo->getStorage(); |
|
| 552 | - $sourceStorage = $storage; |
|
| 553 | - if ($storage->instanceOfStorage('\OCA\Files_Sharing\SharedStorage')) { |
|
| 554 | - $includeExtStorage = false; |
|
| 555 | - $sourceStorage = $storage->getSourceStorage(); |
|
| 556 | - } |
|
| 557 | - if ($includeExtStorage) { |
|
| 558 | - if ($storage->instanceOfStorage('\OC\Files\Storage\Home') |
|
| 559 | - || $storage->instanceOfStorage('\OC\Files\ObjectStore\HomeObjectStoreStorage') |
|
| 560 | - ) { |
|
| 561 | - /** @var \OC\Files\Storage\Home $storage */ |
|
| 562 | - $userInstance = $storage->getUser(); |
|
| 563 | - $user = ($userInstance === null) ? null : $userInstance->getUID(); |
|
| 564 | - } else { |
|
| 565 | - $user = \OC::$server->getUserSession()->getUser()->getUID(); |
|
| 566 | - } |
|
| 567 | - if ($user) { |
|
| 568 | - $quota = OC_Util::getUserQuota($user); |
|
| 569 | - } else { |
|
| 570 | - $quota = \OCP\Files\FileInfo::SPACE_UNLIMITED; |
|
| 571 | - } |
|
| 572 | - if ($quota !== \OCP\Files\FileInfo::SPACE_UNLIMITED) { |
|
| 573 | - // always get free space / total space from root + mount points |
|
| 574 | - return self::getGlobalStorageInfo(); |
|
| 575 | - } |
|
| 576 | - } |
|
| 577 | - |
|
| 578 | - // TODO: need a better way to get total space from storage |
|
| 579 | - if ($sourceStorage->instanceOfStorage('\OC\Files\Storage\Wrapper\Quota')) { |
|
| 580 | - /** @var \OC\Files\Storage\Wrapper\Quota $storage */ |
|
| 581 | - $quota = $sourceStorage->getQuota(); |
|
| 582 | - } |
|
| 583 | - $free = $sourceStorage->free_space($rootInfo->getInternalPath()); |
|
| 584 | - if ($free >= 0) { |
|
| 585 | - $total = $free + $used; |
|
| 586 | - } else { |
|
| 587 | - $total = $free; //either unknown or unlimited |
|
| 588 | - } |
|
| 589 | - if ($total > 0) { |
|
| 590 | - if ($quota > 0 && $total > $quota) { |
|
| 591 | - $total = $quota; |
|
| 592 | - } |
|
| 593 | - // prevent division by zero or error codes (negative values) |
|
| 594 | - $relative = round(($used / $total) * 10000) / 100; |
|
| 595 | - } else { |
|
| 596 | - $relative = 0; |
|
| 597 | - } |
|
| 598 | - |
|
| 599 | - $ownerId = $storage->getOwner($path); |
|
| 600 | - $ownerDisplayName = ''; |
|
| 601 | - $owner = \OC::$server->getUserManager()->get($ownerId); |
|
| 602 | - if($owner) { |
|
| 603 | - $ownerDisplayName = $owner->getDisplayName(); |
|
| 604 | - } |
|
| 605 | - |
|
| 606 | - return [ |
|
| 607 | - 'free' => $free, |
|
| 608 | - 'used' => $used, |
|
| 609 | - 'quota' => $quota, |
|
| 610 | - 'total' => $total, |
|
| 611 | - 'relative' => $relative, |
|
| 612 | - 'owner' => $ownerId, |
|
| 613 | - 'ownerDisplayName' => $ownerDisplayName, |
|
| 614 | - ]; |
|
| 615 | - } |
|
| 616 | - |
|
| 617 | - /** |
|
| 618 | - * Get storage info including all mount points and quota |
|
| 619 | - * |
|
| 620 | - * @return array |
|
| 621 | - */ |
|
| 622 | - private static function getGlobalStorageInfo() { |
|
| 623 | - $quota = OC_Util::getUserQuota(\OCP\User::getUser()); |
|
| 624 | - |
|
| 625 | - $rootInfo = \OC\Files\Filesystem::getFileInfo('', 'ext'); |
|
| 626 | - $used = $rootInfo['size']; |
|
| 627 | - if ($used < 0) { |
|
| 628 | - $used = 0; |
|
| 629 | - } |
|
| 630 | - |
|
| 631 | - $total = $quota; |
|
| 632 | - $free = $quota - $used; |
|
| 633 | - |
|
| 634 | - if ($total > 0) { |
|
| 635 | - if ($quota > 0 && $total > $quota) { |
|
| 636 | - $total = $quota; |
|
| 637 | - } |
|
| 638 | - // prevent division by zero or error codes (negative values) |
|
| 639 | - $relative = round(($used / $total) * 10000) / 100; |
|
| 640 | - } else { |
|
| 641 | - $relative = 0; |
|
| 642 | - } |
|
| 643 | - |
|
| 644 | - return array('free' => $free, 'used' => $used, 'total' => $total, 'relative' => $relative); |
|
| 645 | - |
|
| 646 | - } |
|
| 647 | - |
|
| 648 | - /** |
|
| 649 | - * Returns whether the config file is set manually to read-only |
|
| 650 | - * @return bool |
|
| 651 | - */ |
|
| 652 | - public static function isReadOnlyConfigEnabled() { |
|
| 653 | - return \OC::$server->getConfig()->getSystemValue('config_is_read_only', false); |
|
| 654 | - } |
|
| 52 | + private static $templateManager; |
|
| 53 | + |
|
| 54 | + /** |
|
| 55 | + * Creates an absolute url for public use |
|
| 56 | + * @param string $service id |
|
| 57 | + * @param bool $add_slash |
|
| 58 | + * @return string the url |
|
| 59 | + * |
|
| 60 | + * Returns a absolute url to the given service. |
|
| 61 | + */ |
|
| 62 | + public static function linkToPublic($service, $add_slash = false) { |
|
| 63 | + if ($service === 'files') { |
|
| 64 | + $url = OC::$server->getURLGenerator()->getAbsoluteURL('/s'); |
|
| 65 | + } else { |
|
| 66 | + $url = OC::$server->getURLGenerator()->getAbsoluteURL(OC::$server->getURLGenerator()->linkTo('', 'public.php').'?service='.$service); |
|
| 67 | + } |
|
| 68 | + return $url . (($add_slash && $service[strlen($service) - 1] != '/') ? '/' : ''); |
|
| 69 | + } |
|
| 70 | + |
|
| 71 | + /** |
|
| 72 | + * Make a human file size |
|
| 73 | + * @param int $bytes file size in bytes |
|
| 74 | + * @return string a human readable file size |
|
| 75 | + * |
|
| 76 | + * Makes 2048 to 2 kB. |
|
| 77 | + */ |
|
| 78 | + public static function humanFileSize($bytes) { |
|
| 79 | + if ($bytes < 0) { |
|
| 80 | + return "?"; |
|
| 81 | + } |
|
| 82 | + if ($bytes < 1024) { |
|
| 83 | + return "$bytes B"; |
|
| 84 | + } |
|
| 85 | + $bytes = round($bytes / 1024, 0); |
|
| 86 | + if ($bytes < 1024) { |
|
| 87 | + return "$bytes KB"; |
|
| 88 | + } |
|
| 89 | + $bytes = round($bytes / 1024, 1); |
|
| 90 | + if ($bytes < 1024) { |
|
| 91 | + return "$bytes MB"; |
|
| 92 | + } |
|
| 93 | + $bytes = round($bytes / 1024, 1); |
|
| 94 | + if ($bytes < 1024) { |
|
| 95 | + return "$bytes GB"; |
|
| 96 | + } |
|
| 97 | + $bytes = round($bytes / 1024, 1); |
|
| 98 | + if ($bytes < 1024) { |
|
| 99 | + return "$bytes TB"; |
|
| 100 | + } |
|
| 101 | + |
|
| 102 | + $bytes = round($bytes / 1024, 1); |
|
| 103 | + return "$bytes PB"; |
|
| 104 | + } |
|
| 105 | + |
|
| 106 | + /** |
|
| 107 | + * Make a php file size |
|
| 108 | + * @param int $bytes file size in bytes |
|
| 109 | + * @return string a php parseable file size |
|
| 110 | + * |
|
| 111 | + * Makes 2048 to 2k and 2^41 to 2048G |
|
| 112 | + */ |
|
| 113 | + public static function phpFileSize($bytes) { |
|
| 114 | + if ($bytes < 0) { |
|
| 115 | + return "?"; |
|
| 116 | + } |
|
| 117 | + if ($bytes < 1024) { |
|
| 118 | + return $bytes . "B"; |
|
| 119 | + } |
|
| 120 | + $bytes = round($bytes / 1024, 1); |
|
| 121 | + if ($bytes < 1024) { |
|
| 122 | + return $bytes . "K"; |
|
| 123 | + } |
|
| 124 | + $bytes = round($bytes / 1024, 1); |
|
| 125 | + if ($bytes < 1024) { |
|
| 126 | + return $bytes . "M"; |
|
| 127 | + } |
|
| 128 | + $bytes = round($bytes / 1024, 1); |
|
| 129 | + return $bytes . "G"; |
|
| 130 | + } |
|
| 131 | + |
|
| 132 | + /** |
|
| 133 | + * Make a computer file size |
|
| 134 | + * @param string $str file size in human readable format |
|
| 135 | + * @return float|bool a file size in bytes |
|
| 136 | + * |
|
| 137 | + * Makes 2kB to 2048. |
|
| 138 | + * |
|
| 139 | + * Inspired by: http://www.php.net/manual/en/function.filesize.php#92418 |
|
| 140 | + */ |
|
| 141 | + public static function computerFileSize($str) { |
|
| 142 | + $str = strtolower($str); |
|
| 143 | + if (is_numeric($str)) { |
|
| 144 | + return (float)$str; |
|
| 145 | + } |
|
| 146 | + |
|
| 147 | + $bytes_array = array( |
|
| 148 | + 'b' => 1, |
|
| 149 | + 'k' => 1024, |
|
| 150 | + 'kb' => 1024, |
|
| 151 | + 'mb' => 1024 * 1024, |
|
| 152 | + 'm' => 1024 * 1024, |
|
| 153 | + 'gb' => 1024 * 1024 * 1024, |
|
| 154 | + 'g' => 1024 * 1024 * 1024, |
|
| 155 | + 'tb' => 1024 * 1024 * 1024 * 1024, |
|
| 156 | + 't' => 1024 * 1024 * 1024 * 1024, |
|
| 157 | + 'pb' => 1024 * 1024 * 1024 * 1024 * 1024, |
|
| 158 | + 'p' => 1024 * 1024 * 1024 * 1024 * 1024, |
|
| 159 | + ); |
|
| 160 | + |
|
| 161 | + $bytes = (float)$str; |
|
| 162 | + |
|
| 163 | + if (preg_match('#([kmgtp]?b?)$#si', $str, $matches) && !empty($bytes_array[$matches[1]])) { |
|
| 164 | + $bytes *= $bytes_array[$matches[1]]; |
|
| 165 | + } else { |
|
| 166 | + return false; |
|
| 167 | + } |
|
| 168 | + |
|
| 169 | + $bytes = round($bytes); |
|
| 170 | + |
|
| 171 | + return $bytes; |
|
| 172 | + } |
|
| 173 | + |
|
| 174 | + /** |
|
| 175 | + * Recursive copying of folders |
|
| 176 | + * @param string $src source folder |
|
| 177 | + * @param string $dest target folder |
|
| 178 | + * |
|
| 179 | + */ |
|
| 180 | + static function copyr($src, $dest) { |
|
| 181 | + if (is_dir($src)) { |
|
| 182 | + if (!is_dir($dest)) { |
|
| 183 | + mkdir($dest); |
|
| 184 | + } |
|
| 185 | + $files = scandir($src); |
|
| 186 | + foreach ($files as $file) { |
|
| 187 | + if ($file != "." && $file != "..") { |
|
| 188 | + self::copyr("$src/$file", "$dest/$file"); |
|
| 189 | + } |
|
| 190 | + } |
|
| 191 | + } elseif (file_exists($src) && !\OC\Files\Filesystem::isFileBlacklisted($src)) { |
|
| 192 | + copy($src, $dest); |
|
| 193 | + } |
|
| 194 | + } |
|
| 195 | + |
|
| 196 | + /** |
|
| 197 | + * Recursive deletion of folders |
|
| 198 | + * @param string $dir path to the folder |
|
| 199 | + * @param bool $deleteSelf if set to false only the content of the folder will be deleted |
|
| 200 | + * @return bool |
|
| 201 | + */ |
|
| 202 | + static function rmdirr($dir, $deleteSelf = true) { |
|
| 203 | + if (is_dir($dir)) { |
|
| 204 | + $files = new RecursiveIteratorIterator( |
|
| 205 | + new RecursiveDirectoryIterator($dir, RecursiveDirectoryIterator::SKIP_DOTS), |
|
| 206 | + RecursiveIteratorIterator::CHILD_FIRST |
|
| 207 | + ); |
|
| 208 | + |
|
| 209 | + foreach ($files as $fileInfo) { |
|
| 210 | + /** @var SplFileInfo $fileInfo */ |
|
| 211 | + if ($fileInfo->isLink()) { |
|
| 212 | + unlink($fileInfo->getPathname()); |
|
| 213 | + } else if ($fileInfo->isDir()) { |
|
| 214 | + rmdir($fileInfo->getRealPath()); |
|
| 215 | + } else { |
|
| 216 | + unlink($fileInfo->getRealPath()); |
|
| 217 | + } |
|
| 218 | + } |
|
| 219 | + if ($deleteSelf) { |
|
| 220 | + rmdir($dir); |
|
| 221 | + } |
|
| 222 | + } elseif (file_exists($dir)) { |
|
| 223 | + if ($deleteSelf) { |
|
| 224 | + unlink($dir); |
|
| 225 | + } |
|
| 226 | + } |
|
| 227 | + if (!$deleteSelf) { |
|
| 228 | + return true; |
|
| 229 | + } |
|
| 230 | + |
|
| 231 | + return !file_exists($dir); |
|
| 232 | + } |
|
| 233 | + |
|
| 234 | + /** |
|
| 235 | + * @return \OC\Files\Type\TemplateManager |
|
| 236 | + */ |
|
| 237 | + static public function getFileTemplateManager() { |
|
| 238 | + if (!self::$templateManager) { |
|
| 239 | + self::$templateManager = new \OC\Files\Type\TemplateManager(); |
|
| 240 | + } |
|
| 241 | + return self::$templateManager; |
|
| 242 | + } |
|
| 243 | + |
|
| 244 | + /** |
|
| 245 | + * detect if a given program is found in the search PATH |
|
| 246 | + * |
|
| 247 | + * @param string $name |
|
| 248 | + * @param bool $path |
|
| 249 | + * @internal param string $program name |
|
| 250 | + * @internal param string $optional search path, defaults to $PATH |
|
| 251 | + * @return bool true if executable program found in path |
|
| 252 | + */ |
|
| 253 | + public static function canExecute($name, $path = false) { |
|
| 254 | + // path defaults to PATH from environment if not set |
|
| 255 | + if ($path === false) { |
|
| 256 | + $path = getenv("PATH"); |
|
| 257 | + } |
|
| 258 | + // we look for an executable file of that name |
|
| 259 | + $exts = [""]; |
|
| 260 | + $check_fn = "is_executable"; |
|
| 261 | + // Default check will be done with $path directories : |
|
| 262 | + $dirs = explode(PATH_SEPARATOR, $path); |
|
| 263 | + // WARNING : We have to check if open_basedir is enabled : |
|
| 264 | + $obd = OC::$server->getIniWrapper()->getString('open_basedir'); |
|
| 265 | + if ($obd != "none") { |
|
| 266 | + $obd_values = explode(PATH_SEPARATOR, $obd); |
|
| 267 | + if (count($obd_values) > 0 and $obd_values[0]) { |
|
| 268 | + // open_basedir is in effect ! |
|
| 269 | + // We need to check if the program is in one of these dirs : |
|
| 270 | + $dirs = $obd_values; |
|
| 271 | + } |
|
| 272 | + } |
|
| 273 | + foreach ($dirs as $dir) { |
|
| 274 | + foreach ($exts as $ext) { |
|
| 275 | + if ($check_fn("$dir/$name" . $ext)) |
|
| 276 | + return true; |
|
| 277 | + } |
|
| 278 | + } |
|
| 279 | + return false; |
|
| 280 | + } |
|
| 281 | + |
|
| 282 | + /** |
|
| 283 | + * copy the contents of one stream to another |
|
| 284 | + * |
|
| 285 | + * @param resource $source |
|
| 286 | + * @param resource $target |
|
| 287 | + * @return array the number of bytes copied and result |
|
| 288 | + */ |
|
| 289 | + public static function streamCopy($source, $target) { |
|
| 290 | + if (!$source or !$target) { |
|
| 291 | + return array(0, false); |
|
| 292 | + } |
|
| 293 | + $bufSize = 8192; |
|
| 294 | + $result = true; |
|
| 295 | + $count = 0; |
|
| 296 | + while (!feof($source)) { |
|
| 297 | + $buf = fread($source, $bufSize); |
|
| 298 | + $bytesWritten = fwrite($target, $buf); |
|
| 299 | + if ($bytesWritten !== false) { |
|
| 300 | + $count += $bytesWritten; |
|
| 301 | + } |
|
| 302 | + // note: strlen is expensive so only use it when necessary, |
|
| 303 | + // on the last block |
|
| 304 | + if ($bytesWritten === false |
|
| 305 | + || ($bytesWritten < $bufSize && $bytesWritten < strlen($buf)) |
|
| 306 | + ) { |
|
| 307 | + // write error, could be disk full ? |
|
| 308 | + $result = false; |
|
| 309 | + break; |
|
| 310 | + } |
|
| 311 | + } |
|
| 312 | + return array($count, $result); |
|
| 313 | + } |
|
| 314 | + |
|
| 315 | + /** |
|
| 316 | + * Adds a suffix to the name in case the file exists |
|
| 317 | + * |
|
| 318 | + * @param string $path |
|
| 319 | + * @param string $filename |
|
| 320 | + * @return string |
|
| 321 | + */ |
|
| 322 | + public static function buildNotExistingFileName($path, $filename) { |
|
| 323 | + $view = \OC\Files\Filesystem::getView(); |
|
| 324 | + return self::buildNotExistingFileNameForView($path, $filename, $view); |
|
| 325 | + } |
|
| 326 | + |
|
| 327 | + /** |
|
| 328 | + * Adds a suffix to the name in case the file exists |
|
| 329 | + * |
|
| 330 | + * @param string $path |
|
| 331 | + * @param string $filename |
|
| 332 | + * @return string |
|
| 333 | + */ |
|
| 334 | + public static function buildNotExistingFileNameForView($path, $filename, \OC\Files\View $view) { |
|
| 335 | + if ($path === '/') { |
|
| 336 | + $path = ''; |
|
| 337 | + } |
|
| 338 | + if ($pos = strrpos($filename, '.')) { |
|
| 339 | + $name = substr($filename, 0, $pos); |
|
| 340 | + $ext = substr($filename, $pos); |
|
| 341 | + } else { |
|
| 342 | + $name = $filename; |
|
| 343 | + $ext = ''; |
|
| 344 | + } |
|
| 345 | + |
|
| 346 | + $newpath = $path . '/' . $filename; |
|
| 347 | + if ($view->file_exists($newpath)) { |
|
| 348 | + if (preg_match_all('/\((\d+)\)/', $name, $matches, PREG_OFFSET_CAPTURE)) { |
|
| 349 | + //Replace the last "(number)" with "(number+1)" |
|
| 350 | + $last_match = count($matches[0]) - 1; |
|
| 351 | + $counter = $matches[1][$last_match][0] + 1; |
|
| 352 | + $offset = $matches[0][$last_match][1]; |
|
| 353 | + $match_length = strlen($matches[0][$last_match][0]); |
|
| 354 | + } else { |
|
| 355 | + $counter = 2; |
|
| 356 | + $match_length = 0; |
|
| 357 | + $offset = false; |
|
| 358 | + } |
|
| 359 | + do { |
|
| 360 | + if ($offset) { |
|
| 361 | + //Replace the last "(number)" with "(number+1)" |
|
| 362 | + $newname = substr_replace($name, '(' . $counter . ')', $offset, $match_length); |
|
| 363 | + } else { |
|
| 364 | + $newname = $name . ' (' . $counter . ')'; |
|
| 365 | + } |
|
| 366 | + $newpath = $path . '/' . $newname . $ext; |
|
| 367 | + $counter++; |
|
| 368 | + } while ($view->file_exists($newpath)); |
|
| 369 | + } |
|
| 370 | + |
|
| 371 | + return $newpath; |
|
| 372 | + } |
|
| 373 | + |
|
| 374 | + /** |
|
| 375 | + * Returns an array with all keys from input lowercased or uppercased. Numbered indices are left as is. |
|
| 376 | + * |
|
| 377 | + * @param array $input The array to work on |
|
| 378 | + * @param int $case Either MB_CASE_UPPER or MB_CASE_LOWER (default) |
|
| 379 | + * @param string $encoding The encoding parameter is the character encoding. Defaults to UTF-8 |
|
| 380 | + * @return array |
|
| 381 | + * |
|
| 382 | + * Returns an array with all keys from input lowercased or uppercased. Numbered indices are left as is. |
|
| 383 | + * based on http://www.php.net/manual/en/function.array-change-key-case.php#107715 |
|
| 384 | + * |
|
| 385 | + */ |
|
| 386 | + public static function mb_array_change_key_case($input, $case = MB_CASE_LOWER, $encoding = 'UTF-8') { |
|
| 387 | + $case = ($case != MB_CASE_UPPER) ? MB_CASE_LOWER : MB_CASE_UPPER; |
|
| 388 | + $ret = array(); |
|
| 389 | + foreach ($input as $k => $v) { |
|
| 390 | + $ret[mb_convert_case($k, $case, $encoding)] = $v; |
|
| 391 | + } |
|
| 392 | + return $ret; |
|
| 393 | + } |
|
| 394 | + |
|
| 395 | + /** |
|
| 396 | + * performs a search in a nested array |
|
| 397 | + * @param array $haystack the array to be searched |
|
| 398 | + * @param string $needle the search string |
|
| 399 | + * @param mixed $index optional, only search this key name |
|
| 400 | + * @return mixed the key of the matching field, otherwise false |
|
| 401 | + * |
|
| 402 | + * performs a search in a nested array |
|
| 403 | + * |
|
| 404 | + * taken from http://www.php.net/manual/en/function.array-search.php#97645 |
|
| 405 | + */ |
|
| 406 | + public static function recursiveArraySearch($haystack, $needle, $index = null) { |
|
| 407 | + $aIt = new RecursiveArrayIterator($haystack); |
|
| 408 | + $it = new RecursiveIteratorIterator($aIt); |
|
| 409 | + |
|
| 410 | + while ($it->valid()) { |
|
| 411 | + if (((isset($index) AND ($it->key() == $index)) OR (!isset($index))) AND ($it->current() == $needle)) { |
|
| 412 | + return $aIt->key(); |
|
| 413 | + } |
|
| 414 | + |
|
| 415 | + $it->next(); |
|
| 416 | + } |
|
| 417 | + |
|
| 418 | + return false; |
|
| 419 | + } |
|
| 420 | + |
|
| 421 | + /** |
|
| 422 | + * calculates the maximum upload size respecting system settings, free space and user quota |
|
| 423 | + * |
|
| 424 | + * @param string $dir the current folder where the user currently operates |
|
| 425 | + * @param int $freeSpace the number of bytes free on the storage holding $dir, if not set this will be received from the storage directly |
|
| 426 | + * @return int number of bytes representing |
|
| 427 | + */ |
|
| 428 | + public static function maxUploadFilesize($dir, $freeSpace = null) { |
|
| 429 | + if (is_null($freeSpace) || $freeSpace < 0){ |
|
| 430 | + $freeSpace = self::freeSpace($dir); |
|
| 431 | + } |
|
| 432 | + return min($freeSpace, self::uploadLimit()); |
|
| 433 | + } |
|
| 434 | + |
|
| 435 | + /** |
|
| 436 | + * Calculate free space left within user quota |
|
| 437 | + * |
|
| 438 | + * @param string $dir the current folder where the user currently operates |
|
| 439 | + * @return int number of bytes representing |
|
| 440 | + */ |
|
| 441 | + public static function freeSpace($dir) { |
|
| 442 | + $freeSpace = \OC\Files\Filesystem::free_space($dir); |
|
| 443 | + if ($freeSpace < \OCP\Files\FileInfo::SPACE_UNLIMITED) { |
|
| 444 | + $freeSpace = max($freeSpace, 0); |
|
| 445 | + return $freeSpace; |
|
| 446 | + } else { |
|
| 447 | + return (INF > 0)? INF: PHP_INT_MAX; // work around https://bugs.php.net/bug.php?id=69188 |
|
| 448 | + } |
|
| 449 | + } |
|
| 450 | + |
|
| 451 | + /** |
|
| 452 | + * Calculate PHP upload limit |
|
| 453 | + * |
|
| 454 | + * @return int PHP upload file size limit |
|
| 455 | + */ |
|
| 456 | + public static function uploadLimit() { |
|
| 457 | + $ini = \OC::$server->getIniWrapper(); |
|
| 458 | + $upload_max_filesize = OCP\Util::computerFileSize($ini->get('upload_max_filesize')); |
|
| 459 | + $post_max_size = OCP\Util::computerFileSize($ini->get('post_max_size')); |
|
| 460 | + if ((int)$upload_max_filesize === 0 and (int)$post_max_size === 0) { |
|
| 461 | + return INF; |
|
| 462 | + } elseif ((int)$upload_max_filesize === 0 or (int)$post_max_size === 0) { |
|
| 463 | + return max($upload_max_filesize, $post_max_size); //only the non 0 value counts |
|
| 464 | + } else { |
|
| 465 | + return min($upload_max_filesize, $post_max_size); |
|
| 466 | + } |
|
| 467 | + } |
|
| 468 | + |
|
| 469 | + /** |
|
| 470 | + * Checks if a function is available |
|
| 471 | + * |
|
| 472 | + * @param string $function_name |
|
| 473 | + * @return bool |
|
| 474 | + */ |
|
| 475 | + public static function is_function_enabled($function_name) { |
|
| 476 | + if (!function_exists($function_name)) { |
|
| 477 | + return false; |
|
| 478 | + } |
|
| 479 | + $ini = \OC::$server->getIniWrapper(); |
|
| 480 | + $disabled = explode(',', $ini->get('disable_functions') ?: ''); |
|
| 481 | + $disabled = array_map('trim', $disabled); |
|
| 482 | + if (in_array($function_name, $disabled)) { |
|
| 483 | + return false; |
|
| 484 | + } |
|
| 485 | + $disabled = explode(',', $ini->get('suhosin.executor.func.blacklist') ?: ''); |
|
| 486 | + $disabled = array_map('trim', $disabled); |
|
| 487 | + if (in_array($function_name, $disabled)) { |
|
| 488 | + return false; |
|
| 489 | + } |
|
| 490 | + return true; |
|
| 491 | + } |
|
| 492 | + |
|
| 493 | + /** |
|
| 494 | + * Try to find a program |
|
| 495 | + * |
|
| 496 | + * @param string $program |
|
| 497 | + * @return null|string |
|
| 498 | + */ |
|
| 499 | + public static function findBinaryPath($program) { |
|
| 500 | + $memcache = \OC::$server->getMemCacheFactory()->createDistributed('findBinaryPath'); |
|
| 501 | + if ($memcache->hasKey($program)) { |
|
| 502 | + return $memcache->get($program); |
|
| 503 | + } |
|
| 504 | + $result = null; |
|
| 505 | + if (self::is_function_enabled('exec')) { |
|
| 506 | + $exeSniffer = new ExecutableFinder(); |
|
| 507 | + // Returns null if nothing is found |
|
| 508 | + $result = $exeSniffer->find($program); |
|
| 509 | + if (empty($result)) { |
|
| 510 | + $paths = getenv('PATH'); |
|
| 511 | + if (empty($paths)) { |
|
| 512 | + $paths = '/usr/local/bin /usr/bin /opt/bin /bin'; |
|
| 513 | + } else { |
|
| 514 | + $paths = str_replace(':',' ',getenv('PATH')); |
|
| 515 | + } |
|
| 516 | + $command = 'find ' . $paths . ' -name ' . escapeshellarg($program) . ' 2> /dev/null'; |
|
| 517 | + exec($command, $output, $returnCode); |
|
| 518 | + if (count($output) > 0) { |
|
| 519 | + $result = escapeshellcmd($output[0]); |
|
| 520 | + } |
|
| 521 | + } |
|
| 522 | + } |
|
| 523 | + // store the value for 5 minutes |
|
| 524 | + $memcache->set($program, $result, 300); |
|
| 525 | + return $result; |
|
| 526 | + } |
|
| 527 | + |
|
| 528 | + /** |
|
| 529 | + * Calculate the disc space for the given path |
|
| 530 | + * |
|
| 531 | + * @param string $path |
|
| 532 | + * @param \OCP\Files\FileInfo $rootInfo (optional) |
|
| 533 | + * @return array |
|
| 534 | + * @throws \OCP\Files\NotFoundException |
|
| 535 | + */ |
|
| 536 | + public static function getStorageInfo($path, $rootInfo = null) { |
|
| 537 | + // return storage info without adding mount points |
|
| 538 | + $includeExtStorage = \OC::$server->getSystemConfig()->getValue('quota_include_external_storage', false); |
|
| 539 | + |
|
| 540 | + if (!$rootInfo) { |
|
| 541 | + $rootInfo = \OC\Files\Filesystem::getFileInfo($path, $includeExtStorage ? 'ext' : false); |
|
| 542 | + } |
|
| 543 | + if (!$rootInfo instanceof \OCP\Files\FileInfo) { |
|
| 544 | + throw new \OCP\Files\NotFoundException(); |
|
| 545 | + } |
|
| 546 | + $used = $rootInfo->getSize(); |
|
| 547 | + if ($used < 0) { |
|
| 548 | + $used = 0; |
|
| 549 | + } |
|
| 550 | + $quota = \OCP\Files\FileInfo::SPACE_UNLIMITED; |
|
| 551 | + $storage = $rootInfo->getStorage(); |
|
| 552 | + $sourceStorage = $storage; |
|
| 553 | + if ($storage->instanceOfStorage('\OCA\Files_Sharing\SharedStorage')) { |
|
| 554 | + $includeExtStorage = false; |
|
| 555 | + $sourceStorage = $storage->getSourceStorage(); |
|
| 556 | + } |
|
| 557 | + if ($includeExtStorage) { |
|
| 558 | + if ($storage->instanceOfStorage('\OC\Files\Storage\Home') |
|
| 559 | + || $storage->instanceOfStorage('\OC\Files\ObjectStore\HomeObjectStoreStorage') |
|
| 560 | + ) { |
|
| 561 | + /** @var \OC\Files\Storage\Home $storage */ |
|
| 562 | + $userInstance = $storage->getUser(); |
|
| 563 | + $user = ($userInstance === null) ? null : $userInstance->getUID(); |
|
| 564 | + } else { |
|
| 565 | + $user = \OC::$server->getUserSession()->getUser()->getUID(); |
|
| 566 | + } |
|
| 567 | + if ($user) { |
|
| 568 | + $quota = OC_Util::getUserQuota($user); |
|
| 569 | + } else { |
|
| 570 | + $quota = \OCP\Files\FileInfo::SPACE_UNLIMITED; |
|
| 571 | + } |
|
| 572 | + if ($quota !== \OCP\Files\FileInfo::SPACE_UNLIMITED) { |
|
| 573 | + // always get free space / total space from root + mount points |
|
| 574 | + return self::getGlobalStorageInfo(); |
|
| 575 | + } |
|
| 576 | + } |
|
| 577 | + |
|
| 578 | + // TODO: need a better way to get total space from storage |
|
| 579 | + if ($sourceStorage->instanceOfStorage('\OC\Files\Storage\Wrapper\Quota')) { |
|
| 580 | + /** @var \OC\Files\Storage\Wrapper\Quota $storage */ |
|
| 581 | + $quota = $sourceStorage->getQuota(); |
|
| 582 | + } |
|
| 583 | + $free = $sourceStorage->free_space($rootInfo->getInternalPath()); |
|
| 584 | + if ($free >= 0) { |
|
| 585 | + $total = $free + $used; |
|
| 586 | + } else { |
|
| 587 | + $total = $free; //either unknown or unlimited |
|
| 588 | + } |
|
| 589 | + if ($total > 0) { |
|
| 590 | + if ($quota > 0 && $total > $quota) { |
|
| 591 | + $total = $quota; |
|
| 592 | + } |
|
| 593 | + // prevent division by zero or error codes (negative values) |
|
| 594 | + $relative = round(($used / $total) * 10000) / 100; |
|
| 595 | + } else { |
|
| 596 | + $relative = 0; |
|
| 597 | + } |
|
| 598 | + |
|
| 599 | + $ownerId = $storage->getOwner($path); |
|
| 600 | + $ownerDisplayName = ''; |
|
| 601 | + $owner = \OC::$server->getUserManager()->get($ownerId); |
|
| 602 | + if($owner) { |
|
| 603 | + $ownerDisplayName = $owner->getDisplayName(); |
|
| 604 | + } |
|
| 605 | + |
|
| 606 | + return [ |
|
| 607 | + 'free' => $free, |
|
| 608 | + 'used' => $used, |
|
| 609 | + 'quota' => $quota, |
|
| 610 | + 'total' => $total, |
|
| 611 | + 'relative' => $relative, |
|
| 612 | + 'owner' => $ownerId, |
|
| 613 | + 'ownerDisplayName' => $ownerDisplayName, |
|
| 614 | + ]; |
|
| 615 | + } |
|
| 616 | + |
|
| 617 | + /** |
|
| 618 | + * Get storage info including all mount points and quota |
|
| 619 | + * |
|
| 620 | + * @return array |
|
| 621 | + */ |
|
| 622 | + private static function getGlobalStorageInfo() { |
|
| 623 | + $quota = OC_Util::getUserQuota(\OCP\User::getUser()); |
|
| 624 | + |
|
| 625 | + $rootInfo = \OC\Files\Filesystem::getFileInfo('', 'ext'); |
|
| 626 | + $used = $rootInfo['size']; |
|
| 627 | + if ($used < 0) { |
|
| 628 | + $used = 0; |
|
| 629 | + } |
|
| 630 | + |
|
| 631 | + $total = $quota; |
|
| 632 | + $free = $quota - $used; |
|
| 633 | + |
|
| 634 | + if ($total > 0) { |
|
| 635 | + if ($quota > 0 && $total > $quota) { |
|
| 636 | + $total = $quota; |
|
| 637 | + } |
|
| 638 | + // prevent division by zero or error codes (negative values) |
|
| 639 | + $relative = round(($used / $total) * 10000) / 100; |
|
| 640 | + } else { |
|
| 641 | + $relative = 0; |
|
| 642 | + } |
|
| 643 | + |
|
| 644 | + return array('free' => $free, 'used' => $used, 'total' => $total, 'relative' => $relative); |
|
| 645 | + |
|
| 646 | + } |
|
| 647 | + |
|
| 648 | + /** |
|
| 649 | + * Returns whether the config file is set manually to read-only |
|
| 650 | + * @return bool |
|
| 651 | + */ |
|
| 652 | + public static function isReadOnlyConfigEnabled() { |
|
| 653 | + return \OC::$server->getConfig()->getSystemValue('config_is_read_only', false); |
|
| 654 | + } |
|
| 655 | 655 | } |
@@ -65,7 +65,7 @@ discard block |
||
| 65 | 65 | } else { |
| 66 | 66 | $url = OC::$server->getURLGenerator()->getAbsoluteURL(OC::$server->getURLGenerator()->linkTo('', 'public.php').'?service='.$service); |
| 67 | 67 | } |
| 68 | - return $url . (($add_slash && $service[strlen($service) - 1] != '/') ? '/' : ''); |
|
| 68 | + return $url.(($add_slash && $service[strlen($service) - 1] != '/') ? '/' : ''); |
|
| 69 | 69 | } |
| 70 | 70 | |
| 71 | 71 | /** |
@@ -115,18 +115,18 @@ discard block |
||
| 115 | 115 | return "?"; |
| 116 | 116 | } |
| 117 | 117 | if ($bytes < 1024) { |
| 118 | - return $bytes . "B"; |
|
| 118 | + return $bytes."B"; |
|
| 119 | 119 | } |
| 120 | 120 | $bytes = round($bytes / 1024, 1); |
| 121 | 121 | if ($bytes < 1024) { |
| 122 | - return $bytes . "K"; |
|
| 122 | + return $bytes."K"; |
|
| 123 | 123 | } |
| 124 | 124 | $bytes = round($bytes / 1024, 1); |
| 125 | 125 | if ($bytes < 1024) { |
| 126 | - return $bytes . "M"; |
|
| 126 | + return $bytes."M"; |
|
| 127 | 127 | } |
| 128 | 128 | $bytes = round($bytes / 1024, 1); |
| 129 | - return $bytes . "G"; |
|
| 129 | + return $bytes."G"; |
|
| 130 | 130 | } |
| 131 | 131 | |
| 132 | 132 | /** |
@@ -141,7 +141,7 @@ discard block |
||
| 141 | 141 | public static function computerFileSize($str) { |
| 142 | 142 | $str = strtolower($str); |
| 143 | 143 | if (is_numeric($str)) { |
| 144 | - return (float)$str; |
|
| 144 | + return (float) $str; |
|
| 145 | 145 | } |
| 146 | 146 | |
| 147 | 147 | $bytes_array = array( |
@@ -158,7 +158,7 @@ discard block |
||
| 158 | 158 | 'p' => 1024 * 1024 * 1024 * 1024 * 1024, |
| 159 | 159 | ); |
| 160 | 160 | |
| 161 | - $bytes = (float)$str; |
|
| 161 | + $bytes = (float) $str; |
|
| 162 | 162 | |
| 163 | 163 | if (preg_match('#([kmgtp]?b?)$#si', $str, $matches) && !empty($bytes_array[$matches[1]])) { |
| 164 | 164 | $bytes *= $bytes_array[$matches[1]]; |
@@ -272,7 +272,7 @@ discard block |
||
| 272 | 272 | } |
| 273 | 273 | foreach ($dirs as $dir) { |
| 274 | 274 | foreach ($exts as $ext) { |
| 275 | - if ($check_fn("$dir/$name" . $ext)) |
|
| 275 | + if ($check_fn("$dir/$name".$ext)) |
|
| 276 | 276 | return true; |
| 277 | 277 | } |
| 278 | 278 | } |
@@ -343,7 +343,7 @@ discard block |
||
| 343 | 343 | $ext = ''; |
| 344 | 344 | } |
| 345 | 345 | |
| 346 | - $newpath = $path . '/' . $filename; |
|
| 346 | + $newpath = $path.'/'.$filename; |
|
| 347 | 347 | if ($view->file_exists($newpath)) { |
| 348 | 348 | if (preg_match_all('/\((\d+)\)/', $name, $matches, PREG_OFFSET_CAPTURE)) { |
| 349 | 349 | //Replace the last "(number)" with "(number+1)" |
@@ -359,11 +359,11 @@ discard block |
||
| 359 | 359 | do { |
| 360 | 360 | if ($offset) { |
| 361 | 361 | //Replace the last "(number)" with "(number+1)" |
| 362 | - $newname = substr_replace($name, '(' . $counter . ')', $offset, $match_length); |
|
| 362 | + $newname = substr_replace($name, '('.$counter.')', $offset, $match_length); |
|
| 363 | 363 | } else { |
| 364 | - $newname = $name . ' (' . $counter . ')'; |
|
| 364 | + $newname = $name.' ('.$counter.')'; |
|
| 365 | 365 | } |
| 366 | - $newpath = $path . '/' . $newname . $ext; |
|
| 366 | + $newpath = $path.'/'.$newname.$ext; |
|
| 367 | 367 | $counter++; |
| 368 | 368 | } while ($view->file_exists($newpath)); |
| 369 | 369 | } |
@@ -426,7 +426,7 @@ discard block |
||
| 426 | 426 | * @return int number of bytes representing |
| 427 | 427 | */ |
| 428 | 428 | public static function maxUploadFilesize($dir, $freeSpace = null) { |
| 429 | - if (is_null($freeSpace) || $freeSpace < 0){ |
|
| 429 | + if (is_null($freeSpace) || $freeSpace < 0) { |
|
| 430 | 430 | $freeSpace = self::freeSpace($dir); |
| 431 | 431 | } |
| 432 | 432 | return min($freeSpace, self::uploadLimit()); |
@@ -444,7 +444,7 @@ discard block |
||
| 444 | 444 | $freeSpace = max($freeSpace, 0); |
| 445 | 445 | return $freeSpace; |
| 446 | 446 | } else { |
| 447 | - return (INF > 0)? INF: PHP_INT_MAX; // work around https://bugs.php.net/bug.php?id=69188 |
|
| 447 | + return (INF > 0) ? INF: PHP_INT_MAX; // work around https://bugs.php.net/bug.php?id=69188 |
|
| 448 | 448 | } |
| 449 | 449 | } |
| 450 | 450 | |
@@ -457,9 +457,9 @@ discard block |
||
| 457 | 457 | $ini = \OC::$server->getIniWrapper(); |
| 458 | 458 | $upload_max_filesize = OCP\Util::computerFileSize($ini->get('upload_max_filesize')); |
| 459 | 459 | $post_max_size = OCP\Util::computerFileSize($ini->get('post_max_size')); |
| 460 | - if ((int)$upload_max_filesize === 0 and (int)$post_max_size === 0) { |
|
| 460 | + if ((int) $upload_max_filesize === 0 and (int) $post_max_size === 0) { |
|
| 461 | 461 | return INF; |
| 462 | - } elseif ((int)$upload_max_filesize === 0 or (int)$post_max_size === 0) { |
|
| 462 | + } elseif ((int) $upload_max_filesize === 0 or (int) $post_max_size === 0) { |
|
| 463 | 463 | return max($upload_max_filesize, $post_max_size); //only the non 0 value counts |
| 464 | 464 | } else { |
| 465 | 465 | return min($upload_max_filesize, $post_max_size); |
@@ -511,9 +511,9 @@ discard block |
||
| 511 | 511 | if (empty($paths)) { |
| 512 | 512 | $paths = '/usr/local/bin /usr/bin /opt/bin /bin'; |
| 513 | 513 | } else { |
| 514 | - $paths = str_replace(':',' ',getenv('PATH')); |
|
| 514 | + $paths = str_replace(':', ' ', getenv('PATH')); |
|
| 515 | 515 | } |
| 516 | - $command = 'find ' . $paths . ' -name ' . escapeshellarg($program) . ' 2> /dev/null'; |
|
| 516 | + $command = 'find '.$paths.' -name '.escapeshellarg($program).' 2> /dev/null'; |
|
| 517 | 517 | exec($command, $output, $returnCode); |
| 518 | 518 | if (count($output) > 0) { |
| 519 | 519 | $result = escapeshellcmd($output[0]); |
@@ -599,7 +599,7 @@ discard block |
||
| 599 | 599 | $ownerId = $storage->getOwner($path); |
| 600 | 600 | $ownerDisplayName = ''; |
| 601 | 601 | $owner = \OC::$server->getUserManager()->get($ownerId); |
| 602 | - if($owner) { |
|
| 602 | + if ($owner) { |
|
| 603 | 603 | $ownerDisplayName = $owner->getDisplayName(); |
| 604 | 604 | } |
| 605 | 605 | |