aboutsummaryrefslogtreecommitdiffstats
path: root/lib/private/legacy
diff options
context:
space:
mode:
Diffstat (limited to 'lib/private/legacy')
-rw-r--r--lib/private/legacy/OC_API.php185
-rw-r--r--lib/private/legacy/OC_App.php610
-rw-r--r--lib/private/legacy/OC_Defaults.php78
-rw-r--r--lib/private/legacy/OC_EventSource.php125
-rw-r--r--lib/private/legacy/OC_FileChunking.php184
-rw-r--r--lib/private/legacy/OC_Files.php459
-rw-r--r--lib/private/legacy/OC_Helper.php412
-rw-r--r--lib/private/legacy/OC_Hook.php42
-rw-r--r--lib/private/legacy/OC_Image.php1152
-rw-r--r--lib/private/legacy/OC_JSON.php70
-rw-r--r--lib/private/legacy/OC_Response.php50
-rw-r--r--lib/private/legacy/OC_Template.php342
-rw-r--r--lib/private/legacy/OC_User.php152
-rw-r--r--lib/private/legacy/OC_Util.php563
-rw-r--r--lib/private/legacy/template/functions.php339
15 files changed, 452 insertions, 4311 deletions
diff --git a/lib/private/legacy/OC_API.php b/lib/private/legacy/OC_API.php
deleted file mode 100644
index 275e02986c4..00000000000
--- a/lib/private/legacy/OC_API.php
+++ /dev/null
@@ -1,185 +0,0 @@
-<?php
-/**
- * @copyright Copyright (c) 2016, ownCloud, Inc.
- *
- * @author Bart Visscher <bartv@thisnet.nl>
- * @author Björn Schießle <bjoern@schiessle.org>
- * @author Christoph Wurst <christoph@winzerhof-wurst.at>
- * @author Jörn Friedrich Dreyer <jfd@butonic.de>
- * @author Lukas Reschke <lukas@statuscode.ch>
- * @author Michael Gapczynski <GapczynskiM@gmail.com>
- * @author Morris Jobke <hey@morrisjobke.de>
- * @author Roeland Jago Douma <roeland@famdouma.nl>
- * @author Thomas Müller <thomas.mueller@tmit.eu>
- * @author Tom Needham <tom@owncloud.com>
- *
- * @license AGPL-3.0
- *
- * This code is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License, version 3,
- * as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License, version 3,
- * along with this program. If not, see <http://www.gnu.org/licenses/>
- *
- */
-use OCP\API;
-use OCP\AppFramework\Http;
-
-class OC_API {
- /**
- * api actions
- */
- protected static $actions = [];
-
- /**
- * respond to a call
- * @param \OC\OCS\Result $result
- * @param string $format the format xml|json
- * @psalm-taint-escape html
- */
- public static function respond($result, $format = 'xml') {
- $request = \OC::$server->getRequest();
-
- // Send 401 headers if unauthorised
- if ($result->getStatusCode() === \OCP\AppFramework\OCSController::RESPOND_UNAUTHORISED) {
- // If request comes from JS return dummy auth request
- if ($request->getHeader('X-Requested-With') === 'XMLHttpRequest') {
- header('WWW-Authenticate: DummyBasic realm="Authorisation Required"');
- } else {
- header('WWW-Authenticate: Basic realm="Authorisation Required"');
- }
- http_response_code(401);
- }
-
- foreach ($result->getHeaders() as $name => $value) {
- header($name . ': ' . $value);
- }
-
- $meta = $result->getMeta();
- $data = $result->getData();
- if (self::isV2($request)) {
- $statusCode = self::mapStatusCodes($result->getStatusCode());
- if (!is_null($statusCode)) {
- $meta['statuscode'] = $statusCode;
- http_response_code($statusCode);
- }
- }
-
- self::setContentType($format);
- $body = self::renderResult($format, $meta, $data);
- echo $body;
- }
-
- /**
- * @param XMLWriter $writer
- */
- private static function toXML($array, $writer) {
- foreach ($array as $k => $v) {
- if ($k[0] === '@') {
- $writer->writeAttribute(substr($k, 1), $v);
- continue;
- } elseif (is_numeric($k)) {
- $k = 'element';
- }
- if (is_array($v)) {
- $writer->startElement($k);
- self::toXML($v, $writer);
- $writer->endElement();
- } else {
- $writer->writeElement($k, $v);
- }
- }
- }
-
- public static function requestedFormat(): string {
- $formats = ['json', 'xml'];
-
- $format = (isset($_GET['format']) && is_string($_GET['format']) && in_array($_GET['format'], $formats)) ? $_GET['format'] : 'xml';
- return $format;
- }
-
- /**
- * Based on the requested format the response content type is set
- * @param string $format
- */
- public static function setContentType($format = null) {
- $format = is_null($format) ? self::requestedFormat() : $format;
- if ($format === 'xml') {
- header('Content-type: text/xml; charset=UTF-8');
- return;
- }
-
- if ($format === 'json') {
- header('Content-Type: application/json; charset=utf-8');
- return;
- }
-
- header('Content-Type: application/octet-stream; charset=utf-8');
- }
-
- /**
- * @param \OCP\IRequest $request
- * @return bool
- */
- protected static function isV2(\OCP\IRequest $request) {
- $script = $request->getScriptName();
-
- return substr($script, -11) === '/ocs/v2.php';
- }
-
- /**
- * @param integer $sc
- * @return int
- */
- public static function mapStatusCodes($sc) {
- switch ($sc) {
- case \OCP\AppFramework\OCSController::RESPOND_NOT_FOUND:
- return Http::STATUS_NOT_FOUND;
- case \OCP\AppFramework\OCSController::RESPOND_SERVER_ERROR:
- return Http::STATUS_INTERNAL_SERVER_ERROR;
- case \OCP\AppFramework\OCSController::RESPOND_UNKNOWN_ERROR:
- return Http::STATUS_INTERNAL_SERVER_ERROR;
- case \OCP\AppFramework\OCSController::RESPOND_UNAUTHORISED:
- // already handled for v1
- return null;
- case 100:
- return Http::STATUS_OK;
- }
- // any 2xx, 4xx and 5xx will be used as is
- if ($sc >= 200 && $sc < 600) {
- return $sc;
- }
-
- return Http::STATUS_BAD_REQUEST;
- }
-
- /**
- * @param string $format
- * @return string
- */
- public static function renderResult($format, $meta, $data) {
- $response = [
- 'ocs' => [
- 'meta' => $meta,
- 'data' => $data,
- ],
- ];
- if ($format == 'json') {
- return OC_JSON::encode($response);
- }
-
- $writer = new XMLWriter();
- $writer->openMemory();
- $writer->setIndent(true);
- $writer->startDocument();
- self::toXML($response, $writer);
- $writer->endDocument();
- return $writer->outputMemory(true);
- }
-}
diff --git a/lib/private/legacy/OC_App.php b/lib/private/legacy/OC_App.php
index c4c2f089767..10b78e2a7ef 100644
--- a/lib/private/legacy/OC_App.php
+++ b/lib/private/legacy/OC_App.php
@@ -1,80 +1,36 @@
<?php
declare(strict_types=1);
-
/**
- * @copyright Copyright (c) 2016, ownCloud, Inc.
- * @copyright Copyright (c) 2016, Lukas Reschke <lukas@statuscode.ch>
- *
- * @author Arthur Schiwon <blizzz@arthur-schiwon.de>
- * @author Bart Visscher <bartv@thisnet.nl>
- * @author Bernhard Posselt <dev@bernhard-posselt.com>
- * @author Borjan Tchakaloff <borjan@tchakaloff.fr>
- * @author Brice Maron <brice@bmaron.net>
- * @author Christopher Schäpers <kondou@ts.unde.re>
- * @author Christoph Wurst <christoph@winzerhof-wurst.at>
- * @author Daniel Rudolf <github.com@daniel-rudolf.de>
- * @author Frank Karlitschek <frank@karlitschek.de>
- * @author Georg Ehrke <oc.list@georgehrke.com>
- * @author Jakob Sack <mail@jakobsack.de>
- * @author Joas Schilling <coding@schilljs.com>
- * @author Jörn Friedrich Dreyer <jfd@butonic.de>
- * @author Julius Haertl <jus@bitgrid.net>
- * @author Julius Härtl <jus@bitgrid.net>
- * @author Kamil Domanski <kdomanski@kdemail.net>
- * @author Lukas Reschke <lukas@statuscode.ch>
- * @author Markus Goetz <markus@woboq.com>
- * @author Morris Jobke <hey@morrisjobke.de>
- * @author RealRancor <Fisch.666@gmx.de>
- * @author Robin Appelman <robin@icewind.nl>
- * @author Robin McCorkell <robin@mccorkell.me.uk>
- * @author Roeland Jago Douma <roeland@famdouma.nl>
- * @author Sam Tuke <mail@samtuke.com>
- * @author Sebastian Wessalowski <sebastian@wessalowski.org>
- * @author Thomas Müller <thomas.mueller@tmit.eu>
- * @author Thomas Tanghus <thomas@tanghus.net>
- * @author Vincent Petry <vincent@nextcloud.com>
- *
- * @license AGPL-3.0
- *
- * This code is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License, version 3,
- * as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License, version 3,
- * along with this program. If not, see <http://www.gnu.org/licenses/>
- *
+ * SPDX-FileCopyrightText: 2016 Nextcloud GmbH and Nextcloud contributors
+ * SPDX-FileCopyrightText: 2016 ownCloud, Inc.
+ * SPDX-License-Identifier: AGPL-3.0-only
*/
-use OCP\AppFramework\QueryException;
-use OCP\App\ManagerEvent;
-use OCP\Authentication\IAlternativeLogin;
-use OCP\ILogger;
-use OCP\Settings\IManager as ISettingsManager;
-use OC\AppFramework\Bootstrap\Coordinator;
use OC\App\DependencyAnalyzer;
use OC\App\Platform;
+use OC\AppFramework\Bootstrap\Coordinator;
+use OC\Config\ConfigManager;
use OC\DB\MigrationService;
use OC\Installer;
use OC\Repair;
use OC\Repair\Events\RepairErrorEvent;
-use OC\ServerNotAvailableException;
+use OCP\App\Events\AppUpdateEvent;
+use OCP\App\IAppManager;
+use OCP\App\ManagerEvent;
+use OCP\Authentication\IAlternativeLogin;
+use OCP\EventDispatcher\IEventDispatcher;
+use OCP\IAppConfig;
+use OCP\Server;
+use Psr\Container\ContainerExceptionInterface;
use Psr\Log\LoggerInterface;
+use function OCP\Log\logger;
/**
* This class manages the apps. It allows them to register and integrate in the
- * ownCloud ecosystem. Furthermore, this class is responsible for installing,
+ * Nextcloud ecosystem. Furthermore, this class is responsible for installing,
* upgrading and removing apps.
*/
class OC_App {
- private static $adminForms = [];
- private static $personalForms = [];
- private static $appTypes = [];
- private static $loadedApps = [];
private static $altLogin = [];
private static $alreadyRegistered = [];
public const supportedApp = 300;
@@ -85,12 +41,13 @@ class OC_App {
*
* @psalm-taint-escape file
* @psalm-taint-escape include
+ * @psalm-taint-escape html
+ * @psalm-taint-escape has_quotes
*
- * @param string $app AppId that needs to be cleaned
- * @return string
+ * @deprecated 31.0.0 use IAppManager::cleanAppId
*/
public static function cleanAppId(string $app): string {
- return str_replace(['\0', '/', '\\', '..'], '', $app);
+ return str_replace(['<', '>', '"', "'", '\0', '/', '\\', '..'], '', $app);
}
/**
@@ -98,9 +55,10 @@ class OC_App {
*
* @param string $app
* @return bool
+ * @deprecated 27.0.0 use IAppManager::isAppLoaded
*/
public static function isAppLoaded(string $app): bool {
- return isset(self::$loadedApps[$app]);
+ return \OC::$server->get(IAppManager::class)->isAppLoaded($app);
}
/**
@@ -109,47 +67,20 @@ class OC_App {
* @param string[] $types
* @return bool
*
- * This function walks through the ownCloud directory and loads all apps
+ * This function walks through the Nextcloud directory and loads all apps
* it can find. A directory contains an app if the file /appinfo/info.xml
* exists.
*
* if $types is set to non-empty array, only apps of those types will be loaded
+ *
+ * @deprecated 29.0.0 use IAppManager::loadApps instead
*/
public static function loadApps(array $types = []): bool {
- if ((bool) \OC::$server->getSystemConfig()->getValue('maintenance', false)) {
+ if (!\OC::$server->getSystemConfig()->getValue('installed', false)) {
+ // This should be done before calling this method so that appmanager can be used
return false;
}
- // Load the enabled apps here
- $apps = self::getEnabledApps();
-
- // Add each apps' folder as allowed class path
- foreach ($apps as $app) {
- // If the app is already loaded then autoloading it makes no sense
- if (!isset(self::$loadedApps[$app])) {
- $path = self::getAppPath($app);
- if ($path !== false) {
- self::registerAutoloading($app, $path);
- }
- }
- }
-
- // prevent app.php from printing output
- ob_start();
- foreach ($apps as $app) {
- if (!isset(self::$loadedApps[$app]) && ($types === [] || self::isType($app, $types))) {
- try {
- self::loadApp($app);
- } catch (\Throwable $e) {
- \OC::$server->get(LoggerInterface::class)->emergency('Error during app loading: ' . $e->getMessage(), [
- 'exception' => $e,
- 'app' => $app,
- ]);
- }
- }
- }
- ob_end_clean();
-
- return true;
+ return \OC::$server->get(IAppManager::class)->loadApps($types);
}
/**
@@ -157,110 +88,10 @@ class OC_App {
*
* @param string $app
* @throws Exception
+ * @deprecated 27.0.0 use IAppManager::loadApp
*/
- public static function loadApp(string $app) {
- self::$loadedApps[$app] = true;
- $appPath = self::getAppPath($app);
- if ($appPath === false) {
- return;
- }
-
- // in case someone calls loadApp() directly
- self::registerAutoloading($app, $appPath);
-
- /** @var Coordinator $coordinator */
- $coordinator = \OC::$server->query(Coordinator::class);
- $isBootable = $coordinator->isBootable($app);
-
- $hasAppPhpFile = is_file($appPath . '/appinfo/app.php');
-
- \OC::$server->getEventLogger()->start('bootstrap:load_app_' . $app, 'Load app: ' . $app);
- if ($isBootable && $hasAppPhpFile) {
- \OC::$server->getLogger()->error('/appinfo/app.php is not loaded when \OCP\AppFramework\Bootstrap\IBootstrap on the application class is used. Migrate everything from app.php to the Application class.', [
- 'app' => $app,
- ]);
- } elseif ($hasAppPhpFile) {
- \OC::$server->getLogger()->debug('/appinfo/app.php is deprecated, use \OCP\AppFramework\Bootstrap\IBootstrap on the application class instead.', [
- 'app' => $app,
- ]);
- try {
- self::requireAppFile($appPath);
- } catch (Throwable $ex) {
- if ($ex instanceof ServerNotAvailableException) {
- throw $ex;
- }
- if (!\OC::$server->getAppManager()->isShipped($app) && !self::isType($app, ['authentication'])) {
- \OC::$server->getLogger()->logException($ex, [
- 'message' => "App $app threw an error during app.php load and will be disabled: " . $ex->getMessage(),
- ]);
-
- // Only disable apps which are not shipped and that are not authentication apps
- \OC::$server->getAppManager()->disableApp($app, true);
- } else {
- \OC::$server->getLogger()->logException($ex, [
- 'message' => "App $app threw an error during app.php load: " . $ex->getMessage(),
- ]);
- }
- }
- }
- \OC::$server->getEventLogger()->end('bootstrap:load_app_' . $app);
-
- $coordinator->bootApp($app);
-
- $info = self::getAppInfo($app);
- if (!empty($info['activity']['filters'])) {
- foreach ($info['activity']['filters'] as $filter) {
- \OC::$server->getActivityManager()->registerFilter($filter);
- }
- }
- if (!empty($info['activity']['settings'])) {
- foreach ($info['activity']['settings'] as $setting) {
- \OC::$server->getActivityManager()->registerSetting($setting);
- }
- }
- if (!empty($info['activity']['providers'])) {
- foreach ($info['activity']['providers'] as $provider) {
- \OC::$server->getActivityManager()->registerProvider($provider);
- }
- }
-
- if (!empty($info['settings']['admin'])) {
- foreach ($info['settings']['admin'] as $setting) {
- \OC::$server->get(ISettingsManager::class)->registerSetting('admin', $setting);
- }
- }
- if (!empty($info['settings']['admin-section'])) {
- foreach ($info['settings']['admin-section'] as $section) {
- \OC::$server->get(ISettingsManager::class)->registerSection('admin', $section);
- }
- }
- if (!empty($info['settings']['personal'])) {
- foreach ($info['settings']['personal'] as $setting) {
- \OC::$server->get(ISettingsManager::class)->registerSetting('personal', $setting);
- }
- }
- if (!empty($info['settings']['personal-section'])) {
- foreach ($info['settings']['personal-section'] as $section) {
- \OC::$server->get(ISettingsManager::class)->registerSection('personal', $section);
- }
- }
-
- if (!empty($info['collaboration']['plugins'])) {
- // deal with one or many plugin entries
- $plugins = isset($info['collaboration']['plugins']['plugin']['@value']) ?
- [$info['collaboration']['plugins']['plugin']] : $info['collaboration']['plugins']['plugin'];
- foreach ($plugins as $plugin) {
- if ($plugin['@attributes']['type'] === 'collaborator-search') {
- $pluginInfo = [
- 'shareType' => $plugin['@attributes']['share-type'],
- 'class' => $plugin['@value'],
- ];
- \OC::$server->getCollaboratorSearch()->registerPlugin($pluginInfo);
- } elseif ($plugin['@attributes']['type'] === 'autocomplete-sort') {
- \OC::$server->getAutoCompleteManager()->registerSorter($plugin['@value']);
- }
- }
- }
+ public static function loadApp(string $app): void {
+ \OC::$server->get(IAppManager::class)->loadApp($app);
}
/**
@@ -285,8 +116,6 @@ class OC_App {
require_once $path . '/composer/autoload.php';
} else {
\OC::$composerAutoloader->addPsr4($appNamespace . '\\', $path . '/lib/', true);
- // Register on legacy autoloader
- \OC::$loader->addValidRoot($path);
}
// Register Test namespace only when testing
@@ -296,50 +125,15 @@ class OC_App {
}
/**
- * Load app.php from the given app
- *
- * @param string $app app name
- * @throws Error
- */
- private static function requireAppFile(string $app) {
- // encapsulated here to avoid variable scope conflicts
- require_once $app . '/appinfo/app.php';
- }
-
- /**
* check if an app is of a specific type
*
* @param string $app
* @param array $types
* @return bool
+ * @deprecated 27.0.0 use IAppManager::isType
*/
public static function isType(string $app, array $types): bool {
- $appTypes = self::getAppTypes($app);
- foreach ($types as $type) {
- if (array_search($type, $appTypes) !== false) {
- return true;
- }
- }
- return false;
- }
-
- /**
- * get the types of an app
- *
- * @param string $app
- * @return array
- */
- private static function getAppTypes(string $app): array {
- //load the cache
- if (count(self::$appTypes) == 0) {
- self::$appTypes = \OC::$server->getAppConfig()->getValues(false, 'types');
- }
-
- if (isset(self::$appTypes[$app])) {
- return explode(',', self::$appTypes[$app]);
- }
-
- return [];
+ return \OC::$server->get(IAppManager::class)->isType($app, $types);
}
/**
@@ -375,8 +169,8 @@ class OC_App {
*
* @param bool $forceRefresh whether to refresh the cache
* @param bool $all whether to return apps for all users, not only the
- * currently logged in one
- * @return string[]
+ * currently logged in one
+ * @return list<string>
*/
public static function getEnabledApps(bool $forceRefresh = false, bool $all = false): array {
if (!\OC::$server->getSystemConfig()->getValue('installed', false)) {
@@ -392,7 +186,7 @@ class OC_App {
}
if (is_null($user)) {
- $apps = $appManager->getInstalledApps();
+ $apps = $appManager->getEnabledApps();
} else {
$apps = $appManager->getEnabledAppsForUser($user);
}
@@ -405,19 +199,6 @@ class OC_App {
}
/**
- * checks whether or not an app is enabled
- *
- * @param string $app app
- * @return bool
- * @deprecated 13.0.0 use \OC::$server->getAppManager()->isEnabledForUser($appId)
- *
- * This function checks whether or not an app is enabled.
- */
- public static function isEnabled(string $app): bool {
- return \OC::$server->getAppManager()->isEnabledForUser($app);
- }
-
- /**
* enables an app
*
* @param string $appId
@@ -428,10 +209,10 @@ class OC_App {
* This function set an app as enabled in appconfig.
*/
public function enable(string $appId,
- array $groups = []) {
+ array $groups = []) {
// Check if app is already downloaded
/** @var Installer $installer */
- $installer = \OC::$server->query(Installer::class);
+ $installer = Server::get(Installer::class);
$isDownloaded = $installer->isDownloaded($appId);
if (!$isDownloaded) {
@@ -457,28 +238,13 @@ class OC_App {
}
/**
- * Get the path where to install apps
+ * Find the apps root for an app id.
*
- * @return string|false
- */
- public static function getInstallPath() {
- foreach (OC::$APPSROOTS as $dir) {
- if (isset($dir['writable']) && $dir['writable'] === true) {
- return $dir['path'];
- }
- }
-
- \OCP\Util::writeLog('core', 'No application directories are marked as writable.', ILogger::ERROR);
- return null;
- }
-
-
- /**
- * search for an app in all app-directories
+ * If multiple copies are found, the apps root the latest version is returned.
*
* @param string $appId
* @param bool $ignoreCache ignore cache and rebuild it
- * @return false|string
+ * @return false|array{path: string, url: string} the apps root shape
*/
public static function findAppInDirectories(string $appId, bool $ignoreCache = false) {
$sanitizedAppId = self::cleanAppId($appId);
@@ -530,11 +296,14 @@ class OC_App {
* @param string $appId
* @param bool $refreshAppPath should be set to true only during install/upgrade
* @return string|false
- * @deprecated 11.0.0 use \OC::$server->getAppManager()->getAppPath()
+ * @deprecated 11.0.0 use Server::get(IAppManager)->getAppPath()
*/
public static function getAppPath(string $appId, bool $refreshAppPath = false) {
- if ($appId === null || trim($appId) === '') {
+ $appId = self::cleanAppId($appId);
+ if ($appId === '') {
return false;
+ } elseif ($appId === 'core') {
+ return __DIR__ . '/../../../core';
}
if (($dir = self::findAppInDirectories($appId, $refreshAppPath)) != false) {
@@ -559,18 +328,6 @@ class OC_App {
}
/**
- * get the last version of the app from appinfo/info.xml
- *
- * @param string $appId
- * @param bool $useCache
- * @return string
- * @deprecated 14.0.0 use \OC::$server->getAppManager()->getAppVersion()
- */
- public static function getAppVersion(string $appId, bool $useCache = true): string {
- return \OC::$server->getAppManager()->getAppVersion($appId, $useCache);
- }
-
- /**
* get app's version based on it's path
*
* @param string $path
@@ -578,51 +335,8 @@ class OC_App {
*/
public static function getAppVersionByPath(string $path): string {
$infoFile = $path . '/appinfo/info.xml';
- $appData = \OC::$server->getAppManager()->getAppInfo($infoFile, true);
- return isset($appData['version']) ? $appData['version'] : '';
- }
-
-
- /**
- * Read all app metadata from the info.xml file
- *
- * @param string $appId id of the app or the path of the info.xml file
- * @param bool $path
- * @param string $lang
- * @return array|null
- * @note all data is read from info.xml, not just pre-defined fields
- * @deprecated 14.0.0 use \OC::$server->getAppManager()->getAppInfo()
- */
- public static function getAppInfo(string $appId, bool $path = false, string $lang = null) {
- return \OC::$server->getAppManager()->getAppInfo($appId, $path, $lang);
- }
-
- /**
- * Returns the navigation
- *
- * @return array
- * @deprecated 14.0.0 use \OC::$server->getNavigationManager()->getAll()
- *
- * This function returns an array containing all entries added. The
- * entries are sorted by the key 'order' ascending. Additional to the keys
- * given for each app the following keys exist:
- * - active: boolean, signals if the user is on this navigation entry
- */
- public static function getNavigation(): array {
- return OC::$server->getNavigationManager()->getAll();
- }
-
- /**
- * Returns the Settings Navigation
- *
- * @return string[]
- * @deprecated 14.0.0 use \OC::$server->getNavigationManager()->getAll('settings')
- *
- * This function returns an array containing all settings pages added. The
- * entries are sorted by the key 'order' ascending.
- */
- public static function getSettingsNavigation(): array {
- return OC::$server->getNavigationManager()->getAll('settings');
+ $appData = Server::get(IAppManager::class)->getAppInfoByPath($infoFile);
+ return $appData['version'] ?? '';
}
/**
@@ -659,33 +373,11 @@ class OC_App {
}
/**
- * @param string $type
- * @return array
- */
- public static function getForms(string $type): array {
- $forms = [];
- switch ($type) {
- case 'admin':
- $source = self::$adminForms;
- break;
- case 'personal':
- $source = self::$personalForms;
- break;
- default:
- return [];
- }
- foreach ($source as $form) {
- $forms[] = include $form;
- }
- return $forms;
- }
-
- /**
* @param array $entry
* @deprecated 20.0.0 Please register your alternative login option using the registerAlternativeLogin() on the RegistrationContext in your Application class implementing the OCP\Authentication\IAlternativeLogin interface
*/
public static function registerLogIn(array $entry) {
- \OC::$server->getLogger()->debug('OC_App::registerLogIn() is deprecated, please register your alternative login option using the registerAlternativeLogin() on the RegistrationContext in your Application class implementing the OCP\Authentication\IAlternativeLogin interface');
+ Server::get(LoggerInterface::class)->debug('OC_App::registerLogIn() is deprecated, please register your alternative login option using the registerAlternativeLogin() on the RegistrationContext in your Application class implementing the OCP\Authentication\IAlternativeLogin interface');
self::$altLogin[] = $entry;
}
@@ -694,11 +386,11 @@ class OC_App {
*/
public static function getAlternativeLogIns(): array {
/** @var Coordinator $bootstrapCoordinator */
- $bootstrapCoordinator = \OC::$server->query(Coordinator::class);
+ $bootstrapCoordinator = Server::get(Coordinator::class);
foreach ($bootstrapCoordinator->getRegistrationContext()->getAlternativeLogins() as $registration) {
if (!in_array(IAlternativeLogin::class, class_implements($registration->getService()), true)) {
- \OC::$server->getLogger()->error('Alternative login option {option} does not implement {interface} and is therefore ignored.', [
+ Server::get(LoggerInterface::class)->error('Alternative login option {option} does not implement {interface} and is therefore ignored.', [
'option' => $registration->getService(),
'interface' => IAlternativeLogin::class,
'app' => $registration->getAppId(),
@@ -708,13 +400,14 @@ class OC_App {
try {
/** @var IAlternativeLogin $provider */
- $provider = \OC::$server->query($registration->getService());
- } catch (QueryException $e) {
- \OC::$server->getLogger()->logException($e, [
- 'message' => 'Alternative login option {option} can not be initialised.',
- 'option' => $registration->getService(),
- 'app' => $registration->getAppId(),
- ]);
+ $provider = Server::get($registration->getService());
+ } catch (ContainerExceptionInterface $e) {
+ Server::get(LoggerInterface::class)->error('Alternative login option {option} can not be initialized.',
+ [
+ 'exception' => $e,
+ 'option' => $registration->getService(),
+ 'app' => $registration->getAppId(),
+ ]);
}
try {
@@ -726,11 +419,12 @@ class OC_App {
'class' => $provider->getClass(),
];
} catch (Throwable $e) {
- \OC::$server->getLogger()->logException($e, [
- 'message' => 'Alternative login option {option} had an error while loading.',
- 'option' => $registration->getService(),
- 'app' => $registration->getAppId(),
- ]);
+ Server::get(LoggerInterface::class)->error('Alternative login option {option} had an error while loading.',
+ [
+ 'exception' => $e,
+ 'option' => $registration->getService(),
+ 'app' => $registration->getAppId(),
+ ]);
}
}
@@ -741,40 +435,19 @@ class OC_App {
* get a list of all apps in the apps folder
*
* @return string[] an array of app names (string IDs)
- * @todo: change the name of this method to getInstalledApps, which is more accurate
+ * @deprecated 31.0.0 Use IAppManager::getAllAppsInAppsFolders instead
*/
public static function getAllApps(): array {
- $apps = [];
-
- foreach (OC::$APPSROOTS as $apps_dir) {
- if (!is_readable($apps_dir['path'])) {
- \OCP\Util::writeLog('core', 'unable to read app folder : ' . $apps_dir['path'], ILogger::WARN);
- continue;
- }
- $dh = opendir($apps_dir['path']);
-
- if (is_resource($dh)) {
- while (($file = readdir($dh)) !== false) {
- if ($file[0] != '.' and is_dir($apps_dir['path'] . '/' . $file) and is_file($apps_dir['path'] . '/' . $file . '/appinfo/info.xml')) {
- $apps[] = $file;
- }
- }
- }
- }
-
- $apps = array_unique($apps);
-
- return $apps;
+ return Server::get(IAppManager::class)->getAllAppsInAppsFolders();
}
/**
* List all supported apps
*
- * @return array
+ * @deprecated 32.0.0 Use \OCP\Support\Subscription\IRegistry::delegateGetSupportedApps instead
*/
public function getSupportedApps(): array {
- /** @var \OCP\Support\Subscription\IRegistry $subscriptionRegistry */
- $subscriptionRegistry = \OC::$server->query(\OCP\Support\Subscription\IRegistry::class);
+ $subscriptionRegistry = Server::get(\OCP\Support\Subscription\IRegistry::class);
$supportedApps = $subscriptionRegistry->delegateGetSupportedApps();
return $supportedApps;
}
@@ -785,9 +458,9 @@ class OC_App {
* @return array
*/
public function listAllApps(): array {
- $installedApps = OC_App::getAllApps();
-
$appManager = \OC::$server->getAppManager();
+
+ $installedApps = $appManager->getAllAppsInAppsFolders();
//we don't want to show configuration for these
$blacklist = $appManager->getAlwaysEnabledApps();
$appList = [];
@@ -796,15 +469,15 @@ class OC_App {
$supportedApps = $this->getSupportedApps();
foreach ($installedApps as $app) {
- if (array_search($app, $blacklist) === false) {
- $info = OC_App::getAppInfo($app, false, $langCode);
+ if (!in_array($app, $blacklist)) {
+ $info = $appManager->getAppInfo($app, false, $langCode);
if (!is_array($info)) {
- \OCP\Util::writeLog('core', 'Could not read app info file for app "' . $app . '"', ILogger::ERROR);
+ Server::get(LoggerInterface::class)->error('Could not read app info file for app "' . $app . '"', ['app' => 'core']);
continue;
}
if (!isset($info['name'])) {
- \OCP\Util::writeLog('core', 'App id "' . $app . '" has no name in appinfo', ILogger::ERROR);
+ Server::get(LoggerInterface::class)->error('App id "' . $app . '" has no name in appinfo', ['app' => 'core']);
continue;
}
@@ -861,7 +534,7 @@ class OC_App {
}
}
- $info['version'] = OC_App::getAppVersion($app);
+ $info['version'] = $appManager->getAppVersion($app);
$appList[] = $info;
}
}
@@ -871,7 +544,7 @@ class OC_App {
public static function shouldUpgrade(string $app): bool {
$versions = self::getAppVersions();
- $currentVersion = OC_App::getAppVersion($app);
+ $currentVersion = Server::get(\OCP\App\IAppManager::class)->getAppVersion($app);
if ($currentVersion && isset($versions[$app])) {
$installedVersion = $versions[$app];
if (!version_compare($currentVersion, $installedVersion, '=')) {
@@ -904,7 +577,7 @@ class OC_App {
}
/**
- * Check whether the current ownCloud version matches the given
+ * Check whether the current Nextcloud version matches the given
* application's version requirements.
*
* The comparison is made based on the number of parts that the
@@ -914,7 +587,7 @@ class OC_App {
* This means that it's possible to specify "requiremin" => 6
* and "requiremax" => 6 and it will still match ownCloud 6.0.3.
*
- * @param string $ocVersion ownCloud version to check against
+ * @param string $ocVersion Nextcloud version to check against
* @param array $appInfo app info (from xml)
*
* @return boolean true if compatible, otherwise false
@@ -957,15 +630,10 @@ class OC_App {
/**
* get the installed version of all apps
+ * @deprecated 32.0.0 Use IAppManager::getAppInstalledVersions or IAppConfig::getAppInstalledVersions instead
*/
- public static function getAppVersions() {
- static $versions;
-
- if (!$versions) {
- $appConfig = \OC::$server->getAppConfig();
- $versions = $appConfig->getValues(false, 'installed_version');
- }
- return $versions;
+ public static function getAppVersions(): array {
+ return Server::get(IAppConfig::class)->getAppInstalledVersions();
}
/**
@@ -983,13 +651,13 @@ class OC_App {
}
if (is_file($appPath . '/appinfo/database.xml')) {
- \OC::$server->getLogger()->error('The appinfo/database.xml file is not longer supported. Used in ' . $appId);
+ Server::get(LoggerInterface::class)->error('The appinfo/database.xml file is not longer supported. Used in ' . $appId);
return false;
}
\OC::$server->getAppManager()->clearAppsCache();
$l = \OC::$server->getL10N('core');
- $appData = self::getAppInfo($appId, false, $l->getLanguageCode());
+ $appData = Server::get(\OCP\App\IAppManager::class)->getAppInfo($appId, false, $l->getLanguageCode());
$ignoreMaxApps = \OC::$server->getConfig()->getSystemValue('app_install_overwrite', []);
$ignoreMax = in_array($appId, $ignoreMaxApps, true);
@@ -1029,10 +697,15 @@ class OC_App {
self::setAppTypes($appId);
- $version = \OC_App::getAppVersion($appId);
+ $version = Server::get(\OCP\App\IAppManager::class)->getAppVersion($appId);
\OC::$server->getConfig()->setAppValue($appId, 'installed_version', $version);
- \OC::$server->getEventDispatcher()->dispatch(ManagerEvent::EVENT_APP_UPDATE, new ManagerEvent(
+ // migrate eventual new config keys in the process
+ /** @psalm-suppress InternalMethod */
+ Server::get(ConfigManager::class)->migrateConfigLexiconKeys($appId);
+
+ \OC::$server->get(IEventDispatcher::class)->dispatchTyped(new AppUpdateEvent($appId));
+ \OC::$server->get(IEventDispatcher::class)->dispatch(ManagerEvent::EVENT_APP_UPDATE, new ManagerEvent(
ManagerEvent::EVENT_APP_UPDATE, $appId
));
@@ -1051,16 +724,16 @@ class OC_App {
// load the app
self::loadApp($appId);
- $dispatcher = \OC::$server->get(\OCP\EventDispatcher\IEventDispatcher::class);
+ $dispatcher = Server::get(IEventDispatcher::class);
// load the steps
- $r = new Repair([], $dispatcher, \OC::$server->get(LoggerInterface::class));
+ $r = Server::get(Repair::class);
foreach ($steps as $step) {
try {
$r->addStep($step);
} catch (Exception $ex) {
$dispatcher->dispatchTyped(new RepairErrorEvent($ex->getMessage()));
- \OC::$server->getLogger()->logException($ex);
+ logger('core')->error('Failed to add app migration step ' . $step, ['exception' => $ex]);
}
}
// run the steps
@@ -1088,103 +761,6 @@ class OC_App {
}
/**
- * @param string $appId
- * @return \OC\Files\View|false
- */
- public static function getStorage(string $appId) {
- if (\OC::$server->getAppManager()->isEnabledForUser($appId)) { //sanity check
- if (\OC::$server->getUserSession()->isLoggedIn()) {
- $view = new \OC\Files\View('/' . OC_User::getUser());
- if (!$view->file_exists($appId)) {
- $view->mkdir($appId);
- }
- return new \OC\Files\View('/' . OC_User::getUser() . '/' . $appId);
- } else {
- \OCP\Util::writeLog('core', 'Can\'t get app storage, app ' . $appId . ', user not logged in', ILogger::ERROR);
- return false;
- }
- } else {
- \OCP\Util::writeLog('core', 'Can\'t get app storage, app ' . $appId . ' not enabled', ILogger::ERROR);
- return false;
- }
- }
-
- protected static function findBestL10NOption(array $options, string $lang): string {
- // only a single option
- if (isset($options['@value'])) {
- return $options['@value'];
- }
-
- $fallback = $similarLangFallback = $englishFallback = false;
-
- $lang = strtolower($lang);
- $similarLang = $lang;
- if (strpos($similarLang, '_')) {
- // For "de_DE" we want to find "de" and the other way around
- $similarLang = substr($lang, 0, strpos($lang, '_'));
- }
-
- foreach ($options as $option) {
- if (is_array($option)) {
- if ($fallback === false) {
- $fallback = $option['@value'];
- }
-
- if (!isset($option['@attributes']['lang'])) {
- continue;
- }
-
- $attributeLang = strtolower($option['@attributes']['lang']);
- if ($attributeLang === $lang) {
- return $option['@value'];
- }
-
- if ($attributeLang === $similarLang) {
- $similarLangFallback = $option['@value'];
- } elseif (strpos($attributeLang, $similarLang . '_') === 0) {
- if ($similarLangFallback === false) {
- $similarLangFallback = $option['@value'];
- }
- }
- } else {
- $englishFallback = $option;
- }
- }
-
- if ($similarLangFallback !== false) {
- return $similarLangFallback;
- } elseif ($englishFallback !== false) {
- return $englishFallback;
- }
- return (string) $fallback;
- }
-
- /**
- * parses the app data array and enhanced the 'description' value
- *
- * @param array $data the app data
- * @param string $lang
- * @return array improved app data
- */
- public static function parseAppInfo(array $data, $lang = null): array {
- if ($lang && isset($data['name']) && is_array($data['name'])) {
- $data['name'] = self::findBestL10NOption($data['name'], $lang);
- }
- if ($lang && isset($data['summary']) && is_array($data['summary'])) {
- $data['summary'] = self::findBestL10NOption($data['summary'], $lang);
- }
- if ($lang && isset($data['description']) && is_array($data['description'])) {
- $data['description'] = trim(self::findBestL10NOption($data['description'], $lang));
- } elseif (isset($data['description']) && is_string($data['description'])) {
- $data['description'] = trim($data['description']);
- } else {
- $data['description'] = '';
- }
-
- return $data;
- }
-
- /**
* @param \OCP\IConfig $config
* @param \OCP\IL10N $l
* @param array $info
diff --git a/lib/private/legacy/OC_Defaults.php b/lib/private/legacy/OC_Defaults.php
index 707df7279bb..0d460ff966d 100644
--- a/lib/private/legacy/OC_Defaults.php
+++ b/lib/private/legacy/OC_Defaults.php
@@ -1,42 +1,15 @@
<?php
+
/**
- * @copyright Copyright (c) 2016, ownCloud, Inc.
- *
- * @author Björn Schießle <bjoern@schiessle.org>
- * @author Christoph Wurst <christoph@winzerhof-wurst.at>
- * @author Daniel Kesselberg <mail@danielkesselberg.de>
- * @author Jan-Christoph Borchardt <hey@jancborchardt.net>
- * @author Jörn Friedrich Dreyer <jfd@butonic.de>
- * @author Julius Haertl <jus@bitgrid.net>
- * @author Julius Härtl <jus@bitgrid.net>
- * @author Lukas Reschke <lukas@statuscode.ch>
- * @author Markus Staab <markus.staab@redaxo.de>
- * @author Michael Weimann <mail@michael-weimann.eu>
- * @author Morris Jobke <hey@morrisjobke.de>
- * @author Pascal de Bruijn <pmjdebruijn@pcode.nl>
- * @author Robin Appelman <robin@icewind.nl>
- * @author Robin McCorkell <robin@mccorkell.me.uk>
- * @author Roeland Jago Douma <roeland@famdouma.nl>
- * @author scolebrook <scolebrook@mac.com>
- * @author Thomas Müller <thomas.mueller@tmit.eu>
- * @author Volkan Gezer <volkangezer@gmail.com>
- *
- * @license AGPL-3.0
- *
- * This code is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License, version 3,
- * as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License, version 3,
- * along with this program. If not, see <http://www.gnu.org/licenses/>
- *
+ * SPDX-FileCopyrightText: 2016-2024 Nextcloud GmbH and Nextcloud contributors
+ * SPDX-FileCopyrightText: 2016 ownCloud, Inc.
+ * SPDX-License-Identifier: AGPL-3.0-only
*/
+use OCP\IConfig;
+use OCP\Server;
+use OCP\ServerVersion;
+
class OC_Defaults {
private $theme;
@@ -52,12 +25,14 @@ class OC_Defaults {
private $defaultDocBaseUrl;
private $defaultDocVersion;
private $defaultSlogan;
+ private $defaultColorBackground;
private $defaultColorPrimary;
private $defaultTextColorPrimary;
private $defaultProductName;
public function __construct() {
- $config = \OC::$server->getConfig();
+ $config = Server::get(IConfig::class);
+ $serverVersion = Server::get(ServerVersion::class);
$this->defaultEntity = 'Nextcloud'; /* e.g. company name, used for footers and copyright notices */
$this->defaultName = 'Nextcloud'; /* short name, used when referring to the software */
@@ -69,8 +44,9 @@ class OC_Defaults {
$this->defaultAndroidClientUrl = $config->getSystemValue('customclient_android', 'https://play.google.com/store/apps/details?id=com.nextcloud.client');
$this->defaultFDroidClientUrl = $config->getSystemValue('customclient_fdroid', 'https://f-droid.org/packages/com.nextcloud.client/');
$this->defaultDocBaseUrl = 'https://docs.nextcloud.com';
- $this->defaultDocVersion = \OC_Util::getVersion()[0]; // used to generate doc links
- $this->defaultColorPrimary = '#0082c9';
+ $this->defaultDocVersion = $serverVersion->getMajorVersion(); // used to generate doc links
+ $this->defaultColorBackground = '#00679e';
+ $this->defaultColorPrimary = '#00679e';
$this->defaultTextColorPrimary = '#ffffff';
$this->defaultProductName = 'Nextcloud';
@@ -245,15 +221,6 @@ class OC_Defaults {
}
/**
- * Returns logo claim
- * @return string logo claim
- * @deprecated 13.0.0
- */
- public function getLogoClaim() {
- return '';
- }
-
- /**
* Returns short version of the footer
* @return string short footer
*/
@@ -261,9 +228,9 @@ class OC_Defaults {
if ($this->themeExist('getShortFooter')) {
$footer = $this->theme->getShortFooter();
} else {
- $footer = '<a href="'. $this->getBaseUrl() . '" target="_blank"' .
- ' rel="noreferrer noopener">' .$this->getEntity() . '</a>'.
- ' – ' . $this->getSlogan();
+ $footer = '<a href="' . $this->getBaseUrl() . '" target="_blank"'
+ . ' rel="noreferrer noopener">' . $this->getEntity() . '</a>'
+ . ' – ' . $this->getSlogan();
}
return $footer;
@@ -309,6 +276,17 @@ class OC_Defaults {
}
/**
+ * Returns primary color
+ * @return string
+ */
+ public function getColorBackground() {
+ if ($this->themeExist('getColorBackground')) {
+ return $this->theme->getColorBackground();
+ }
+ return $this->defaultColorBackground;
+ }
+
+ /**
* @return array scss variables to overwrite
*/
public function getScssVariables() {
diff --git a/lib/private/legacy/OC_EventSource.php b/lib/private/legacy/OC_EventSource.php
deleted file mode 100644
index c733316050f..00000000000
--- a/lib/private/legacy/OC_EventSource.php
+++ /dev/null
@@ -1,125 +0,0 @@
-<?php
-/**
- * @copyright Copyright (c) 2016, ownCloud, Inc.
- *
- * @author Bart Visscher <bartv@thisnet.nl>
- * @author Christian Oliff <christianoliff@yahoo.com>
- * @author Christoph Wurst <christoph@winzerhof-wurst.at>
- * @author Felix Moeller <mail@felixmoeller.de>
- * @author Lukas Reschke <lukas@statuscode.ch>
- * @author Morris Jobke <hey@morrisjobke.de>
- * @author Robin Appelman <robin@icewind.nl>
- * @author Thomas Müller <thomas.mueller@tmit.eu>
- *
- * @license AGPL-3.0
- *
- * This code is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License, version 3,
- * as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License, version 3,
- * along with this program. If not, see <http://www.gnu.org/licenses/>
- *
- */
-class OC_EventSource implements \OCP\IEventSource {
- /**
- * @var bool
- */
- private $fallback;
-
- /**
- * @var int
- */
- private $fallBackId = 0;
-
- /**
- * @var bool
- */
- private $started = false;
-
- protected function init() {
- if ($this->started) {
- return;
- }
- $this->started = true;
-
- // prevent php output buffering, caching and nginx buffering
- OC_Util::obEnd();
- header('Cache-Control: no-cache');
- header('X-Accel-Buffering: no');
- $this->fallback = isset($_GET['fallback']) and $_GET['fallback'] == 'true';
- if ($this->fallback) {
- $this->fallBackId = (int)$_GET['fallback_id'];
- /**
- * FIXME: The default content-security-policy of ownCloud forbids inline
- * JavaScript for security reasons. IE starting on Windows 10 will
- * however also obey the CSP which will break the event source fallback.
- *
- * As a workaround thus we set a custom policy which allows the execution
- * of inline JavaScript.
- *
- * @link https://github.com/owncloud/core/issues/14286
- */
- header("Content-Security-Policy: default-src 'none'; script-src 'unsafe-inline'");
- header("Content-Type: text/html");
- echo str_repeat('<span></span>' . PHP_EOL, 10); //dummy data to keep IE happy
- } else {
- header("Content-Type: text/event-stream");
- }
- if (!\OC::$server->getRequest()->passesStrictCookieCheck()) {
- header('Location: '.\OC::$WEBROOT);
- exit();
- }
- if (!\OC::$server->getRequest()->passesCSRFCheck()) {
- $this->send('error', 'Possible CSRF attack. Connection will be closed.');
- $this->close();
- exit();
- }
- flush();
- }
-
- /**
- * send a message to the client
- *
- * @param string $type
- * @param mixed $data
- *
- * @throws \BadMethodCallException
- * if only one parameter is given, a typeless message will be send with that parameter as data
- * @suppress PhanDeprecatedFunction
- */
- public function send($type, $data = null) {
- if ($data and !preg_match('/^[A-Za-z0-9_]+$/', $type)) {
- throw new BadMethodCallException('Type needs to be alphanumeric ('. $type .')');
- }
- $this->init();
- if (is_null($data)) {
- $data = $type;
- $type = null;
- }
- if ($this->fallback) {
- $response = '<script type="text/javascript">window.parent.OC.EventSource.fallBackCallBack('
- . $this->fallBackId . ',"' . $type . '",' . OC_JSON::encode($data) . ')</script>' . PHP_EOL;
- echo $response;
- } else {
- if ($type) {
- echo 'event: ' . $type . PHP_EOL;
- }
- echo 'data: ' . OC_JSON::encode($data) . PHP_EOL;
- }
- echo PHP_EOL;
- flush();
- }
-
- /**
- * close the connection of the event source
- */
- public function close() {
- $this->send('__internal__', 'close'); //server side closing can be an issue, let the client do it
- }
-}
diff --git a/lib/private/legacy/OC_FileChunking.php b/lib/private/legacy/OC_FileChunking.php
deleted file mode 100644
index e3782cabb4a..00000000000
--- a/lib/private/legacy/OC_FileChunking.php
+++ /dev/null
@@ -1,184 +0,0 @@
-<?php
-/**
- * @copyright Copyright (c) 2016, ownCloud, Inc.
- *
- * @author Bart Visscher <bartv@thisnet.nl>
- * @author Christoph Wurst <christoph@winzerhof-wurst.at>
- * @author Felix Moeller <mail@felixmoeller.de>
- * @author Jörn Friedrich Dreyer <jfd@butonic.de>
- * @author Morris Jobke <hey@morrisjobke.de>
- * @author Robin Appelman <robin@icewind.nl>
- * @author Roeland Jago Douma <roeland@famdouma.nl>
- * @author Thomas Müller <thomas.mueller@tmit.eu>
- * @author Thomas Tanghus <thomas@tanghus.net>
- * @author Vincent Petry <vincent@nextcloud.com>
- *
- * @license AGPL-3.0
- *
- * This code is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License, version 3,
- * as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License, version 3,
- * along with this program. If not, see <http://www.gnu.org/licenses/>
- *
- */
-class OC_FileChunking {
- protected $info;
- protected $cache;
-
- /**
- * TTL of chunks
- *
- * @var int
- */
- protected $ttl;
-
- public static function decodeName($name) {
- preg_match('/(?P<name>.*)-chunking-(?P<transferid>\d+)-(?P<chunkcount>\d+)-(?P<index>\d+)/', $name, $matches);
- return $matches;
- }
-
- /**
- * @param string[] $info
- */
- public function __construct($info) {
- $this->info = $info;
- $this->ttl = \OC::$server->getConfig()->getSystemValue('cache_chunk_gc_ttl', 86400);
- }
-
- public function getPrefix() {
- $name = $this->info['name'];
- $transferid = $this->info['transferid'];
-
- return $name.'-chunking-'.$transferid.'-';
- }
-
- protected function getCache() {
- if (!isset($this->cache)) {
- $this->cache = new \OC\Cache\File();
- }
- return $this->cache;
- }
-
- /**
- * Stores the given $data under the given $key - the number of stored bytes is returned
- *
- * @param string $index
- * @param resource $data
- * @return int
- */
- public function store($index, $data) {
- $cache = $this->getCache();
- $name = $this->getPrefix().$index;
- $cache->set($name, $data, $this->ttl);
-
- return $cache->size($name);
- }
-
- public function isComplete() {
- $prefix = $this->getPrefix();
- $cache = $this->getCache();
- $chunkcount = (int)$this->info['chunkcount'];
-
- for ($i = ($chunkcount - 1); $i >= 0; $i--) {
- if (!$cache->hasKey($prefix.$i)) {
- return false;
- }
- }
-
- return true;
- }
-
- /**
- * Assembles the chunks into the file specified by the path.
- * Chunks are deleted afterwards.
- *
- * @param resource $f target path
- *
- * @return integer assembled file size
- *
- * @throws \OC\InsufficientStorageException when file could not be fully
- * assembled due to lack of free space
- */
- public function assemble($f) {
- $cache = $this->getCache();
- $prefix = $this->getPrefix();
- $count = 0;
- for ($i = 0; $i < $this->info['chunkcount']; $i++) {
- $chunk = $cache->get($prefix.$i);
- // remove after reading to directly save space
- $cache->remove($prefix.$i);
- $count += fwrite($f, $chunk);
- // let php release the memory to work around memory exhausted error with php 5.6
- $chunk = null;
- }
-
- return $count;
- }
-
- /**
- * Returns the size of the chunks already present
- * @return integer size in bytes
- */
- public function getCurrentSize() {
- $cache = $this->getCache();
- $prefix = $this->getPrefix();
- $total = 0;
- for ($i = 0; $i < $this->info['chunkcount']; $i++) {
- $total += $cache->size($prefix.$i);
- }
- return $total;
- }
-
- /**
- * Removes all chunks which belong to this transmission
- */
- public function cleanup() {
- $cache = $this->getCache();
- $prefix = $this->getPrefix();
- for ($i = 0; $i < $this->info['chunkcount']; $i++) {
- $cache->remove($prefix.$i);
- }
- }
-
- /**
- * Removes one specific chunk
- * @param string $index
- */
- public function remove($index) {
- $cache = $this->getCache();
- $prefix = $this->getPrefix();
- $cache->remove($prefix.$index);
- }
-
- /**
- * Assembles the chunks into the file specified by the path.
- * Also triggers the relevant hooks and proxies.
- *
- * @param \OC\Files\Storage\Storage $storage storage
- * @param string $path target path relative to the storage
- * @return bool true on success or false if file could not be created
- *
- * @throws \OC\ServerNotAvailableException
- */
- public function file_assemble($storage, $path) {
- // use file_put_contents as method because that best matches what this function does
- if (\OC\Files\Filesystem::isValidPath($path)) {
- $target = $storage->fopen($path, 'w');
- if ($target) {
- $count = $this->assemble($target);
- fclose($target);
- return $count > 0;
- } else {
- return false;
- }
- }
- return false;
- }
-}
diff --git a/lib/private/legacy/OC_Files.php b/lib/private/legacy/OC_Files.php
deleted file mode 100644
index 6a3a44d6cc0..00000000000
--- a/lib/private/legacy/OC_Files.php
+++ /dev/null
@@ -1,459 +0,0 @@
-<?php
-/**
- * @copyright Copyright (c) 2016, ownCloud, Inc.
- *
- * @author Arthur Schiwon <blizzz@arthur-schiwon.de>
- * @author Björn Schießle <bjoern@schiessle.org>
- * @author Christoph Wurst <christoph@winzerhof-wurst.at>
- * @author Daniel Calviño Sánchez <danxuliu@gmail.com>
- * @author Frank Karlitschek <frank@karlitschek.de>
- * @author Jakob Sack <mail@jakobsack.de>
- * @author Joas Schilling <coding@schilljs.com>
- * @author Jörn Friedrich Dreyer <jfd@butonic.de>
- * @author Julius Härtl <jus@bitgrid.net>
- * @author Ko- <k.stoffelen@cs.ru.nl>
- * @author Michael Gapczynski <GapczynskiM@gmail.com>
- * @author Morris Jobke <hey@morrisjobke.de>
- * @author Nicolai Ehemann <en@enlightened.de>
- * @author Piotr Filiciak <piotr@filiciak.pl>
- * @author Robin Appelman <robin@icewind.nl>
- * @author Robin McCorkell <robin@mccorkell.me.uk>
- * @author Roeland Jago Douma <roeland@famdouma.nl>
- * @author Thibaut GRIDEL <tgridel@free.fr>
- * @author Thomas Müller <thomas.mueller@tmit.eu>
- * @author Valdnet <47037905+Valdnet@users.noreply.github.com>
- * @author Victor Dubiniuk <dubiniuk@owncloud.com>
- * @author Vincent Petry <vincent@nextcloud.com>
- *
- * @license AGPL-3.0
- *
- * This code is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License, version 3,
- * as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License, version 3,
- * along with this program. If not, see <http://www.gnu.org/licenses/>
- *
- */
-use bantu\IniGetWrapper\IniGetWrapper;
-use OC\Files\View;
-use OC\Streamer;
-use OCP\Lock\ILockingProvider;
-use OCP\Files\Events\BeforeZipCreatedEvent;
-use OCP\Files\Events\BeforeDirectFileDownloadEvent;
-use OCP\EventDispatcher\IEventDispatcher;
-
-/**
- * Class for file server access
- */
-class OC_Files {
- public const FILE = 1;
- public const ZIP_FILES = 2;
- public const ZIP_DIR = 3;
-
- public const UPLOAD_MIN_LIMIT_BYTES = 1048576; // 1 MiB
-
-
- private static $multipartBoundary = '';
-
- /**
- * @return string
- */
- private static function getBoundary() {
- if (empty(self::$multipartBoundary)) {
- self::$multipartBoundary = md5(mt_rand());
- }
- return self::$multipartBoundary;
- }
-
- /**
- * @param string $filename
- * @param string $name
- * @param array $rangeArray ('from'=>int,'to'=>int), ...
- */
- private static function sendHeaders($filename, $name, array $rangeArray) {
- OC_Response::setContentDispositionHeader($name, 'attachment');
- header('Content-Transfer-Encoding: binary', true);
- header('Pragma: public');// enable caching in IE
- header('Expires: 0');
- header("Cache-Control: must-revalidate, post-check=0, pre-check=0");
- $fileSize = \OC\Files\Filesystem::filesize($filename);
- $type = \OC::$server->getMimeTypeDetector()->getSecureMimeType(\OC\Files\Filesystem::getMimeType($filename));
- if ($fileSize > -1) {
- if (!empty($rangeArray)) {
- http_response_code(206);
- header('Accept-Ranges: bytes', true);
- if (count($rangeArray) > 1) {
- $type = 'multipart/byteranges; boundary='.self::getBoundary();
- // no Content-Length header here
- } else {
- header(sprintf('Content-Range: bytes %d-%d/%d', $rangeArray[0]['from'], $rangeArray[0]['to'], $fileSize), true);
- OC_Response::setContentLengthHeader($rangeArray[0]['to'] - $rangeArray[0]['from'] + 1);
- }
- } else {
- OC_Response::setContentLengthHeader($fileSize);
- }
- }
- header('Content-Type: '.$type, true);
- header('X-Accel-Buffering: no');
- }
-
- /**
- * return the content of a file or return a zip file containing multiple files
- *
- * @param string $dir
- * @param string $files ; separated list of files to download
- * @param array $params ; 'head' boolean to only send header of the request ; 'range' http range header
- */
- public static function get($dir, $files, $params = null) {
- OC_Util::setupFS();
- $view = \OC\Files\Filesystem::getView();
- $getType = self::FILE;
- $filename = $dir;
- try {
- if (is_array($files) && count($files) === 1) {
- $files = $files[0];
- }
-
- if (!is_array($files)) {
- $filename = $dir . '/' . $files;
- if (!$view->is_dir($filename)) {
- self::getSingleFile($view, $dir, $files, is_null($params) ? [] : $params);
- return;
- }
- }
-
- $name = 'download';
- if (is_array($files)) {
- $getType = self::ZIP_FILES;
- $basename = basename($dir);
- if ($basename) {
- $name = $basename;
- }
-
- $filename = $dir . '/' . $name;
- } else {
- $filename = $dir . '/' . $files;
- $getType = self::ZIP_DIR;
- // downloading root ?
- if ($files !== '') {
- $name = $files;
- }
- }
-
- self::lockFiles($view, $dir, $files);
- $numberOfFiles = 0;
- $fileSize = 0;
-
- /* Calculate filesize and number of files */
- if ($getType === self::ZIP_FILES) {
- $fileInfos = [];
- foreach ($files as $file) {
- $fileInfo = \OC\Files\Filesystem::getFileInfo($dir . '/' . $file);
- if ($fileInfo) {
- $fileSize += $fileInfo->getSize();
- $fileInfos[] = $fileInfo;
- }
- }
- $numberOfFiles = self::getNumberOfFiles($fileInfos);
- } elseif ($getType === self::ZIP_DIR) {
- $fileInfo = \OC\Files\Filesystem::getFileInfo($dir . '/' . $files);
- if ($fileInfo) {
- $fileSize = $fileInfo->getSize();
- $numberOfFiles = self::getNumberOfFiles([$fileInfo]);
- }
- }
-
- //Dispatch an event to see if any apps have problem with download
- $event = new BeforeZipCreatedEvent($dir, is_array($files) ? $files : [$files]);
- $dispatcher = \OCP\Server::get(IEventDispatcher::class);
- $dispatcher->dispatchTyped($event);
- if ((!$event->isSuccessful()) || $event->getErrorMessage() !== null) {
- throw new \OC\ForbiddenException($event->getErrorMessage());
- }
-
- $streamer = new Streamer(\OC::$server->getRequest(), $fileSize, $numberOfFiles);
- OC_Util::obEnd();
-
- $streamer->sendHeaders($name);
- $executionTime = (int)OC::$server->get(IniGetWrapper::class)->getNumeric('max_execution_time');
- if (strpos(@ini_get('disable_functions'), 'set_time_limit') === false) {
- @set_time_limit(0);
- }
- ignore_user_abort(true);
-
- if ($getType === self::ZIP_FILES) {
- foreach ($files as $file) {
- $file = $dir . '/' . $file;
- if (\OC\Files\Filesystem::is_file($file)) {
- $userFolder = \OC::$server->getRootFolder()->get(\OC\Files\Filesystem::getRoot());
- $file = $userFolder->get($file);
- if ($file instanceof \OC\Files\Node\File) {
- try {
- $fh = $file->fopen('r');
- } catch (\OCP\Files\NotPermittedException $e) {
- continue;
- }
- $fileSize = $file->getSize();
- $fileTime = $file->getMTime();
- } else {
- // File is not a file? …
- \OC::$server->getLogger()->debug(
- 'File given, but no Node available. Name {file}',
- [ 'app' => 'files', 'file' => $file ]
- );
- continue;
- }
- $streamer->addFileFromStream($fh, $file->getName(), $fileSize, $fileTime);
- fclose($fh);
- } elseif (\OC\Files\Filesystem::is_dir($file)) {
- $streamer->addDirRecursive($file);
- }
- }
- } elseif ($getType === self::ZIP_DIR) {
- $file = $dir . '/' . $files;
- $streamer->addDirRecursive($file);
- }
- $streamer->finalize();
- set_time_limit($executionTime);
- self::unlockAllTheFiles($dir, $files, $getType, $view, $filename);
- } catch (\OCP\Lock\LockedException $ex) {
- self::unlockAllTheFiles($dir, $files, $getType, $view, $filename);
- OC::$server->getLogger()->logException($ex);
- $l = \OC::$server->getL10N('lib');
- $hint = method_exists($ex, 'getHint') ? $ex->getHint() : '';
- \OC_Template::printErrorPage($l->t('File is currently busy, please try again later'), $hint, 200);
- } catch (\OCP\Files\ForbiddenException $ex) {
- self::unlockAllTheFiles($dir, $files, $getType, $view, $filename);
- OC::$server->getLogger()->logException($ex);
- $l = \OC::$server->getL10N('lib');
- \OC_Template::printErrorPage($l->t('Cannot download file'), $ex->getMessage(), 200);
- } catch (\Exception $ex) {
- self::unlockAllTheFiles($dir, $files, $getType, $view, $filename);
- OC::$server->getLogger()->logException($ex);
- $l = \OC::$server->getL10N('lib');
- $hint = method_exists($ex, 'getHint') ? $ex->getHint() : '';
- if ($event && $event->getErrorMessage() !== null) {
- $hint .= ' ' . $event->getErrorMessage();
- }
- \OC_Template::printErrorPage($l->t('Cannot download file'), $hint, 200);
- }
- }
-
- /**
- * @param string $rangeHeaderPos
- * @param int $fileSize
- * @return array $rangeArray ('from'=>int,'to'=>int), ...
- */
- private static function parseHttpRangeHeader($rangeHeaderPos, $fileSize) {
- $rArray = explode(',', $rangeHeaderPos);
- $minOffset = 0;
- $ind = 0;
-
- $rangeArray = [];
-
- foreach ($rArray as $value) {
- $ranges = explode('-', $value);
- if (is_numeric($ranges[0])) {
- if ($ranges[0] < $minOffset) { // case: bytes=500-700,601-999
- $ranges[0] = $minOffset;
- }
- if ($ind > 0 && $rangeArray[$ind - 1]['to'] + 1 == $ranges[0]) { // case: bytes=500-600,601-999
- $ind--;
- $ranges[0] = $rangeArray[$ind]['from'];
- }
- }
-
- if (is_numeric($ranges[0]) && is_numeric($ranges[1]) && $ranges[0] < $fileSize && $ranges[0] <= $ranges[1]) {
- // case: x-x
- if ($ranges[1] >= $fileSize) {
- $ranges[1] = $fileSize - 1;
- }
- $rangeArray[$ind++] = [ 'from' => $ranges[0], 'to' => $ranges[1], 'size' => $fileSize ];
- $minOffset = $ranges[1] + 1;
- if ($minOffset >= $fileSize) {
- break;
- }
- } elseif (is_numeric($ranges[0]) && $ranges[0] < $fileSize) {
- // case: x-
- $rangeArray[$ind++] = [ 'from' => $ranges[0], 'to' => $fileSize - 1, 'size' => $fileSize ];
- break;
- } elseif (is_numeric($ranges[1])) {
- // case: -x
- if ($ranges[1] > $fileSize) {
- $ranges[1] = $fileSize;
- }
- $rangeArray[$ind++] = [ 'from' => $fileSize - $ranges[1], 'to' => $fileSize - 1, 'size' => $fileSize ];
- break;
- }
- }
- return $rangeArray;
- }
-
- /**
- * @param View $view
- * @param string $name
- * @param string $dir
- * @param array $params ; 'head' boolean to only send header of the request ; 'range' http range header
- * @throws \OC\ForbiddenException
- */
- private static function getSingleFile($view, $dir, $name, $params) {
- $filename = $dir . '/' . $name;
- $file = null;
-
- try {
- $userFolder = \OC::$server->getRootFolder()->get(\OC\Files\Filesystem::getRoot());
- $file = $userFolder->get($filename);
- if (!$file instanceof \OC\Files\Node\File || !$file->isReadable()) {
- http_response_code(403);
- die('403 Forbidden');
- }
- $fileSize = $file->getSize();
- } catch (\OCP\Files\NotPermittedException $e) {
- http_response_code(403);
- die('403 Forbidden');
- } catch (\OCP\Files\InvalidPathException $e) {
- http_response_code(403);
- die('403 Forbidden');
- } catch (\OCP\Files\NotFoundException $e) {
- http_response_code(404);
- $tmpl = new OC_Template('', '404', 'guest');
- $tmpl->printPage();
- exit();
- }
-
- OC_Util::obEnd();
- $view->lockFile($filename, ILockingProvider::LOCK_SHARED);
-
- $rangeArray = [];
-
- if (isset($params['range']) && substr($params['range'], 0, 6) === 'bytes=') {
- $rangeArray = self::parseHttpRangeHeader(substr($params['range'], 6), $fileSize);
- }
-
- $dispatcher = \OC::$server->query(IEventDispatcher::class);
- $event = new BeforeDirectFileDownloadEvent($filename);
- $dispatcher->dispatchTyped($event);
-
- if (!\OC\Files\Filesystem::isReadable($filename) || $event->getErrorMessage()) {
- if ($event->getErrorMessage()) {
- $msg = $event->getErrorMessage();
- } else {
- $msg = 'Access denied';
- }
- throw new \OC\ForbiddenException($msg);
- }
-
- self::sendHeaders($filename, $name, $rangeArray);
-
- if (isset($params['head']) && $params['head']) {
- return;
- }
-
- if (!empty($rangeArray)) {
- try {
- if (count($rangeArray) == 1) {
- $view->readfilePart($filename, $rangeArray[0]['from'], $rangeArray[0]['to']);
- } else {
- // check if file is seekable (if not throw UnseekableException)
- // we have to check it before body contents
- $view->readfilePart($filename, $rangeArray[0]['size'], $rangeArray[0]['size']);
-
- $type = \OC::$server->getMimeTypeDetector()->getSecureMimeType(\OC\Files\Filesystem::getMimeType($filename));
-
- foreach ($rangeArray as $range) {
- echo "\r\n--".self::getBoundary()."\r\n".
- "Content-type: ".$type."\r\n".
- "Content-range: bytes ".$range['from']."-".$range['to']."/".$range['size']."\r\n\r\n";
- $view->readfilePart($filename, $range['from'], $range['to']);
- }
- echo "\r\n--".self::getBoundary()."--\r\n";
- }
- } catch (\OCP\Files\UnseekableException $ex) {
- // file is unseekable
- header_remove('Accept-Ranges');
- header_remove('Content-Range');
- http_response_code(200);
- self::sendHeaders($filename, $name, []);
- $view->readfile($filename);
- }
- } else {
- $view->readfile($filename);
- }
- }
-
- /**
- * Returns the total (recursive) number of files and folders in the given
- * FileInfos.
- *
- * @param \OCP\Files\FileInfo[] $fileInfos the FileInfos to count
- * @return int the total number of files and folders
- */
- private static function getNumberOfFiles($fileInfos) {
- $numberOfFiles = 0;
-
- $view = new View();
-
- while ($fileInfo = array_pop($fileInfos)) {
- $numberOfFiles++;
-
- if ($fileInfo->getType() === \OCP\Files\FileInfo::TYPE_FOLDER) {
- $fileInfos = array_merge($fileInfos, $view->getDirectoryContent($fileInfo->getPath()));
- }
- }
-
- return $numberOfFiles;
- }
-
- /**
- * @param View $view
- * @param string $dir
- * @param string[]|string $files
- */
- public static function lockFiles($view, $dir, $files) {
- if (!is_array($files)) {
- $file = $dir . '/' . $files;
- $files = [$file];
- }
- foreach ($files as $file) {
- $file = $dir . '/' . $file;
- $view->lockFile($file, ILockingProvider::LOCK_SHARED);
- if ($view->is_dir($file)) {
- $contents = $view->getDirectoryContent($file);
- $contents = array_map(function ($fileInfo) use ($file) {
- /** @var \OCP\Files\FileInfo $fileInfo */
- return $file . '/' . $fileInfo->getName();
- }, $contents);
- self::lockFiles($view, $dir, $contents);
- }
- }
- }
-
- /**
- * @param string $dir
- * @param $files
- * @param integer $getType
- * @param View $view
- * @param string $filename
- */
- private static function unlockAllTheFiles($dir, $files, $getType, $view, $filename) {
- if ($getType === self::FILE) {
- $view->unlockFile($filename, ILockingProvider::LOCK_SHARED);
- }
- if ($getType === self::ZIP_FILES) {
- foreach ($files as $file) {
- $file = $dir . '/' . $file;
- $view->unlockFile($file, ILockingProvider::LOCK_SHARED);
- }
- }
- if ($getType === self::ZIP_DIR) {
- $file = $dir . '/' . $files;
- $view->unlockFile($file, ILockingProvider::LOCK_SHARED);
- }
- }
-}
diff --git a/lib/private/legacy/OC_Helper.php b/lib/private/legacy/OC_Helper.php
index 9ecd05b0a73..4388f775623 100644
--- a/lib/private/legacy/OC_Helper.php
+++ b/lib/private/legacy/OC_Helper.php
@@ -1,197 +1,69 @@
<?php
+
/**
- * @copyright Copyright (c) 2016, ownCloud, Inc.
- *
- * @author Ardinis <Ardinis@users.noreply.github.com>
- * @author Arthur Schiwon <blizzz@arthur-schiwon.de>
- * @author Bart Visscher <bartv@thisnet.nl>
- * @author Björn Schießle <bjoern@schiessle.org>
- * @author Christoph Wurst <christoph@winzerhof-wurst.at>
- * @author Daniel Kesselberg <mail@danielkesselberg.de>
- * @author Felix Moeller <mail@felixmoeller.de>
- * @author J0WI <J0WI@users.noreply.github.com>
- * @author Jakob Sack <mail@jakobsack.de>
- * @author Jan-Christoph Borchardt <hey@jancborchardt.net>
- * @author Joas Schilling <coding@schilljs.com>
- * @author Jörn Friedrich Dreyer <jfd@butonic.de>
- * @author Julius Härtl <jus@bitgrid.net>
- * @author Lukas Reschke <lukas@statuscode.ch>
- * @author Morris Jobke <hey@morrisjobke.de>
- * @author Olivier Paroz <github@oparoz.com>
- * @author Pellaeon Lin <nfsmwlin@gmail.com>
- * @author RealRancor <fisch.666@gmx.de>
- * @author Robin Appelman <robin@icewind.nl>
- * @author Robin McCorkell <robin@mccorkell.me.uk>
- * @author Roeland Jago Douma <roeland@famdouma.nl>
- * @author Simon Könnecke <simonkoennecke@gmail.com>
- * @author Thomas Müller <thomas.mueller@tmit.eu>
- * @author Thomas Tanghus <thomas@tanghus.net>
- * @author Vincent Petry <vincent@nextcloud.com>
- *
- * @license AGPL-3.0
- *
- * This code is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License, version 3,
- * as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License, version 3,
- * along with this program. If not, see <http://www.gnu.org/licenses/>
- *
+ * SPDX-FileCopyrightText: 2016-2024 Nextcloud GmbH and Nextcloud contributors
+ * SPDX-FileCopyrightText: 2016 ownCloud, Inc.
+ * SPDX-License-Identifier: AGPL-3.0-only
*/
use bantu\IniGetWrapper\IniGetWrapper;
+use OC\Files\FilenameValidator;
use OC\Files\Filesystem;
use OCP\Files\Mount\IMountPoint;
-use OCP\ICacheFactory;
use OCP\IBinaryFinder;
+use OCP\ICacheFactory;
use OCP\IUser;
+use OCP\Server;
+use OCP\Util;
use Psr\Log\LoggerInterface;
/**
* Collection of useful functions
+ *
+ * @psalm-type StorageInfo = array{
+ * free: float|int,
+ * mountPoint: string,
+ * mountType: string,
+ * owner: string,
+ * ownerDisplayName: string,
+ * quota: float|int,
+ * relative: float|int,
+ * total: float|int,
+ * used: float|int,
+ * }
*/
class OC_Helper {
private static $templateManager;
-
- /**
- * Make a human file size
- * @param int $bytes file size in bytes
- * @return string a human readable file size
- *
- * Makes 2048 to 2 kB.
- */
- public static function humanFileSize($bytes) {
- if ($bytes < 0) {
- return "?";
- }
- if ($bytes < 1024) {
- return "$bytes B";
- }
- $bytes = round($bytes / 1024, 0);
- if ($bytes < 1024) {
- return "$bytes KB";
- }
- $bytes = round($bytes / 1024, 1);
- if ($bytes < 1024) {
- return "$bytes MB";
- }
- $bytes = round($bytes / 1024, 1);
- if ($bytes < 1024) {
- return "$bytes GB";
- }
- $bytes = round($bytes / 1024, 1);
- if ($bytes < 1024) {
- return "$bytes TB";
- }
-
- $bytes = round($bytes / 1024, 1);
- return "$bytes PB";
- }
-
- /**
- * Make a computer file size
- * @param string $str file size in human readable format
- * @return int|false a file size in bytes
- *
- * Makes 2kB to 2048.
- *
- * Inspired by: https://www.php.net/manual/en/function.filesize.php#92418
- */
- public static function computerFileSize($str) {
- $str = strtolower($str);
- if (is_numeric($str)) {
- return (int)$str;
- }
-
- $bytes_array = [
- 'b' => 1,
- 'k' => 1024,
- 'kb' => 1024,
- 'mb' => 1024 * 1024,
- 'm' => 1024 * 1024,
- 'gb' => 1024 * 1024 * 1024,
- 'g' => 1024 * 1024 * 1024,
- 'tb' => 1024 * 1024 * 1024 * 1024,
- 't' => 1024 * 1024 * 1024 * 1024,
- 'pb' => 1024 * 1024 * 1024 * 1024 * 1024,
- 'p' => 1024 * 1024 * 1024 * 1024 * 1024,
- ];
-
- $bytes = (float)$str;
-
- if (preg_match('#([kmgtp]?b?)$#si', $str, $matches) && !empty($bytes_array[$matches[1]])) {
- $bytes *= $bytes_array[$matches[1]];
- } else {
- return false;
- }
-
- $bytes = round($bytes);
-
- return (int)$bytes;
- }
+ private static ?ICacheFactory $cacheFactory = null;
+ private static ?bool $quotaIncludeExternalStorage = null;
/**
* Recursive copying of folders
* @param string $src source folder
* @param string $dest target folder
- *
+ * @return void
+ * @deprecated 32.0.0 - use \OCP\Files\Folder::copy
*/
public static function copyr($src, $dest) {
+ if (!file_exists($src)) {
+ return;
+ }
+
if (is_dir($src)) {
if (!is_dir($dest)) {
mkdir($dest);
}
$files = scandir($src);
foreach ($files as $file) {
- if ($file != "." && $file != "..") {
+ if ($file != '.' && $file != '..') {
self::copyr("$src/$file", "$dest/$file");
}
}
- } elseif (file_exists($src) && !\OC\Files\Filesystem::isFileBlacklisted($src)) {
- copy($src, $dest);
- }
- }
-
- /**
- * Recursive deletion of folders
- * @param string $dir path to the folder
- * @param bool $deleteSelf if set to false only the content of the folder will be deleted
- * @return bool
- */
- public static function rmdirr($dir, $deleteSelf = true) {
- if (is_dir($dir)) {
- $files = new RecursiveIteratorIterator(
- new RecursiveDirectoryIterator($dir, RecursiveDirectoryIterator::SKIP_DOTS),
- RecursiveIteratorIterator::CHILD_FIRST
- );
-
- foreach ($files as $fileInfo) {
- /** @var SplFileInfo $fileInfo */
- if ($fileInfo->isLink()) {
- unlink($fileInfo->getPathname());
- } elseif ($fileInfo->isDir()) {
- rmdir($fileInfo->getRealPath());
- } else {
- unlink($fileInfo->getRealPath());
- }
- }
- if ($deleteSelf) {
- rmdir($dir);
- }
- } elseif (file_exists($dir)) {
- if ($deleteSelf) {
- unlink($dir);
+ } else {
+ $validator = \OCP\Server::get(FilenameValidator::class);
+ if (!$validator->isForbidden($src)) {
+ copy($src, $dest);
}
}
- if (!$deleteSelf) {
- return true;
- }
-
- return !file_exists($dir);
}
/**
@@ -212,21 +84,22 @@ class OC_Helper {
* @param bool $path
* @internal param string $program name
* @internal param string $optional search path, defaults to $PATH
- * @return bool true if executable program found in path
+ * @return bool true if executable program found in path
+ * @deprecated 32.0.0 use the \OCP\IBinaryFinder
*/
public static function canExecute($name, $path = false) {
// path defaults to PATH from environment if not set
if ($path === false) {
- $path = getenv("PATH");
+ $path = getenv('PATH');
}
// we look for an executable file of that name
- $exts = [""];
- $check_fn = "is_executable";
+ $exts = [''];
+ $check_fn = 'is_executable';
// Default check will be done with $path directories :
- $dirs = explode(PATH_SEPARATOR, $path);
+ $dirs = explode(PATH_SEPARATOR, (string)$path);
// WARNING : We have to check if open_basedir is enabled :
$obd = OC::$server->get(IniGetWrapper::class)->getString('open_basedir');
- if ($obd != "none") {
+ if ($obd != 'none') {
$obd_values = explode(PATH_SEPARATOR, $obd);
if (count($obd_values) > 0 and $obd_values[0]) {
// open_basedir is in effect !
@@ -250,31 +123,10 @@ class OC_Helper {
* @param resource $source
* @param resource $target
* @return array the number of bytes copied and result
+ * @deprecated 5.0.0 - Use \OCP\Files::streamCopy
*/
public static function streamCopy($source, $target) {
- if (!$source or !$target) {
- return [0, false];
- }
- $bufSize = 8192;
- $result = true;
- $count = 0;
- while (!feof($source)) {
- $buf = fread($source, $bufSize);
- $bytesWritten = fwrite($target, $buf);
- if ($bytesWritten !== false) {
- $count += $bytesWritten;
- }
- // note: strlen is expensive so only use it when necessary,
- // on the last block
- if ($bytesWritten === false
- || ($bytesWritten < $bufSize && $bytesWritten < strlen($buf))
- ) {
- // write error, could be disk full ?
- $result = false;
- break;
- }
- }
- return [$count, $result];
+ return \OCP\Files::streamCopy($source, $target, true);
}
/**
@@ -337,115 +189,20 @@ class OC_Helper {
}
/**
- * Returns an array with all keys from input lowercased or uppercased. Numbered indices are left as is.
- *
- * @param array $input The array to work on
- * @param int $case Either MB_CASE_UPPER or MB_CASE_LOWER (default)
- * @param string $encoding The encoding parameter is the character encoding. Defaults to UTF-8
- * @return array
- *
- * Returns an array with all keys from input lowercased or uppercased. Numbered indices are left as is.
- * based on https://www.php.net/manual/en/function.array-change-key-case.php#107715
- *
- */
- public static function mb_array_change_key_case($input, $case = MB_CASE_LOWER, $encoding = 'UTF-8') {
- $case = ($case != MB_CASE_UPPER) ? MB_CASE_LOWER : MB_CASE_UPPER;
- $ret = [];
- foreach ($input as $k => $v) {
- $ret[mb_convert_case($k, $case, $encoding)] = $v;
- }
- return $ret;
- }
-
- /**
- * performs a search in a nested array
- * @param array $haystack the array to be searched
- * @param string $needle the search string
- * @param mixed $index optional, only search this key name
- * @return mixed the key of the matching field, otherwise false
- *
- * performs a search in a nested array
- *
- * taken from https://www.php.net/manual/en/function.array-search.php#97645
- */
- public static function recursiveArraySearch($haystack, $needle, $index = null) {
- $aIt = new RecursiveArrayIterator($haystack);
- $it = new RecursiveIteratorIterator($aIt);
-
- while ($it->valid()) {
- if (((isset($index) and ($it->key() == $index)) or !isset($index)) and ($it->current() == $needle)) {
- return $aIt->key();
- }
-
- $it->next();
- }
-
- return false;
- }
-
- /**
- * calculates the maximum upload size respecting system settings, free space and user quota
- *
- * @param string $dir the current folder where the user currently operates
- * @param int $freeSpace the number of bytes free on the storage holding $dir, if not set this will be received from the storage directly
- * @return int number of bytes representing
- */
- public static function maxUploadFilesize($dir, $freeSpace = null) {
- if (is_null($freeSpace) || $freeSpace < 0) {
- $freeSpace = self::freeSpace($dir);
- }
- return min($freeSpace, self::uploadLimit());
- }
-
- /**
- * Calculate free space left within user quota
- *
- * @param string $dir the current folder where the user currently operates
- * @return int number of bytes representing
- */
- public static function freeSpace($dir) {
- $freeSpace = \OC\Files\Filesystem::free_space($dir);
- if ($freeSpace < \OCP\Files\FileInfo::SPACE_UNLIMITED) {
- $freeSpace = max($freeSpace, 0);
- return $freeSpace;
- } else {
- return (INF > 0)? INF: PHP_INT_MAX; // work around https://bugs.php.net/bug.php?id=69188
- }
- }
-
- /**
- * Calculate PHP upload limit
- *
- * @return int PHP upload file size limit
- */
- public static function uploadLimit() {
- $ini = \OC::$server->get(IniGetWrapper::class);
- $upload_max_filesize = (int)OCP\Util::computerFileSize($ini->get('upload_max_filesize'));
- $post_max_size = (int)OCP\Util::computerFileSize($ini->get('post_max_size'));
- if ($upload_max_filesize === 0 && $post_max_size === 0) {
- return INF;
- } elseif ($upload_max_filesize === 0 || $post_max_size === 0) {
- return max($upload_max_filesize, $post_max_size); //only the non 0 value counts
- } else {
- return min($upload_max_filesize, $post_max_size);
- }
- }
-
- /**
* Checks if a function is available
*
- * @deprecated Since 25.0.0 use \OCP\Util::isFunctionEnabled instead
+ * @deprecated 25.0.0 use \OCP\Util::isFunctionEnabled instead
*/
public static function is_function_enabled(string $function_name): bool {
- return \OCP\Util::isFunctionEnabled($function_name);
+ return Util::isFunctionEnabled($function_name);
}
/**
* Try to find a program
- * @deprecated Since 25.0.0 Use \OC\BinaryFinder directly
+ * @deprecated 25.0.0 Use \OCP\IBinaryFinder directly
*/
public static function findBinaryPath(string $program): ?string {
- $result = \OCP\Server::get(IBinaryFinder::class)->findBinaryPath($program);
+ $result = Server::get(IBinaryFinder::class)->findBinaryPath($program);
return $result !== false ? $result : null;
}
@@ -459,24 +216,28 @@ class OC_Helper {
* @param \OCP\Files\FileInfo $rootInfo (optional)
* @param bool $includeMountPoints whether to include mount points in the size calculation
* @param bool $useCache whether to use the cached quota values
- * @return array
+ * @psalm-suppress LessSpecificReturnStatement Legacy code outputs weird types - manually validated that they are correct
+ * @return StorageInfo
* @throws \OCP\Files\NotFoundException
*/
public static function getStorageInfo($path, $rootInfo = null, $includeMountPoints = true, $useCache = true) {
- /** @var ICacheFactory $cacheFactory */
- $cacheFactory = \OC::$server->get(ICacheFactory::class);
- $memcache = $cacheFactory->createLocal('storage_info');
+ if (!self::$cacheFactory) {
+ self::$cacheFactory = Server::get(ICacheFactory::class);
+ }
+ $memcache = self::$cacheFactory->createLocal('storage_info');
// return storage info without adding mount points
- $includeExtStorage = \OC::$server->getSystemConfig()->getValue('quota_include_external_storage', false);
+ if (self::$quotaIncludeExternalStorage === null) {
+ self::$quotaIncludeExternalStorage = \OC::$server->getSystemConfig()->getValue('quota_include_external_storage', false);
+ }
$view = Filesystem::getView();
if (!$view) {
throw new \OCP\Files\NotFoundException();
}
- $fullPath = $view->getAbsolutePath($path);
+ $fullPath = Filesystem::normalizePath($view->getAbsolutePath($path));
- $cacheKey = $fullPath. '::' . ($includeMountPoints ? 'include' : 'exclude');
+ $cacheKey = $fullPath . '::' . ($includeMountPoints ? 'include' : 'exclude');
if ($useCache) {
$cached = $memcache->get($cacheKey);
if ($cached) {
@@ -485,23 +246,24 @@ class OC_Helper {
}
if (!$rootInfo) {
- $rootInfo = \OC\Files\Filesystem::getFileInfo($path, $includeExtStorage ? 'ext' : false);
+ $rootInfo = \OC\Files\Filesystem::getFileInfo($path, self::$quotaIncludeExternalStorage ? 'ext' : false);
}
if (!$rootInfo instanceof \OCP\Files\FileInfo) {
- throw new \OCP\Files\NotFoundException();
+ throw new \OCP\Files\NotFoundException('The root directory of the user\'s files is missing');
}
$used = $rootInfo->getSize($includeMountPoints);
if ($used < 0) {
- $used = 0;
+ $used = 0.0;
}
+ /** @var int|float $quota */
$quota = \OCP\Files\FileInfo::SPACE_UNLIMITED;
$mount = $rootInfo->getMountPoint();
$storage = $mount->getStorage();
$sourceStorage = $storage;
if ($storage->instanceOfStorage('\OCA\Files_Sharing\SharedStorage')) {
- $includeExtStorage = false;
+ self::$quotaIncludeExternalStorage = false;
}
- if ($includeExtStorage) {
+ if (self::$quotaIncludeExternalStorage) {
if ($storage->instanceOfStorage('\OC\Files\Storage\Home')
|| $storage->instanceOfStorage('\OC\Files\ObjectStore\HomeObjectStoreStorage')
) {
@@ -510,7 +272,7 @@ class OC_Helper {
} else {
$user = \OC::$server->getUserSession()->getUser();
}
- $quota = OC_Util::getUserQuota($user);
+ $quota = $user?->getQuotaBytes() ?? \OCP\Files\FileInfo::SPACE_UNKNOWN;
if ($quota !== \OCP\Files\FileInfo::SPACE_UNLIMITED) {
// always get free space / total space from root + mount points
return self::getGlobalStorageInfo($quota, $user, $mount);
@@ -524,14 +286,17 @@ class OC_Helper {
}
try {
$free = $sourceStorage->free_space($rootInfo->getInternalPath());
+ if (is_bool($free)) {
+ $free = 0.0;
+ }
} catch (\Exception $e) {
- if ($path === "") {
+ if ($path === '') {
throw $e;
}
/** @var LoggerInterface $logger */
$logger = \OC::$server->get(LoggerInterface::class);
- $logger->warning("Error while getting quota info, using root quota", ['exception' => $e]);
- $rootInfo = self::getStorageInfo("");
+ $logger->warning('Error while getting quota info, using root quota', ['exception' => $e]);
+ $rootInfo = self::getStorageInfo('');
$memcache->set($cacheKey, $rootInfo, 5 * 60);
return $rootInfo;
}
@@ -550,9 +315,16 @@ class OC_Helper {
$relative = 0;
}
+ /*
+ * \OCA\Files_Sharing\External\Storage returns the cloud ID as the owner for the storage.
+ * It is unnecessary to query the user manager for the display name, as it won't have this information.
+ */
+ $isRemoteShare = $storage->instanceOfStorage(\OCA\Files_Sharing\External\Storage::class);
+
$ownerId = $storage->getOwner($path);
$ownerDisplayName = '';
- if ($ownerId) {
+
+ if ($isRemoteShare === false && $ownerId !== false) {
$ownerDisplayName = \OC::$server->getUserManager()->getDisplayName($ownerId) ?? '';
}
@@ -574,6 +346,11 @@ class OC_Helper {
'mountPoint' => trim($mountPoint, '/'),
];
+ if ($isRemoteShare === false && $ownerId !== false && $path === '/') {
+ // If path is root, store this as last known quota usage for this user
+ \OCP\Server::get(\OCP\IConfig::class)->setUserValue($ownerId, 'files', 'lastSeenQuotaUsage', (string)$relative);
+ }
+
$memcache->set($cacheKey, $info, 5 * 60);
return $info;
@@ -581,15 +358,20 @@ class OC_Helper {
/**
* Get storage info including all mount points and quota
+ *
+ * @psalm-suppress LessSpecificReturnStatement Legacy code outputs weird types - manually validated that they are correct
+ * @return StorageInfo
*/
- private static function getGlobalStorageInfo(int $quota, IUser $user, IMountPoint $mount): array {
+ private static function getGlobalStorageInfo(int|float $quota, IUser $user, IMountPoint $mount): array {
$rootInfo = \OC\Files\Filesystem::getFileInfo('', 'ext');
+ /** @var int|float $used */
$used = $rootInfo['size'];
if ($used < 0) {
- $used = 0;
+ $used = 0.0;
}
$total = $quota;
+ /** @var int|float $free */
$free = $quota - $used;
if ($total > 0) {
@@ -599,7 +381,7 @@ class OC_Helper {
// prevent division by zero or error codes (negative values)
$relative = round(($used / $total) * 10000) / 100;
} else {
- $relative = 0;
+ $relative = 0.0;
}
if (substr_count($mount->getMountPoint(), '/') < 3) {
@@ -621,11 +403,21 @@ class OC_Helper {
];
}
+ public static function clearStorageInfo(string $absolutePath): void {
+ /** @var ICacheFactory $cacheFactory */
+ $cacheFactory = \OC::$server->get(ICacheFactory::class);
+ $memcache = $cacheFactory->createLocal('storage_info');
+ $cacheKeyPrefix = Filesystem::normalizePath($absolutePath) . '::';
+ $memcache->remove($cacheKeyPrefix . 'include');
+ $memcache->remove($cacheKeyPrefix . 'exclude');
+ }
+
/**
* Returns whether the config file is set manually to read-only
* @return bool
+ * @deprecated 32.0.0 use the `config_is_read_only` system config directly
*/
public static function isReadOnlyConfigEnabled() {
- return \OC::$server->getConfig()->getSystemValue('config_is_read_only', false);
+ return \OC::$server->getConfig()->getSystemValueBool('config_is_read_only', false);
}
}
diff --git a/lib/private/legacy/OC_Hook.php b/lib/private/legacy/OC_Hook.php
index a7a0f755673..e472b105498 100644
--- a/lib/private/legacy/OC_Hook.php
+++ b/lib/private/legacy/OC_Hook.php
@@ -1,33 +1,13 @@
<?php
+
/**
- * @copyright Copyright (c) 2016, ownCloud, Inc.
- *
- * @author Bart Visscher <bartv@thisnet.nl>
- * @author Christoph Wurst <christoph@winzerhof-wurst.at>
- * @author Jakob Sack <mail@jakobsack.de>
- * @author Jörn Friedrich Dreyer <jfd@butonic.de>
- * @author Morris Jobke <hey@morrisjobke.de>
- * @author Robin Appelman <robin@icewind.nl>
- * @author Robin McCorkell <robin@mccorkell.me.uk>
- * @author Sam Tuke <mail@samtuke.com>
- * @author Thomas Müller <thomas.mueller@tmit.eu>
- * @author Vincent Petry <vincent@nextcloud.com>
- *
- * @license AGPL-3.0
- *
- * This code is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License, version 3,
- * as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License, version 3,
- * along with this program. If not, see <http://www.gnu.org/licenses/>
- *
+ * SPDX-FileCopyrightText: 2016-2024 Nextcloud GmbH and Nextcloud contributors
+ * SPDX-FileCopyrightText: 2016 ownCloud, Inc.
+ * SPDX-License-Identifier: AGPL-3.0-only
*/
+
+use Psr\Log\LoggerInterface;
+
class OC_Hook {
public static $thrownExceptions = [];
@@ -66,8 +46,8 @@ class OC_Hook {
}
// Connect the hook handler to the requested emitter
self::$registered[$signalClass][$signalName][] = [
- "class" => $slotClass,
- "name" => $slotName
+ 'class' => $slotClass,
+ 'name' => $slotName
];
// No chance for failure ;-)
@@ -102,10 +82,10 @@ class OC_Hook {
// Call all slots
foreach (self::$registered[$signalClass][$signalName] as $i) {
try {
- call_user_func([ $i["class"], $i["name"] ], $params);
+ call_user_func([ $i['class'], $i['name'] ], $params);
} catch (Exception $e) {
self::$thrownExceptions[] = $e;
- \OC::$server->getLogger()->logException($e);
+ \OCP\Server::get(LoggerInterface::class)->error($e->getMessage(), ['exception' => $e]);
if ($e instanceof \OCP\HintException) {
throw $e;
}
diff --git a/lib/private/legacy/OC_Image.php b/lib/private/legacy/OC_Image.php
deleted file mode 100644
index f2fa2058faa..00000000000
--- a/lib/private/legacy/OC_Image.php
+++ /dev/null
@@ -1,1152 +0,0 @@
-<?php
-
-declare(strict_types=1);
-
-/**
- * @copyright Copyright (c) 2016, ownCloud, Inc.
- *
- * @author Bartek Przybylski <bart.p.pl@gmail.com>
- * @author Bart Visscher <bartv@thisnet.nl>
- * @author Björn Schießle <bjoern@schiessle.org>
- * @author Byron Marohn <combustible@live.com>
- * @author Côme Chilliet <come.chilliet@nextcloud.com>
- * @author Christopher Schäpers <kondou@ts.unde.re>
- * @author Christoph Wurst <christoph@winzerhof-wurst.at>
- * @author Georg Ehrke <oc.list@georgehrke.com>
- * @author J0WI <J0WI@users.noreply.github.com>
- * @author j-ed <juergen@eisfair.org>
- * @author Joas Schilling <coding@schilljs.com>
- * @author Johannes Willnecker <johannes@willnecker.com>
- * @author Jörn Friedrich Dreyer <jfd@butonic.de>
- * @author Julius Härtl <jus@bitgrid.net>
- * @author Lukas Reschke <lukas@statuscode.ch>
- * @author Morris Jobke <hey@morrisjobke.de>
- * @author Olivier Paroz <github@oparoz.com>
- * @author Robin Appelman <robin@icewind.nl>
- * @author Roeland Jago Douma <roeland@famdouma.nl>
- * @author Samuel CHEMLA <chemla.samuel@gmail.com>
- * @author Thomas Müller <thomas.mueller@tmit.eu>
- * @author Thomas Tanghus <thomas@tanghus.net>
- *
- * @license AGPL-3.0
- *
- * This code is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License, version 3,
- * as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License, version 3,
- * along with this program. If not, see <http://www.gnu.org/licenses/>
- *
- */
-use OCP\IImage;
-
-/**
- * Class for basic image manipulation
- */
-class OC_Image implements \OCP\IImage {
- // Default memory limit for images to load (256 MBytes).
- protected const DEFAULT_MEMORY_LIMIT = 256;
-
- // Default quality for jpeg images
- protected const DEFAULT_JPEG_QUALITY = 80;
-
- /** @var false|resource|\GdImage */
- protected $resource = false; // tmp resource.
- /** @var int */
- protected $imageType = IMAGETYPE_PNG; // Default to png if file type isn't evident.
- /** @var null|string */
- protected $mimeType = 'image/png'; // Default to png
- /** @var null|string */
- protected $filePath = null;
- /** @var finfo */
- private $fileInfo;
- /** @var \OCP\ILogger */
- private $logger;
- /** @var \OCP\IConfig */
- private $config;
- /** @var array */
- private $exif;
-
- /**
- * Constructor.
- *
- * @param resource|string|\GdImage $imageRef The path to a local file, a base64 encoded string or a resource created by
- * an imagecreate* function.
- * @param \OCP\ILogger $logger
- * @param \OCP\IConfig $config
- * @throws \InvalidArgumentException in case the $imageRef parameter is not null
- */
- public function __construct($imageRef = null, \OCP\ILogger $logger = null, \OCP\IConfig $config = null) {
- $this->logger = $logger;
- if ($logger === null) {
- $this->logger = \OC::$server->getLogger();
- }
- $this->config = $config;
- if ($config === null) {
- $this->config = \OC::$server->getConfig();
- }
-
- if (\OC_Util::fileInfoLoaded()) {
- $this->fileInfo = new finfo(FILEINFO_MIME_TYPE);
- }
-
- if ($imageRef !== null) {
- throw new \InvalidArgumentException('The first parameter in the constructor is not supported anymore. Please use any of the load* methods of the image object to load an image.');
- }
- }
-
- /**
- * Determine whether the object contains an image resource.
- *
- * @return bool
- */
- public function valid(): bool {
- if ((is_resource($this->resource) && get_resource_type($this->resource) === 'gd') ||
- (is_object($this->resource) && get_class($this->resource) === \GdImage::class)) {
- return true;
- }
-
- return false;
- }
-
- /**
- * Returns the MIME type of the image or null if no image is loaded.
- *
- * @return string
- */
- public function mimeType(): ?string {
- return $this->valid() ? $this->mimeType : null;
- }
-
- /**
- * Returns the width of the image or -1 if no image is loaded.
- *
- * @return int
- */
- public function width(): int {
- if ($this->valid()) {
- $width = imagesx($this->resource);
- if ($width !== false) {
- return $width;
- }
- }
- return -1;
- }
-
- /**
- * Returns the height of the image or -1 if no image is loaded.
- *
- * @return int
- */
- public function height(): int {
- if ($this->valid()) {
- $height = imagesy($this->resource);
- if ($height !== false) {
- return $height;
- }
- }
- return -1;
- }
-
- /**
- * Returns the width when the image orientation is top-left.
- *
- * @return int
- */
- public function widthTopLeft(): int {
- $o = $this->getOrientation();
- $this->logger->debug('OC_Image->widthTopLeft() Orientation: ' . $o, ['app' => 'core']);
- switch ($o) {
- case -1:
- case 1:
- case 2: // Not tested
- case 3:
- case 4: // Not tested
- return $this->width();
- case 5: // Not tested
- case 6:
- case 7: // Not tested
- case 8:
- return $this->height();
- }
- return $this->width();
- }
-
- /**
- * Returns the height when the image orientation is top-left.
- *
- * @return int
- */
- public function heightTopLeft(): int {
- $o = $this->getOrientation();
- $this->logger->debug('OC_Image->heightTopLeft() Orientation: ' . $o, ['app' => 'core']);
- switch ($o) {
- case -1:
- case 1:
- case 2: // Not tested
- case 3:
- case 4: // Not tested
- return $this->height();
- case 5: // Not tested
- case 6:
- case 7: // Not tested
- case 8:
- return $this->width();
- }
- return $this->height();
- }
-
- /**
- * Outputs the image.
- *
- * @param string $mimeType
- * @return bool
- */
- public function show(string $mimeType = null): bool {
- if ($mimeType === null) {
- $mimeType = $this->mimeType();
- }
- header('Content-Type: ' . $mimeType);
- return $this->_output(null, $mimeType);
- }
-
- /**
- * Saves the image.
- *
- * @param string $filePath
- * @param string $mimeType
- * @return bool
- */
-
- public function save(?string $filePath = null, ?string $mimeType = null): bool {
- if ($mimeType === null) {
- $mimeType = $this->mimeType();
- }
- if ($filePath === null) {
- if ($this->filePath === null) {
- $this->logger->error(__METHOD__ . '(): called with no path.', ['app' => 'core']);
- return false;
- } else {
- $filePath = $this->filePath;
- }
- }
- return $this->_output($filePath, $mimeType);
- }
-
- /**
- * Outputs/saves the image.
- *
- * @param string $filePath
- * @param string $mimeType
- * @return bool
- * @throws Exception
- */
- private function _output(?string $filePath = null, ?string $mimeType = null): bool {
- if ($filePath) {
- if (!file_exists(dirname($filePath))) {
- mkdir(dirname($filePath), 0777, true);
- }
- $isWritable = is_writable(dirname($filePath));
- if (!$isWritable) {
- $this->logger->error(__METHOD__ . '(): Directory \'' . dirname($filePath) . '\' is not writable.', ['app' => 'core']);
- return false;
- } elseif (file_exists($filePath) && !is_writable($filePath)) {
- $this->logger->error(__METHOD__ . '(): File \'' . $filePath . '\' is not writable.', ['app' => 'core']);
- return false;
- }
- }
- if (!$this->valid()) {
- return false;
- }
-
- $imageType = $this->imageType;
- if ($mimeType !== null) {
- switch ($mimeType) {
- case 'image/gif':
- $imageType = IMAGETYPE_GIF;
- break;
- case 'image/jpeg':
- $imageType = IMAGETYPE_JPEG;
- break;
- case 'image/png':
- $imageType = IMAGETYPE_PNG;
- break;
- case 'image/x-xbitmap':
- $imageType = IMAGETYPE_XBM;
- break;
- case 'image/bmp':
- case 'image/x-ms-bmp':
- $imageType = IMAGETYPE_BMP;
- break;
- default:
- throw new Exception('\OC_Image::_output(): "' . $mimeType . '" is not supported when forcing a specific output format');
- }
- }
-
- switch ($imageType) {
- case IMAGETYPE_GIF:
- $retVal = imagegif($this->resource, $filePath);
- break;
- case IMAGETYPE_JPEG:
- /** @psalm-suppress InvalidScalarArgument */
- imageinterlace($this->resource, (PHP_VERSION_ID >= 80000 ? true : 1));
- $retVal = imagejpeg($this->resource, $filePath, $this->getJpegQuality());
- break;
- case IMAGETYPE_PNG:
- $retVal = imagepng($this->resource, $filePath);
- break;
- case IMAGETYPE_XBM:
- if (function_exists('imagexbm')) {
- $retVal = imagexbm($this->resource, $filePath);
- } else {
- throw new Exception('\OC_Image::_output(): imagexbm() is not supported.');
- }
-
- break;
- case IMAGETYPE_WBMP:
- $retVal = imagewbmp($this->resource, $filePath);
- break;
- case IMAGETYPE_BMP:
- $retVal = imagebmp($this->resource, $filePath);
- break;
- default:
- $retVal = imagepng($this->resource, $filePath);
- }
- return $retVal;
- }
-
- /**
- * Prints the image when called as $image().
- */
- public function __invoke() {
- return $this->show();
- }
-
- /**
- * @param resource|\GdImage $resource
- * @throws \InvalidArgumentException in case the supplied resource does not have the type "gd"
- */
- public function setResource($resource) {
- // For PHP<8
- if (is_resource($resource) && get_resource_type($resource) === 'gd') {
- $this->resource = $resource;
- return;
- }
- // PHP 8 has real objects for GD stuff
- if (is_object($resource) && get_class($resource) === \GdImage::class) {
- $this->resource = $resource;
- return;
- }
- throw new \InvalidArgumentException('Supplied resource is not of type "gd".');
- }
-
- /**
- * @return false|resource|\GdImage Returns the image resource if any
- */
- public function resource() {
- return $this->resource;
- }
-
- /**
- * @return string Returns the mimetype of the data. Returns null if the data is not valid.
- */
- public function dataMimeType(): ?string {
- if (!$this->valid()) {
- return null;
- }
-
- switch ($this->mimeType) {
- case 'image/png':
- case 'image/jpeg':
- case 'image/gif':
- return $this->mimeType;
- default:
- return 'image/png';
- }
- }
-
- /**
- * @return null|string Returns the raw image data.
- */
- public function data(): ?string {
- if (!$this->valid()) {
- return null;
- }
- ob_start();
- switch ($this->mimeType) {
- case "image/png":
- $res = imagepng($this->resource);
- break;
- case "image/jpeg":
- /** @psalm-suppress InvalidScalarArgument */
- imageinterlace($this->resource, (PHP_VERSION_ID >= 80000 ? true : 1));
- $quality = $this->getJpegQuality();
- $res = imagejpeg($this->resource, null, $quality);
- break;
- case "image/gif":
- $res = imagegif($this->resource);
- break;
- default:
- $res = imagepng($this->resource);
- $this->logger->info('OC_Image->data. Could not guess mime-type, defaulting to png', ['app' => 'core']);
- break;
- }
- if (!$res) {
- $this->logger->error('OC_Image->data. Error getting image data.', ['app' => 'core']);
- }
- return ob_get_clean();
- }
-
- /**
- * @return string - base64 encoded, which is suitable for embedding in a VCard.
- */
- public function __toString() {
- return base64_encode($this->data());
- }
-
- /**
- * @return int
- */
- protected function getJpegQuality(): int {
- $quality = $this->config->getAppValue('preview', 'jpeg_quality', (string) self::DEFAULT_JPEG_QUALITY);
- // TODO: remove when getAppValue is type safe
- if ($quality === null) {
- $quality = self::DEFAULT_JPEG_QUALITY;
- }
- return min(100, max(10, (int) $quality));
- }
-
- /**
- * (I'm open for suggestions on better method name ;)
- * Get the orientation based on EXIF data.
- *
- * @return int The orientation or -1 if no EXIF data is available.
- */
- public function getOrientation(): int {
- if ($this->exif !== null) {
- return $this->exif['Orientation'];
- }
-
- if ($this->imageType !== IMAGETYPE_JPEG) {
- $this->logger->debug('OC_Image->fixOrientation() Image is not a JPEG.', ['app' => 'core']);
- return -1;
- }
- if (!is_callable('exif_read_data')) {
- $this->logger->debug('OC_Image->fixOrientation() Exif module not enabled.', ['app' => 'core']);
- return -1;
- }
- if (!$this->valid()) {
- $this->logger->debug('OC_Image->fixOrientation() No image loaded.', ['app' => 'core']);
- return -1;
- }
- if (is_null($this->filePath) || !is_readable($this->filePath)) {
- $this->logger->debug('OC_Image->fixOrientation() No readable file path set.', ['app' => 'core']);
- return -1;
- }
- $exif = @exif_read_data($this->filePath, 'IFD0');
- if (!$exif) {
- return -1;
- }
- if (!isset($exif['Orientation'])) {
- return -1;
- }
- $this->exif = $exif;
- return $exif['Orientation'];
- }
-
- public function readExif($data): void {
- if (!is_callable('exif_read_data')) {
- $this->logger->debug('OC_Image->fixOrientation() Exif module not enabled.', ['app' => 'core']);
- return;
- }
- if (!$this->valid()) {
- $this->logger->debug('OC_Image->fixOrientation() No image loaded.', ['app' => 'core']);
- return;
- }
-
- $exif = @exif_read_data('data://image/jpeg;base64,' . base64_encode($data));
- if (!$exif) {
- return;
- }
- if (!isset($exif['Orientation'])) {
- return;
- }
- $this->exif = $exif;
- }
-
- /**
- * (I'm open for suggestions on better method name ;)
- * Fixes orientation based on EXIF data.
- *
- * @return bool
- */
- public function fixOrientation(): bool {
- if (!$this->valid()) {
- $this->logger->debug(__METHOD__ . '(): No image loaded', ['app' => 'core']);
- return false;
- }
- $o = $this->getOrientation();
- $this->logger->debug('OC_Image->fixOrientation() Orientation: ' . $o, ['app' => 'core']);
- $rotate = 0;
- $flip = false;
- switch ($o) {
- case -1:
- return false; //Nothing to fix
- case 1:
- $rotate = 0;
- break;
- case 2:
- $rotate = 0;
- $flip = true;
- break;
- case 3:
- $rotate = 180;
- break;
- case 4:
- $rotate = 180;
- $flip = true;
- break;
- case 5:
- $rotate = 90;
- $flip = true;
- break;
- case 6:
- $rotate = 270;
- break;
- case 7:
- $rotate = 270;
- $flip = true;
- break;
- case 8:
- $rotate = 90;
- break;
- }
- if ($flip && function_exists('imageflip')) {
- imageflip($this->resource, IMG_FLIP_HORIZONTAL);
- }
- if ($rotate) {
- $res = imagerotate($this->resource, $rotate, 0);
- if ($res) {
- if (imagealphablending($res, true)) {
- if (imagesavealpha($res, true)) {
- imagedestroy($this->resource);
- $this->resource = $res;
- return true;
- } else {
- $this->logger->debug('OC_Image->fixOrientation() Error during alpha-saving', ['app' => 'core']);
- return false;
- }
- } else {
- $this->logger->debug('OC_Image->fixOrientation() Error during alpha-blending', ['app' => 'core']);
- return false;
- }
- } else {
- $this->logger->debug('OC_Image->fixOrientation() Error during orientation fixing', ['app' => 'core']);
- return false;
- }
- }
- return false;
- }
-
- /**
- * Loads an image from an open file handle.
- * It is the responsibility of the caller to position the pointer at the correct place and to close the handle again.
- *
- * @param resource $handle
- * @return resource|\GdImage|false An image resource or false on error
- */
- public function loadFromFileHandle($handle) {
- $contents = stream_get_contents($handle);
- if ($this->loadFromData($contents)) {
- return $this->resource;
- }
- return false;
- }
-
- /**
- * Check if allocating an image with the given size is allowed.
- *
- * @param int $width The image width.
- * @param int $height The image height.
- * @return bool true if allocating is allowed, false otherwise
- */
- private function checkImageMemory($width, $height) {
- $memory_limit = $this->config->getSystemValueInt('preview_max_memory', self::DEFAULT_MEMORY_LIMIT);
- if ($memory_limit < 0) {
- // Not limited.
- return true;
- }
-
- // Assume 32 bits per pixel.
- if ($width * $height * 4 > $memory_limit * 1024 * 1024) {
- $this->logger->info('Image size of ' . $width . 'x' . $height . ' would exceed allowed memory limit of ' . $memory_limit . '. You may increase the preview_max_memory in your config.php if you need previews of this image.');
- return false;
- }
-
- return true;
- }
-
- /**
- * Check if loading an image file from the given path is allowed.
- *
- * @param string $path The path to a local file.
- * @return bool true if allocating is allowed, false otherwise
- */
- private function checkImageSize($path) {
- $size = getimagesize($path);
- if (!$size) {
- return true;
- }
-
- $width = $size[0];
- $height = $size[1];
- if (!$this->checkImageMemory($width, $height)) {
- return false;
- }
-
- return true;
- }
-
- /**
- * Check if loading an image from the given data is allowed.
- *
- * @param string $data A string of image data as read from a file.
- * @return bool true if allocating is allowed, false otherwise
- */
- private function checkImageDataSize($data) {
- $size = getimagesizefromstring($data);
- if (!$size) {
- return true;
- }
-
- $width = $size[0];
- $height = $size[1];
- if (!$this->checkImageMemory($width, $height)) {
- return false;
- }
-
- return true;
- }
-
- /**
- * Loads an image from a local file.
- *
- * @param bool|string $imagePath The path to a local file.
- * @return bool|resource|\GdImage An image resource or false on error
- */
- public function loadFromFile($imagePath = false) {
- // exif_imagetype throws "read error!" if file is less than 12 byte
- if (is_bool($imagePath) || !@is_file($imagePath) || !file_exists($imagePath) || filesize($imagePath) < 12 || !is_readable($imagePath)) {
- return false;
- }
- $iType = exif_imagetype($imagePath);
- switch ($iType) {
- case IMAGETYPE_GIF:
- if (imagetypes() & IMG_GIF) {
- if (!$this->checkImageSize($imagePath)) {
- return false;
- }
- $this->resource = imagecreatefromgif($imagePath);
- if ($this->resource) {
- // Preserve transparency
- imagealphablending($this->resource, true);
- imagesavealpha($this->resource, true);
- } else {
- $this->logger->debug('OC_Image->loadFromFile, GIF image not valid: ' . $imagePath, ['app' => 'core']);
- }
- } else {
- $this->logger->debug('OC_Image->loadFromFile, GIF images not supported: ' . $imagePath, ['app' => 'core']);
- }
- break;
- case IMAGETYPE_JPEG:
- if (imagetypes() & IMG_JPG) {
- if (!$this->checkImageSize($imagePath)) {
- return false;
- }
- if (getimagesize($imagePath) !== false) {
- $this->resource = @imagecreatefromjpeg($imagePath);
- } else {
- $this->logger->debug('OC_Image->loadFromFile, JPG image not valid: ' . $imagePath, ['app' => 'core']);
- }
- } else {
- $this->logger->debug('OC_Image->loadFromFile, JPG images not supported: ' . $imagePath, ['app' => 'core']);
- }
- break;
- case IMAGETYPE_PNG:
- if (imagetypes() & IMG_PNG) {
- if (!$this->checkImageSize($imagePath)) {
- return false;
- }
- $this->resource = @imagecreatefrompng($imagePath);
- if ($this->resource) {
- // Preserve transparency
- imagealphablending($this->resource, true);
- imagesavealpha($this->resource, true);
- } else {
- $this->logger->debug('OC_Image->loadFromFile, PNG image not valid: ' . $imagePath, ['app' => 'core']);
- }
- } else {
- $this->logger->debug('OC_Image->loadFromFile, PNG images not supported: ' . $imagePath, ['app' => 'core']);
- }
- break;
- case IMAGETYPE_XBM:
- if (imagetypes() & IMG_XPM) {
- if (!$this->checkImageSize($imagePath)) {
- return false;
- }
- $this->resource = @imagecreatefromxbm($imagePath);
- } else {
- $this->logger->debug('OC_Image->loadFromFile, XBM/XPM images not supported: ' . $imagePath, ['app' => 'core']);
- }
- break;
- case IMAGETYPE_WBMP:
- if (imagetypes() & IMG_WBMP) {
- if (!$this->checkImageSize($imagePath)) {
- return false;
- }
- $this->resource = @imagecreatefromwbmp($imagePath);
- } else {
- $this->logger->debug('OC_Image->loadFromFile, WBMP images not supported: ' . $imagePath, ['app' => 'core']);
- }
- break;
- case IMAGETYPE_BMP:
- $this->resource = imagecreatefrombmp($imagePath);
- break;
- case IMAGETYPE_WEBP:
- if (imagetypes() & IMG_WEBP) {
- if (!$this->checkImageSize($imagePath)) {
- return false;
- }
- $this->resource = @imagecreatefromwebp($imagePath);
- } else {
- $this->logger->debug('OC_Image->loadFromFile, webp images not supported: ' . $imagePath, ['app' => 'core']);
- }
- break;
- /*
- case IMAGETYPE_TIFF_II: // (intel byte order)
- break;
- case IMAGETYPE_TIFF_MM: // (motorola byte order)
- break;
- case IMAGETYPE_JPC:
- break;
- case IMAGETYPE_JP2:
- break;
- case IMAGETYPE_JPX:
- break;
- case IMAGETYPE_JB2:
- break;
- case IMAGETYPE_SWC:
- break;
- case IMAGETYPE_IFF:
- break;
- case IMAGETYPE_ICO:
- break;
- case IMAGETYPE_SWF:
- break;
- case IMAGETYPE_PSD:
- break;
- */
- default:
-
- // this is mostly file created from encrypted file
- $data = file_get_contents($imagePath);
- if (!$this->checkImageDataSize($data)) {
- return false;
- }
- $this->resource = imagecreatefromstring($data);
- $iType = IMAGETYPE_PNG;
- $this->logger->debug('OC_Image->loadFromFile, Default', ['app' => 'core']);
- break;
- }
- if ($this->valid()) {
- $this->imageType = $iType;
- $this->mimeType = image_type_to_mime_type($iType);
- $this->filePath = $imagePath;
- }
- return $this->resource;
- }
-
- /**
- * Loads an image from a string of data.
- *
- * @param string $str A string of image data as read from a file.
- * @return bool|resource|\GdImage An image resource or false on error
- */
- public function loadFromData(string $str) {
- if (!$this->checkImageDataSize($str)) {
- return false;
- }
- $this->resource = @imagecreatefromstring($str);
- if ($this->fileInfo) {
- $this->mimeType = $this->fileInfo->buffer($str);
- }
- if ($this->valid()) {
- imagealphablending($this->resource, false);
- imagesavealpha($this->resource, true);
- }
-
- if (!$this->resource) {
- $this->logger->debug('OC_Image->loadFromFile, could not load', ['app' => 'core']);
- return false;
- }
- return $this->resource;
- }
-
- /**
- * Loads an image from a base64 encoded string.
- *
- * @param string $str A string base64 encoded string of image data.
- * @return bool|resource|\GdImage An image resource or false on error
- */
- public function loadFromBase64(string $str) {
- $data = base64_decode($str);
- if ($data) { // try to load from string data
- if (!$this->checkImageDataSize($data)) {
- return false;
- }
- $this->resource = @imagecreatefromstring($data);
- if ($this->fileInfo) {
- $this->mimeType = $this->fileInfo->buffer($data);
- }
- if (!$this->resource) {
- $this->logger->debug('OC_Image->loadFromBase64, could not load', ['app' => 'core']);
- return false;
- }
- return $this->resource;
- } else {
- return false;
- }
- }
-
- /**
- * Resizes the image preserving ratio.
- *
- * @param int $maxSize The maximum size of either the width or height.
- * @return bool
- */
- public function resize(int $maxSize): bool {
- if (!$this->valid()) {
- $this->logger->debug(__METHOD__ . '(): No image loaded', ['app' => 'core']);
- return false;
- }
- $result = $this->resizeNew($maxSize);
- imagedestroy($this->resource);
- $this->resource = $result;
- return $this->valid();
- }
-
- /**
- * @param $maxSize
- * @return resource|bool|\GdImage
- */
- private function resizeNew(int $maxSize) {
- if (!$this->valid()) {
- $this->logger->debug(__METHOD__ . '(): No image loaded', ['app' => 'core']);
- return false;
- }
- $widthOrig = imagesx($this->resource);
- $heightOrig = imagesy($this->resource);
- $ratioOrig = $widthOrig / $heightOrig;
-
- if ($ratioOrig > 1) {
- $newHeight = round($maxSize / $ratioOrig);
- $newWidth = $maxSize;
- } else {
- $newWidth = round($maxSize * $ratioOrig);
- $newHeight = $maxSize;
- }
-
- return $this->preciseResizeNew((int)round($newWidth), (int)round($newHeight));
- }
-
- /**
- * @param int $width
- * @param int $height
- * @return bool
- */
- public function preciseResize(int $width, int $height): bool {
- if (!$this->valid()) {
- $this->logger->debug(__METHOD__ . '(): No image loaded', ['app' => 'core']);
- return false;
- }
- $result = $this->preciseResizeNew($width, $height);
- imagedestroy($this->resource);
- $this->resource = $result;
- return $this->valid();
- }
-
- /**
- * @param int $width
- * @param int $height
- * @return resource|bool|\GdImage
- */
- public function preciseResizeNew(int $width, int $height) {
- if (!($width > 0) || !($height > 0)) {
- $this->logger->info(__METHOD__ . '(): Requested image size not bigger than 0', ['app' => 'core']);
- return false;
- }
- if (!$this->valid()) {
- $this->logger->debug(__METHOD__ . '(): No image loaded', ['app' => 'core']);
- return false;
- }
- $widthOrig = imagesx($this->resource);
- $heightOrig = imagesy($this->resource);
- $process = imagecreatetruecolor($width, $height);
- if ($process === false) {
- $this->logger->debug(__METHOD__ . '(): Error creating true color image', ['app' => 'core']);
- return false;
- }
-
- // preserve transparency
- if ($this->imageType == IMAGETYPE_GIF or $this->imageType == IMAGETYPE_PNG) {
- imagecolortransparent($process, imagecolorallocatealpha($process, 0, 0, 0, 127));
- imagealphablending($process, false);
- imagesavealpha($process, true);
- }
-
- $res = imagecopyresampled($process, $this->resource, 0, 0, 0, 0, $width, $height, $widthOrig, $heightOrig);
- if ($res === false) {
- $this->logger->debug(__METHOD__ . '(): Error re-sampling process image', ['app' => 'core']);
- imagedestroy($process);
- return false;
- }
- return $process;
- }
-
- /**
- * Crops the image to the middle square. If the image is already square it just returns.
- *
- * @param int $size maximum size for the result (optional)
- * @return bool for success or failure
- */
- public function centerCrop(int $size = 0): bool {
- if (!$this->valid()) {
- $this->logger->debug('OC_Image->centerCrop, No image loaded', ['app' => 'core']);
- return false;
- }
- $widthOrig = imagesx($this->resource);
- $heightOrig = imagesy($this->resource);
- if ($widthOrig === $heightOrig and $size == 0) {
- return true;
- }
- $ratioOrig = $widthOrig / $heightOrig;
- $width = $height = min($widthOrig, $heightOrig);
-
- if ($ratioOrig > 1) {
- $x = (int) (($widthOrig / 2) - ($width / 2));
- $y = 0;
- } else {
- $y = (int) (($heightOrig / 2) - ($height / 2));
- $x = 0;
- }
- if ($size > 0) {
- $targetWidth = $size;
- $targetHeight = $size;
- } else {
- $targetWidth = $width;
- $targetHeight = $height;
- }
- $process = imagecreatetruecolor($targetWidth, $targetHeight);
- if ($process === false) {
- $this->logger->debug('OC_Image->centerCrop, Error creating true color image', ['app' => 'core']);
- return false;
- }
-
- // preserve transparency
- if ($this->imageType == IMAGETYPE_GIF or $this->imageType == IMAGETYPE_PNG) {
- imagecolortransparent($process, imagecolorallocatealpha($process, 0, 0, 0, 127));
- imagealphablending($process, false);
- imagesavealpha($process, true);
- }
-
- imagecopyresampled($process, $this->resource, 0, 0, $x, $y, $targetWidth, $targetHeight, $width, $height);
- if ($process === false) {
- $this->logger->debug('OC_Image->centerCrop, Error re-sampling process image ' . $width . 'x' . $height, ['app' => 'core']);
- return false;
- }
- imagedestroy($this->resource);
- $this->resource = $process;
- return true;
- }
-
- /**
- * Crops the image from point $x$y with dimension $wx$h.
- *
- * @param int $x Horizontal position
- * @param int $y Vertical position
- * @param int $w Width
- * @param int $h Height
- * @return bool for success or failure
- */
- public function crop(int $x, int $y, int $w, int $h): bool {
- if (!$this->valid()) {
- $this->logger->debug(__METHOD__ . '(): No image loaded', ['app' => 'core']);
- return false;
- }
- $result = $this->cropNew($x, $y, $w, $h);
- imagedestroy($this->resource);
- $this->resource = $result;
- return $this->valid();
- }
-
- /**
- * Crops the image from point $x$y with dimension $wx$h.
- *
- * @param int $x Horizontal position
- * @param int $y Vertical position
- * @param int $w Width
- * @param int $h Height
- * @return resource|\GdImage|false
- */
- public function cropNew(int $x, int $y, int $w, int $h) {
- if (!$this->valid()) {
- $this->logger->debug(__METHOD__ . '(): No image loaded', ['app' => 'core']);
- return false;
- }
- $process = imagecreatetruecolor($w, $h);
- if ($process === false) {
- $this->logger->debug(__METHOD__ . '(): Error creating true color image', ['app' => 'core']);
- return false;
- }
-
- // preserve transparency
- if ($this->imageType == IMAGETYPE_GIF or $this->imageType == IMAGETYPE_PNG) {
- imagecolortransparent($process, imagecolorallocatealpha($process, 0, 0, 0, 127));
- imagealphablending($process, false);
- imagesavealpha($process, true);
- }
-
- imagecopyresampled($process, $this->resource, 0, 0, $x, $y, $w, $h, $w, $h);
- if ($process === false) {
- $this->logger->debug(__METHOD__ . '(): Error re-sampling process image ' . $w . 'x' . $h, ['app' => 'core']);
- return false;
- }
- return $process;
- }
-
- /**
- * Resizes the image to fit within a boundary while preserving ratio.
- *
- * Warning: Images smaller than $maxWidth x $maxHeight will end up being scaled up
- *
- * @param int $maxWidth
- * @param int $maxHeight
- * @return bool
- */
- public function fitIn(int $maxWidth, int $maxHeight): bool {
- if (!$this->valid()) {
- $this->logger->debug(__METHOD__ . '(): No image loaded', ['app' => 'core']);
- return false;
- }
- $widthOrig = imagesx($this->resource);
- $heightOrig = imagesy($this->resource);
- $ratio = $widthOrig / $heightOrig;
-
- $newWidth = min($maxWidth, $ratio * $maxHeight);
- $newHeight = min($maxHeight, $maxWidth / $ratio);
-
- $this->preciseResize((int)round($newWidth), (int)round($newHeight));
- return true;
- }
-
- /**
- * Shrinks larger images to fit within specified boundaries while preserving ratio.
- *
- * @param int $maxWidth
- * @param int $maxHeight
- * @return bool
- */
- public function scaleDownToFit(int $maxWidth, int $maxHeight): bool {
- if (!$this->valid()) {
- $this->logger->debug(__METHOD__ . '(): No image loaded', ['app' => 'core']);
- return false;
- }
- $widthOrig = imagesx($this->resource);
- $heightOrig = imagesy($this->resource);
-
- if ($widthOrig > $maxWidth || $heightOrig > $maxHeight) {
- return $this->fitIn($maxWidth, $maxHeight);
- }
-
- return false;
- }
-
- public function copy(): IImage {
- $image = new OC_Image(null, $this->logger, $this->config);
- $image->resource = imagecreatetruecolor($this->width(), $this->height());
- imagecopy(
- $image->resource(),
- $this->resource(),
- 0,
- 0,
- 0,
- 0,
- $this->width(),
- $this->height()
- );
-
- return $image;
- }
-
- public function cropCopy(int $x, int $y, int $w, int $h): IImage {
- $image = new OC_Image(null, $this->logger, $this->config);
- $image->imageType = $this->imageType;
- $image->mimeType = $this->mimeType;
- $image->resource = $this->cropNew($x, $y, $w, $h);
-
- return $image;
- }
-
- public function preciseResizeCopy(int $width, int $height): IImage {
- $image = new OC_Image(null, $this->logger, $this->config);
- $image->imageType = $this->imageType;
- $image->mimeType = $this->mimeType;
- $image->resource = $this->preciseResizeNew($width, $height);
-
- return $image;
- }
-
- public function resizeCopy(int $maxSize): IImage {
- $image = new OC_Image(null, $this->logger, $this->config);
- $image->imageType = $this->imageType;
- $image->mimeType = $this->mimeType;
- $image->resource = $this->resizeNew($maxSize);
-
- return $image;
- }
-
- /**
- * Destroys the current image and resets the object
- */
- public function destroy(): void {
- if ($this->valid()) {
- imagedestroy($this->resource);
- }
- $this->resource = false;
- }
-
- public function __destruct() {
- $this->destroy();
- }
-}
-
-if (!function_exists('exif_imagetype')) {
- /**
- * Workaround if exif_imagetype does not exist
- *
- * @link https://www.php.net/manual/en/function.exif-imagetype.php#80383
- * @param string $fileName
- * @return string|boolean
- */
- function exif_imagetype(string $fileName) {
- if (($info = getimagesize($fileName)) !== false) {
- return $info[2];
- }
- return false;
- }
-}
diff --git a/lib/private/legacy/OC_JSON.php b/lib/private/legacy/OC_JSON.php
index b9cfb8210e0..6daef18dd61 100644
--- a/lib/private/legacy/OC_JSON.php
+++ b/lib/private/legacy/OC_JSON.php
@@ -1,37 +1,18 @@
<?php
+
/**
- * @copyright Copyright (c) 2016, ownCloud, Inc.
- *
- * @author Bart Visscher <bartv@thisnet.nl>
- * @author Christoph Wurst <christoph@winzerhof-wurst.at>
- * @author Lukas Reschke <lukas@statuscode.ch>
- * @author Morris Jobke <hey@morrisjobke.de>
- * @author Robin Appelman <robin@icewind.nl>
- * @author Roeland Jago Douma <roeland@famdouma.nl>
- * @author Thomas Müller <thomas.mueller@tmit.eu>
- * @author Thomas Tanghus <thomas@tanghus.net>
- * @author Vincent Petry <vincent@nextcloud.com>
- *
- * @license AGPL-3.0
- *
- * This code is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License, version 3,
- * as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License, version 3,
- * along with this program. If not, see <http://www.gnu.org/licenses/>
- *
+ * SPDX-FileCopyrightText: 2016-2024 Nextcloud GmbH and Nextcloud contributors
+ * SPDX-FileCopyrightText: 2016 ownCloud, Inc.
+ * SPDX-License-Identifier: AGPL-3.0-only
*/
+
+use OC\Authentication\TwoFactorAuth\Manager as TwoFactorAuthManager;
+
class OC_JSON {
/**
* Check if the app is enabled, send json error msg if not
* @param string $app
- * @deprecated Use the AppFramework instead. It will automatically check if the app is enabled.
+ * @deprecated 12.0.0 Use the AppFramework instead. It will automatically check if the app is enabled.
* @suppress PhanDeprecatedFunction
*/
public static function checkAppEnabled($app) {
@@ -44,11 +25,11 @@ class OC_JSON {
/**
* Check if the user is logged in, send json error msg if not
- * @deprecated Use annotation based ACLs from the AppFramework instead
+ * @deprecated 12.0.0 Use annotation based ACLs from the AppFramework instead
* @suppress PhanDeprecatedFunction
*/
public static function checkLoggedIn() {
- $twoFactorAuthManger = \OC::$server->getTwoFactorAuthManager();
+ $twoFactorAuthManger = \OC::$server->get(TwoFactorAuthManager::class);
if (!\OC::$server->getUserSession()->isLoggedIn()
|| $twoFactorAuthManger->needsSecondFactor(\OC::$server->getUserSession()->getUser())) {
$l = \OC::$server->getL10N('lib');
@@ -60,12 +41,12 @@ class OC_JSON {
/**
* Check an ajax get/post call if the request token is valid, send json error msg if not.
- * @deprecated Use annotation based CSRF checks from the AppFramework instead
+ * @deprecated 12.0.0 Use annotation based CSRF checks from the AppFramework instead
* @suppress PhanDeprecatedFunction
*/
public static function callCheck() {
if (!\OC::$server->getRequest()->passesStrictCookieCheck()) {
- header('Location: '.\OC::$WEBROOT);
+ header('Location: ' . \OC::$WEBROOT);
exit();
}
@@ -78,7 +59,7 @@ class OC_JSON {
/**
* Check if the user is a admin, send json error msg if not.
- * @deprecated Use annotation based ACLs from the AppFramework instead
+ * @deprecated 12.0.0 Use annotation based ACLs from the AppFramework instead
* @suppress PhanDeprecatedFunction
*/
public static function checkAdminUser() {
@@ -91,9 +72,8 @@ class OC_JSON {
/**
* Send json error msg
- * @deprecated Use a AppFramework JSONResponse instead
+ * @deprecated 12.0.0 Use a AppFramework JSONResponse instead
* @suppress PhanDeprecatedFunction
- * @psalm-taint-escape html
*/
public static function error($data = []) {
$data['status'] = 'error';
@@ -103,9 +83,8 @@ class OC_JSON {
/**
* Send json success msg
- * @deprecated Use a AppFramework JSONResponse instead
+ * @deprecated 12.0.0 Use a AppFramework JSONResponse instead
* @suppress PhanDeprecatedFunction
- * @psalm-taint-escape html
*/
public static function success($data = []) {
$data['status'] = 'success';
@@ -114,22 +93,13 @@ class OC_JSON {
}
/**
- * Convert OC_L10N_String to string, for use in json encodings
- */
- protected static function to_string(&$value) {
- if ($value instanceof \OC\L10N\L10NString) {
- $value = (string)$value;
- }
- }
-
- /**
* Encode JSON
- * @deprecated Use a AppFramework JSONResponse instead
+ * @deprecated 12.0.0 Use a AppFramework JSONResponse instead
+ *
+ * @psalm-taint-escape has_quotes
+ * @psalm-taint-escape html
*/
- public static function encode($data) {
- if (is_array($data)) {
- array_walk_recursive($data, ['OC_JSON', 'to_string']);
- }
+ private static function encode($data) {
return json_encode($data, JSON_HEX_TAG);
}
}
diff --git a/lib/private/legacy/OC_Response.php b/lib/private/legacy/OC_Response.php
index b849710e90b..c45852b4b1d 100644
--- a/lib/private/legacy/OC_Response.php
+++ b/lib/private/legacy/OC_Response.php
@@ -1,31 +1,9 @@
<?php
+
/**
- * @copyright Copyright (c) 2016, ownCloud, Inc.
- *
- * @author Andreas Fischer <bantu@owncloud.com>
- * @author Bart Visscher <bartv@thisnet.nl>
- * @author Christoph Wurst <christoph@winzerhof-wurst.at>
- * @author J0WI <J0WI@users.noreply.github.com>
- * @author Lukas Reschke <lukas@statuscode.ch>
- * @author Morris Jobke <hey@morrisjobke.de>
- * @author Roeland Jago Douma <roeland@famdouma.nl>
- * @author Thomas Müller <thomas.mueller@tmit.eu>
- * @author Vincent Petry <vincent@nextcloud.com>
- *
- * @license AGPL-3.0
- *
- * This code is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License, version 3,
- * as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License, version 3,
- * along with this program. If not, see <http://www.gnu.org/licenses/>
- *
+ * SPDX-FileCopyrightText: 2016-2024 Nextcloud GmbH and Nextcloud contributors
+ * SPDX-FileCopyrightText: 2016 ownCloud, Inc.
+ * SPDX-License-Identifier: AGPL-3.0-only
*/
class OC_Response {
/**
@@ -52,7 +30,20 @@ class OC_Response {
* @param string|int|float $length Length to be sent
*/
public static function setContentLengthHeader($length) {
- header('Content-Length: '.$length);
+ if (PHP_INT_SIZE === 4) {
+ if ($length > PHP_INT_MAX && stripos(PHP_SAPI, 'apache') === 0) {
+ // Apache PHP SAPI casts Content-Length headers to PHP integers.
+ // This enforces a limit of PHP_INT_MAX (2147483647 on 32-bit
+ // platforms). So, if the length is greater than PHP_INT_MAX,
+ // we just do not send a Content-Length header to prevent
+ // bodies from being received incompletely.
+ return;
+ }
+ // Convert signed integer or float to unsigned base-10 string.
+ $lfh = new \OC\LargeFileHelper;
+ $length = $lfh->formatUnsignedInteger($length);
+ }
+ header('Content-Length: ' . $length);
}
/**
@@ -68,7 +59,7 @@ class OC_Response {
* @see \OCP\AppFramework\Http\Response::getHeaders
*/
$policy = 'default-src \'self\'; '
- . 'script-src \'self\' \'nonce-'.\OC::$server->getContentSecurityPolicyNonceManager()->getNonce().'\'; '
+ . 'script-src \'self\' \'nonce-' . \OC::$server->getContentSecurityPolicyNonceManager()->getNonce() . '\'; '
. 'style-src \'self\' \'unsafe-inline\'; '
. 'frame-src *; '
. 'img-src * data: blob:; '
@@ -86,8 +77,7 @@ class OC_Response {
header('X-Content-Type-Options: nosniff'); // Disable sniffing the content type for IE
header('X-Frame-Options: SAMEORIGIN'); // Disallow iFraming from other domains
header('X-Permitted-Cross-Domain-Policies: none'); // https://www.adobe.com/devnet/adobe-media-server/articles/cross-domain-xml-for-streaming.html
- header('X-Robots-Tag: none'); // https://developers.google.com/webmasters/control-crawl-index/docs/robots_meta_tag
- header('X-XSS-Protection: 1; mode=block'); // Enforce browser based XSS filters
+ header('X-Robots-Tag: noindex, nofollow'); // https://developers.google.com/webmasters/control-crawl-index/docs/robots_meta_tag
}
}
}
diff --git a/lib/private/legacy/OC_Template.php b/lib/private/legacy/OC_Template.php
index 0c9fa1ccc0c..bccf99af65e 100644
--- a/lib/private/legacy/OC_Template.php
+++ b/lib/private/legacy/OC_Template.php
@@ -1,275 +1,29 @@
<?php
+
/**
- * @copyright Copyright (c) 2016, ownCloud, Inc.
- *
- * @author Bart Visscher <bartv@thisnet.nl>
- * @author Brice Maron <brice@bmaron.net>
- * @author Christoph Wurst <christoph@winzerhof-wurst.at>
- * @author Frank Karlitschek <frank@karlitschek.de>
- * @author Individual IT Services <info@individual-it.net>
- * @author Jakob Sack <mail@jakobsack.de>
- * @author Jan-Christoph Borchardt <hey@jancborchardt.net>
- * @author Joas Schilling <coding@schilljs.com>
- * @author John Molakvoæ <skjnldsv@protonmail.com>
- * @author Jörn Friedrich Dreyer <jfd@butonic.de>
- * @author Julius Härtl <jus@bitgrid.net>
- * @author Lukas Reschke <lukas@statuscode.ch>
- * @author Marin Treselj <marin@pixelipo.com>
- * @author Michael Letzgus <www@chronos.michael-letzgus.de>
- * @author Morris Jobke <hey@morrisjobke.de>
- * @author Robin Appelman <robin@icewind.nl>
- * @author Roeland Jago Douma <roeland@famdouma.nl>
- * @author Thomas Müller <thomas.mueller@tmit.eu>
- * @author Vincent Petry <vincent@nextcloud.com>
- *
- * @license AGPL-3.0
- *
- * This code is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License, version 3,
- * as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License, version 3,
- * along with this program. If not, see <http://www.gnu.org/licenses/>
- *
+ * SPDX-FileCopyrightText: 2016-2024 Nextcloud GmbH and Nextcloud contributors
+ * SPDX-FileCopyrightText: 2016 ownCloud, Inc.
+ * SPDX-License-Identifier: AGPL-3.0-only
*/
-use OC\TemplateLayout;
-use OCP\AppFramework\Http\TemplateResponse;
-use OCP\Util;
-
-require_once __DIR__.'/template/functions.php';
+use OCP\Server;
+use OCP\Template\ITemplateManager;
/**
* This class provides the templates for ownCloud.
+ * @deprecated 32.0.0 Use \OCP\Template\ITemplateManager instead
*/
-class OC_Template extends \OC\Template\Base {
- /** @var string */
- private $renderAs; // Create a full page?
-
- /** @var string */
- private $path; // The path to the template
-
- /** @var array */
- private $headers = []; //custom headers
-
- /** @var string */
- protected $app; // app id
-
- protected static $initTemplateEngineFirstRun = true;
-
- /**
- * Constructor
- *
- * @param string $app app providing the template
- * @param string $name of the template file (without suffix)
- * @param string $renderAs If $renderAs is set, OC_Template will try to
- * produce a full page in the according layout. For
- * now, $renderAs can be set to "guest", "user" or
- * "admin".
- * @param bool $registerCall = true
- */
- public function __construct($app, $name, $renderAs = TemplateResponse::RENDER_AS_BLANK, $registerCall = true) {
- // Read the selected theme from the config file
- self::initTemplateEngine($renderAs);
-
- $theme = OC_Util::getTheme();
-
- $requestToken = (OC::$server->getSession() && $registerCall) ? \OCP\Util::callRegister() : '';
-
- $parts = explode('/', $app); // fix translation when app is something like core/lostpassword
- $l10n = \OC::$server->getL10N($parts[0]);
- /** @var \OCP\Defaults $themeDefaults */
- $themeDefaults = \OC::$server->query(\OCP\Defaults::class);
-
- [$path, $template] = $this->findTemplate($theme, $app, $name);
-
- // Set the private data
- $this->renderAs = $renderAs;
- $this->path = $path;
- $this->app = $app;
-
- parent::__construct($template, $requestToken, $l10n, $themeDefaults);
- }
-
- /**
- * @param string $renderAs
- */
- public static function initTemplateEngine($renderAs) {
- if (self::$initTemplateEngineFirstRun) {
- // apps that started before the template initialization can load their own scripts/styles
- // so to make sure this scripts/styles here are loaded first we put all core scripts first
- // check lib/public/Util.php
- OC_Util::addStyle('server', null, true);
-
- // include common nextcloud webpack bundle
- Util::addScript('core', 'common');
- Util::addScript('core', 'main');
- Util::addTranslations('core');
-
- if (\OC::$server->getSystemConfig()->getValue('installed', false) && !\OCP\Util::needUpgrade()) {
- Util::addScript('core', 'files_fileinfo');
- Util::addScript('core', 'files_client');
- Util::addScript('core', 'merged-template-prepend');
- }
-
- // If installed and background job is set to ajax, add dedicated script
- if (\OC::$server->getSystemConfig()->getValue('installed', false)
- && $renderAs !== TemplateResponse::RENDER_AS_ERROR
- && !\OCP\Util::needUpgrade()) {
- if (\OC::$server->getConfig()->getAppValue('core', 'backgroundjobs_mode', 'ajax') == 'ajax') {
- Util::addScript('core', 'backgroundjobs');
- }
- }
-
- self::$initTemplateEngineFirstRun = false;
- }
- }
-
-
- /**
- * find the template with the given name
- * @param string $name of the template file (without suffix)
- *
- * Will select the template file for the selected theme.
- * Checking all the possible locations.
- * @param string $theme
- * @param string $app
- * @return string[]
- */
- protected function findTemplate($theme, $app, $name) {
- // Check if it is a app template or not.
- if ($app !== '') {
- $dirs = $this->getAppTemplateDirs($theme, $app, OC::$SERVERROOT, OC_App::getAppPath($app));
- } else {
- $dirs = $this->getCoreTemplateDirs($theme, OC::$SERVERROOT);
- }
- $locator = new \OC\Template\TemplateFileLocator($dirs);
- $template = $locator->find($name);
- $path = $locator->getPath();
- return [$path, $template];
- }
-
- /**
- * Add a custom element to the header
- * @param string $tag tag name of the element
- * @param array $attributes array of attributes for the element
- * @param string $text the text content for the element. If $text is null then the
- * element will be written as empty element. So use "" to get a closing tag.
- */
- public function addHeader($tag, $attributes, $text = null) {
- $this->headers[] = [
- 'tag' => $tag,
- 'attributes' => $attributes,
- 'text' => $text
- ];
- }
-
- /**
- * Process the template
- * @return string
- *
- * This function process the template. If $this->renderAs is set, it
- * will produce a full page.
- */
- public function fetchPage($additionalParams = null) {
- $data = parent::fetchPage($additionalParams);
-
- if ($this->renderAs) {
- $page = new TemplateLayout($this->renderAs, $this->app);
-
- if (is_array($additionalParams)) {
- foreach ($additionalParams as $key => $value) {
- $page->assign($key, $value);
- }
- }
-
- // Add custom headers
- $headers = '';
- foreach (OC_Util::$headers as $header) {
- $headers .= '<'.\OCP\Util::sanitizeHTML($header['tag']);
- if (strcasecmp($header['tag'], 'script') === 0 && in_array('src', array_map('strtolower', array_keys($header['attributes'])))) {
- $headers .= ' defer';
- }
- foreach ($header['attributes'] as $name => $value) {
- $headers .= ' '.\OCP\Util::sanitizeHTML($name).'="'.\OCP\Util::sanitizeHTML($value).'"';
- }
- if ($header['text'] !== null) {
- $headers .= '>'.\OCP\Util::sanitizeHTML($header['text']).'</'.\OCP\Util::sanitizeHTML($header['tag']).'>';
- } else {
- $headers .= '/>';
- }
- }
-
- $page->assign('headers', $headers);
-
- $page->assign('content', $data);
- return $page->fetchPage($additionalParams);
- }
-
- return $data;
- }
-
- /**
- * Include template
- *
- * @param string $file
- * @param array|null $additionalParams
- * @return string returns content of included template
- *
- * Includes another template. use <?php echo $this->inc('template'); ?> to
- * do this.
- */
- public function inc($file, $additionalParams = null) {
- return $this->load($this->path.$file.'.php', $additionalParams);
- }
-
- /**
- * Shortcut to print a simple page for users
- * @param string $application The application we render the template for
- * @param string $name Name of the template
- * @param array $parameters Parameters for the template
- * @return boolean|null
- */
- public static function printUserPage($application, $name, $parameters = []) {
- $content = new OC_Template($application, $name, "user");
- foreach ($parameters as $key => $value) {
- $content->assign($key, $value);
- }
- print $content->printPage();
- }
-
- /**
- * Shortcut to print a simple page for admins
- * @param string $application The application we render the template for
- * @param string $name Name of the template
- * @param array $parameters Parameters for the template
- * @return bool
- */
- public static function printAdminPage($application, $name, $parameters = []) {
- $content = new OC_Template($application, $name, "admin");
- foreach ($parameters as $key => $value) {
- $content->assign($key, $value);
- }
- return $content->printPage();
- }
-
+class OC_Template extends \OC\Template\Template {
/**
* Shortcut to print a simple page for guests
* @param string $application The application we render the template for
* @param string $name Name of the template
- * @param array|string $parameters Parameters for the template
+ * @param array $parameters Parameters for the template
* @return bool
+ * @deprecated 32.0.0 Use \OCP\Template\ITemplateManager instead
*/
public static function printGuestPage($application, $name, $parameters = []) {
- $content = new OC_Template($application, $name, $name === 'error' ? $name : 'guest');
- foreach ($parameters as $key => $value) {
- $content->assign($key, $value);
- }
- return $content->printPage();
+ Server::get(ITemplateManager::class)->printGuestPage($application, $name, $parameters);
+ return true;
}
/**
@@ -277,81 +31,21 @@ class OC_Template extends \OC\Template\Base {
* @param string $error_msg The error message to show
* @param string $hint An optional hint message - needs to be properly escape
* @param int $statusCode
- * @suppress PhanAccessMethodInternal
+ * @return never
+ * @deprecated 32.0.0 Use \OCP\Template\ITemplateManager instead
*/
public static function printErrorPage($error_msg, $hint = '', $statusCode = 500) {
- if (\OC::$server->getAppManager()->isEnabledForUser('theming') && !\OC_App::isAppLoaded('theming')) {
- \OC_App::loadApp('theming');
- }
-
-
- if ($error_msg === $hint) {
- // If the hint is the same as the message there is no need to display it twice.
- $hint = '';
- }
-
- http_response_code($statusCode);
- try {
- $content = new \OC_Template('', 'error', 'error', false);
- $errors = [['error' => $error_msg, 'hint' => $hint]];
- $content->assign('errors', $errors);
- $content->printPage();
- } catch (\Exception $e) {
- $logger = \OC::$server->getLogger();
- $logger->error("$error_msg $hint", ['app' => 'core']);
- $logger->logException($e, ['app' => 'core']);
-
- header('Content-Type: text/plain; charset=utf-8');
- print("$error_msg $hint");
- }
- die();
+ Server::get(ITemplateManager::class)->printErrorPage($error_msg, $hint, $statusCode);
}
/**
* print error page using Exception details
* @param Exception|Throwable $exception
* @param int $statusCode
- * @return bool|string
- * @suppress PhanAccessMethodInternal
+ * @return never
+ * @deprecated 32.0.0 Use \OCP\Template\ITemplateManager instead
*/
public static function printExceptionErrorPage($exception, $statusCode = 503) {
- http_response_code($statusCode);
- try {
- $request = \OC::$server->getRequest();
- $content = new \OC_Template('', 'exception', 'error', false);
- $content->assign('errorClass', get_class($exception));
- $content->assign('errorMsg', $exception->getMessage());
- $content->assign('errorCode', $exception->getCode());
- $content->assign('file', $exception->getFile());
- $content->assign('line', $exception->getLine());
- $content->assign('exception', $exception);
- $content->assign('debugMode', \OC::$server->getSystemConfig()->getValue('debug', false));
- $content->assign('remoteAddr', $request->getRemoteAddress());
- $content->assign('requestID', $request->getId());
- $content->printPage();
- } catch (\Exception $e) {
- try {
- $logger = \OC::$server->getLogger();
- $logger->logException($exception, ['app' => 'core']);
- $logger->logException($e, ['app' => 'core']);
- } catch (Throwable $e) {
- // no way to log it properly - but to avoid a white page of death we send some output
- header('Content-Type: text/plain; charset=utf-8');
- print("Internal Server Error\n\n");
- print("The server encountered an internal error and was unable to complete your request.\n");
- print("Please contact the server administrator if this error reappears multiple times, please include the technical details below in your report.\n");
- print("More details can be found in the server log.\n");
-
- // and then throw it again to log it at least to the web server error log
- throw $e;
- }
-
- header('Content-Type: text/plain; charset=utf-8');
- print("Internal Server Error\n\n");
- print("The server encountered an internal error and was unable to complete your request.\n");
- print("Please contact the server administrator if this error reappears multiple times, please include the technical details below in your report.\n");
- print("More details can be found in the server log.\n");
- }
- die();
+ Server::get(ITemplateManager::class)->printExceptionErrorPage($exception, $statusCode);
}
}
diff --git a/lib/private/legacy/OC_User.php b/lib/private/legacy/OC_User.php
index 8aaa9072ba4..e5343864c45 100644
--- a/lib/private/legacy/OC_User.php
+++ b/lib/private/legacy/OC_User.php
@@ -1,46 +1,25 @@
<?php
+
/**
- * @copyright Copyright (c) 2016, ownCloud, Inc.
- *
- * @author Aldo "xoen" Giambelluca <xoen@xoen.org>
- * @author Andreas Fischer <bantu@owncloud.com>
- * @author Arthur Schiwon <blizzz@arthur-schiwon.de>
- * @author Bartek Przybylski <bart.p.pl@gmail.com>
- * @author Björn Schießle <bjoern@schiessle.org>
- * @author Christoph Wurst <christoph@winzerhof-wurst.at>
- * @author Georg Ehrke <oc.list@georgehrke.com>
- * @author Jakob Sack <mail@jakobsack.de>
- * @author Jörn Friedrich Dreyer <jfd@butonic.de>
- * @author Lukas Reschke <lukas@statuscode.ch>
- * @author Morris Jobke <hey@morrisjobke.de>
- * @author Robin Appelman <robin@icewind.nl>
- * @author Robin McCorkell <robin@mccorkell.me.uk>
- * @author Roeland Jago Douma <roeland@famdouma.nl>
- * @author shkdee <louis.traynard@m4x.org>
- * @author Thomas Müller <thomas.mueller@tmit.eu>
- * @author Vincent Petry <vincent@nextcloud.com>
- *
- * @license AGPL-3.0
- *
- * This code is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License, version 3,
- * as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License, version 3,
- * along with this program. If not, see <http://www.gnu.org/licenses/>
- *
+ * SPDX-FileCopyrightText: 2016-2024 Nextcloud GmbH and Nextcloud contributors
+ * SPDX-FileCopyrightText: 2016 ownCloud, Inc.
+ * SPDX-License-Identifier: AGPL-3.0-only
*/
-
-use OC\User\LoginException;
+use OC\Authentication\Token\IProvider;
+use OC\User\DisabledUserException;
+use OCP\Authentication\Exceptions\InvalidTokenException;
+use OCP\Authentication\Exceptions\WipeTokenException;
+use OCP\Authentication\Token\IToken;
use OCP\EventDispatcher\IEventDispatcher;
-use OCP\ILogger;
+use OCP\IGroupManager;
+use OCP\ISession;
+use OCP\IUser;
use OCP\IUserManager;
+use OCP\Server;
+use OCP\Session\Exceptions\SessionNotAvailableException;
+use OCP\User\Events\BeforeUserLoggedInEvent;
use OCP\User\Events\UserLoggedInEvent;
+use Psr\Log\LoggerInterface;
/**
* This class provides wrapper methods for user management. Multiple backends are
@@ -61,8 +40,6 @@ use OCP\User\Events\UserLoggedInEvent;
* logout()
*/
class OC_User {
- private static $_usedBackends = [];
-
private static $_setupedBackends = [];
// bool, stores if a user want to access a resource anonymously, e.g if they open a public link
@@ -73,17 +50,16 @@ class OC_User {
*
* @param string|\OCP\UserInterface $backend default: database The backend to use for user management
* @return bool
+ * @deprecated 32.0.0 Use IUserManager::registerBackend instead
*
* Set the User Authentication Module
- * @suppress PhanDeprecatedFunction
*/
public static function useBackend($backend = 'database') {
if ($backend instanceof \OCP\UserInterface) {
- self::$_usedBackends[get_class($backend)] = $backend;
- \OC::$server->getUserManager()->registerBackend($backend);
+ Server::get(IUserManager::class)->registerBackend($backend);
} else {
// You'll never know what happens
- if (null === $backend or !is_string($backend)) {
+ if ($backend === null or !is_string($backend)) {
$backend = 'database';
}
@@ -92,19 +68,16 @@ class OC_User {
case 'database':
case 'mysql':
case 'sqlite':
- \OCP\Util::writeLog('core', 'Adding user backend ' . $backend . '.', ILogger::DEBUG);
- self::$_usedBackends[$backend] = new \OC\User\Database();
- \OC::$server->getUserManager()->registerBackend(self::$_usedBackends[$backend]);
+ Server::get(LoggerInterface::class)->debug('Adding user backend ' . $backend . '.', ['app' => 'core']);
+ Server::get(IUserManager::class)->registerBackend(new \OC\User\Database());
break;
case 'dummy':
- self::$_usedBackends[$backend] = new \Test\Util\User\Dummy();
- \OC::$server->getUserManager()->registerBackend(self::$_usedBackends[$backend]);
+ Server::get(IUserManager::class)->registerBackend(new \Test\Util\User\Dummy());
break;
default:
- \OCP\Util::writeLog('core', 'Adding default user backend ' . $backend . '.', ILogger::DEBUG);
+ Server::get(LoggerInterface::class)->debug('Adding default user backend ' . $backend . '.', ['app' => 'core']);
$className = 'OC_USER_' . strtoupper($backend);
- self::$_usedBackends[$backend] = new $className();
- \OC::$server->getUserManager()->registerBackend(self::$_usedBackends[$backend]);
+ Server::get(IUserManager::class)->registerBackend(new $className());
break;
}
}
@@ -113,10 +86,10 @@ class OC_User {
/**
* remove all used backends
+ * @deprecated 32.0.0 Use IUserManager::clearBackends instead
*/
public static function clearBackends() {
- self::$_usedBackends = [];
- \OC::$server->getUserManager()->clearBackends();
+ Server::get(IUserManager::class)->clearBackends();
}
/**
@@ -137,7 +110,7 @@ class OC_User {
$class = $config['class'];
$arguments = $config['arguments'];
if (class_exists($class)) {
- if (array_search($i, self::$_setupedBackends) === false) {
+ if (!in_array($i, self::$_setupedBackends)) {
// make a reflection object
$reflectionObj = new ReflectionClass($class);
@@ -146,10 +119,10 @@ class OC_User {
self::useBackend($backend);
self::$_setupedBackends[] = $i;
} else {
- \OCP\Util::writeLog('core', 'User backend ' . $class . ' already initialized.', ILogger::DEBUG);
+ Server::get(LoggerInterface::class)->debug('User backend ' . $class . ' already initialized.', ['app' => 'core']);
}
} else {
- \OCP\Util::writeLog('core', 'User backend ' . $class . ' not found.', ILogger::ERROR);
+ Server::get(LoggerInterface::class)->error('User backend ' . $class . ' not found.', ['app' => 'core']);
}
}
}
@@ -166,15 +139,19 @@ class OC_User {
public static function loginWithApache(\OCP\Authentication\IApacheBackend $backend) {
$uid = $backend->getCurrentUserId();
$run = true;
- OC_Hook::emit("OC_User", "pre_login", ["run" => &$run, "uid" => $uid, 'backend' => $backend]);
+ OC_Hook::emit('OC_User', 'pre_login', ['run' => &$run, 'uid' => $uid, 'backend' => $backend]);
if ($uid) {
if (self::getUser() !== $uid) {
self::setUserId($uid);
$userSession = \OC::$server->getUserSession();
+
+ /** @var IEventDispatcher $dispatcher */
+ $dispatcher = \OC::$server->get(IEventDispatcher::class);
+
if ($userSession->getUser() && !$userSession->getUser()->isEnabled()) {
- $message = \OC::$server->getL10N('lib')->t('User disabled');
- throw new LoginException($message);
+ $message = \OC::$server->getL10N('lib')->t('Account disabled');
+ throw new DisabledUserException($message);
}
$userSession->setLoginName($uid);
$request = OC::$server->getRequest();
@@ -182,8 +159,28 @@ class OC_User {
if ($backend instanceof \OCP\Authentication\IProvideUserSecretBackend) {
$password = $backend->getCurrentUserSecret();
}
+
+ /** @var IEventDispatcher $dispatcher */
+ $dispatcher->dispatchTyped(new BeforeUserLoggedInEvent($uid, $password, $backend));
+
$userSession->createSessionToken($request, $uid, $uid, $password);
$userSession->createRememberMeToken($userSession->getUser());
+
+ if (empty($password)) {
+ $tokenProvider = \OC::$server->get(IProvider::class);
+ try {
+ $token = $tokenProvider->getToken($userSession->getSession()->getId());
+ $token->setScope([
+ IToken::SCOPE_SKIP_PASSWORD_VALIDATION => true,
+ IToken::SCOPE_FILESYSTEM => true,
+ ]);
+ $tokenProvider->updateToken($token);
+ } catch (InvalidTokenException|WipeTokenException|SessionNotAvailableException) {
+ // swallow the exceptions as we do not deal with them here
+ // simply skip updating the token when is it missing
+ }
+ }
+
// setup the filesystem
OC_Util::setupFS($uid);
// first call the post_login hooks, the login-process needs to be
@@ -199,8 +196,6 @@ class OC_User {
'isTokenLogin' => false,
]
);
- /** @var IEventDispatcher $dispatcher */
- $dispatcher = \OC::$server->get(IEventDispatcher::class);
$dispatcher->dispatchTyped(new UserLoggedInEvent(
\OC::$server->get(IUserManager::class)->get($uid),
$uid,
@@ -220,9 +215,9 @@ class OC_User {
* Verify with Apache whether user is authenticated.
*
* @return boolean|null
- * true: authenticated
- * false: not authenticated
- * null: not handled / no backend available
+ * true: authenticated
+ * false: not authenticated
+ * null: not handled / no backend available
*/
public static function handleApacheAuth() {
$backend = self::findFirstActiveUsedBackend();
@@ -247,7 +242,7 @@ class OC_User {
*/
public static function setUserId($uid) {
$userSession = \OC::$server->getUserSession();
- $userManager = \OC::$server->getUserManager();
+ $userManager = Server::get(IUserManager::class);
if ($user = $userManager->get($uid)) {
$userSession->setUser($user);
} else {
@@ -258,7 +253,7 @@ class OC_User {
/**
* Check if the user is logged in, considers also the HTTP basic credentials
*
- * @deprecated use \OC::$server->getUserSession()->isLoggedIn()
+ * @deprecated 12.0.0 use \OC::$server->getUserSession()->isLoggedIn()
* @return bool
*/
public static function isLoggedIn() {
@@ -296,7 +291,7 @@ class OC_User {
}
$user = \OC::$server->getUserSession()->getUser();
- if ($user instanceof \OCP\IUser) {
+ if ($user instanceof IUser) {
$backend = $user->getBackend();
if ($backend instanceof \OCP\User\Backend\ICustomLogout) {
return $backend->getLogoutUrl();
@@ -316,12 +311,9 @@ class OC_User {
* @return bool
*/
public static function isAdminUser($uid) {
- $group = \OC::$server->getGroupManager()->get('admin');
- $user = \OC::$server->getUserManager()->get($uid);
- if ($group && $user && $group->inGroup($user) && self::$incognitoMode === false) {
- return true;
- }
- return false;
+ $user = Server::get(IUserManager::class)->get($uid);
+ $isAdmin = $user && Server::get(IGroupManager::class)->isAdmin($user->getUID());
+ return $isAdmin && self::$incognitoMode === false;
}
@@ -331,7 +323,7 @@ class OC_User {
* @return string|false uid or false
*/
public static function getUser() {
- $uid = \OC::$server->getSession() ? \OC::$server->getSession()->get('user_id') : null;
+ $uid = Server::get(ISession::class)?->get('user_id');
if (!is_null($uid) && self::$incognitoMode === false) {
return $uid;
} else {
@@ -350,7 +342,7 @@ class OC_User {
* Change the password of a user
*/
public static function setPassword($uid, $password, $recoveryPassword = null) {
- $user = \OC::$server->getUserManager()->get($uid);
+ $user = Server::get(IUserManager::class)->get($uid);
if ($user) {
return $user->setPassword($password, $recoveryPassword);
} else {
@@ -363,10 +355,10 @@ class OC_User {
* @return string
*
* returns the path to the users home directory
- * @deprecated Use \OC::$server->getUserManager->getHome()
+ * @deprecated 12.0.0 Use \OC::$server->getUserManager->getHome()
*/
public static function getHome($uid) {
- $user = \OC::$server->getUserManager()->get($uid);
+ $user = Server::get(IUserManager::class)->get($uid);
if ($user) {
return $user->getHome();
} else {
@@ -383,11 +375,11 @@ class OC_User {
* @return array associative array with all display names (value) and corresponding uids (key)
*
* Get a list of all display names and user ids.
- * @deprecated Use \OC::$server->getUserManager->searchDisplayName($search, $limit, $offset) instead.
+ * @deprecated 12.0.0 Use \OC::$server->getUserManager->searchDisplayName($search, $limit, $offset) instead.
*/
public static function getDisplayNames($search = '', $limit = null, $offset = null) {
$displayNames = [];
- $users = \OC::$server->getUserManager()->searchDisplayName($search, $limit, $offset);
+ $users = Server::get(IUserManager::class)->searchDisplayName($search, $limit, $offset);
foreach ($users as $user) {
$displayNames[$user->getUID()] = $user->getDisplayName();
}
@@ -400,7 +392,7 @@ class OC_User {
* @return OCP\Authentication\IApacheBackend|null if no backend active, otherwise OCP\Authentication\IApacheBackend
*/
private static function findFirstActiveUsedBackend() {
- foreach (self::$_usedBackends as $backend) {
+ foreach (Server::get(IUserManager::class)->getBackends() as $backend) {
if ($backend instanceof OCP\Authentication\IApacheBackend) {
if ($backend->isSessionActive()) {
return $backend;
diff --git a/lib/private/legacy/OC_Util.php b/lib/private/legacy/OC_Util.php
index 6dc08341b18..ebca1105838 100644
--- a/lib/private/legacy/OC_Util.php
+++ b/lib/private/legacy/OC_Util.php
@@ -1,93 +1,30 @@
<?php
+
/**
- * @copyright Copyright (c) 2016, ownCloud, Inc.
- *
- * @author Arthur Schiwon <blizzz@arthur-schiwon.de>
- * @author Bart Visscher <bartv@thisnet.nl>
- * @author Bernhard Posselt <dev@bernhard-posselt.com>
- * @author Birk Borkason <daniel.niccoli@gmail.com>
- * @author Bjoern Schiessle <bjoern@schiessle.org>
- * @author Björn Schießle <bjoern@schiessle.org>
- * @author Brice Maron <brice@bmaron.net>
- * @author Christopher Schäpers <kondou@ts.unde.re>
- * @author Christoph Wurst <christoph@winzerhof-wurst.at>
- * @author Clark Tomlinson <fallen013@gmail.com>
- * @author cmeh <cmeh@users.noreply.github.com>
- * @author Eric Masseran <rico.masseran@gmail.com>
- * @author Felix Epp <work@felixepp.de>
- * @author Florin Peter <github@florin-peter.de>
- * @author Frank Karlitschek <frank@karlitschek.de>
- * @author Georg Ehrke <oc.list@georgehrke.com>
- * @author helix84 <helix84@centrum.sk>
- * @author Ilja Neumann <ineumann@owncloud.com>
- * @author Individual IT Services <info@individual-it.net>
- * @author Jakob Sack <mail@jakobsack.de>
- * @author Joas Schilling <coding@schilljs.com>
- * @author John Molakvoæ <skjnldsv@protonmail.com>
- * @author Jörn Friedrich Dreyer <jfd@butonic.de>
- * @author Julius Härtl <jus@bitgrid.net>
- * @author Kawohl <john@owncloud.com>
- * @author Lukas Reschke <lukas@statuscode.ch>
- * @author Markus Goetz <markus@woboq.com>
- * @author Martin Mattel <martin.mattel@diemattels.at>
- * @author Marvin Thomas Rabe <mrabe@marvinrabe.de>
- * @author Michael Gapczynski <GapczynskiM@gmail.com>
- * @author Morris Jobke <hey@morrisjobke.de>
- * @author rakekniven <mark.ziegler@rakekniven.de>
- * @author Robert Dailey <rcdailey@gmail.com>
- * @author Robin Appelman <robin@icewind.nl>
- * @author Robin McCorkell <robin@mccorkell.me.uk>
- * @author Roeland Jago Douma <roeland@famdouma.nl>
- * @author Sebastian Wessalowski <sebastian@wessalowski.org>
- * @author Stefan Rado <owncloud@sradonia.net>
- * @author Stefan Weil <sw@weilnetz.de>
- * @author Thomas Müller <thomas.mueller@tmit.eu>
- * @author Thomas Tanghus <thomas@tanghus.net>
- * @author Valdnet <47037905+Valdnet@users.noreply.github.com>
- * @author Victor Dubiniuk <dubiniuk@owncloud.com>
- * @author Vincent Petry <vincent@nextcloud.com>
- * @author Volkan Gezer <volkangezer@gmail.com>
- *
- * @license AGPL-3.0
- *
- * This code is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License, version 3,
- * as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License, version 3,
- * along with this program. If not, see <http://www.gnu.org/licenses/>
- *
+ * SPDX-FileCopyrightText: 2016-2024 Nextcloud GmbH and Nextcloud contributors
+ * SPDX-FileCopyrightText: 2016 ownCloud, Inc.
+ * SPDX-License-Identifier: AGPL-3.0-only
*/
-
use bantu\IniGetWrapper\IniGetWrapper;
-use OC\AppFramework\Http\Request;
+use OC\Authentication\TwoFactorAuth\Manager as TwoFactorAuthManager;
use OC\Files\SetupManager;
use OCP\Files\Template\ITemplateManager;
use OCP\IConfig;
-use OCP\IDBConnection;
use OCP\IGroupManager;
use OCP\IURLGenerator;
use OCP\IUser;
+use OCP\L10N\IFactory;
+use OCP\Security\ISecureRandom;
use OCP\Share\IManager;
use Psr\Log\LoggerInterface;
+/**
+ * @deprecated 32.0.0 Use \OCP\Util or any appropriate official API instead
+ */
class OC_Util {
- public static $scripts = [];
public static $styles = [];
public static $headers = [];
- /** @var array Local cache of version.php */
- private static $versionCache = null;
-
- protected static function getAppManager() {
- return \OC::$server->getAppManager();
- }
-
/**
* Setup the file system
*
@@ -120,8 +57,8 @@ class OC_Util {
* Check if a password is required for each public link
*
* @param bool $checkGroupMembership Check group membership exclusion
- * @return boolean
- * @suppress PhanDeprecatedFunction
+ * @return bool
+ * @deprecated 32.0.0 use OCP\Share\IManager's shareApiLinkEnforcePassword directly
*/
public static function isPublicLinkPasswordRequired(bool $checkGroupMembership = true) {
/** @var IManager $shareManager */
@@ -135,6 +72,7 @@ class OC_Util {
* @param IGroupManager $groupManager
* @param IUser|null $user
* @return bool
+ * @deprecated 32.0.0 use OCP\Share\IManager's sharingDisabledForUser directly
*/
public static function isSharingDisabledForUser(IConfig $config, IGroupManager $groupManager, $user) {
/** @var IManager $shareManager */
@@ -146,8 +84,8 @@ class OC_Util {
/**
* check if share API enforces a default expire date
*
- * @return boolean
- * @suppress PhanDeprecatedFunction
+ * @return bool
+ * @deprecated 32.0.0 use OCP\Share\IManager's shareApiLinkDefaultExpireDateEnforced directly
*/
public static function isDefaultExpireDateEnforced() {
/** @var IManager $shareManager */
@@ -159,7 +97,8 @@ class OC_Util {
* Get the quota of a user
*
* @param IUser|null $user
- * @return int|\OCP\Files\FileInfo::SPACE_UNLIMITED|false Quota bytes
+ * @return int|\OCP\Files\FileInfo::SPACE_UNLIMITED|false|float Quota bytes
+ * @deprecated 9.0.0 - Use \OCP\IUser::getQuota or \OCP\IUser::getQuotaBytes
*/
public static function getUserQuota(?IUser $user) {
if (is_null($user)) {
@@ -169,7 +108,7 @@ class OC_Util {
if ($userQuota === 'none') {
return \OCP\Files\FileInfo::SPACE_UNLIMITED;
}
- return OC_Helper::computerFileSize($userQuota);
+ return \OCP\Util::computerFileSize($userQuota);
}
/**
@@ -185,8 +124,8 @@ class OC_Util {
/** @var LoggerInterface $logger */
$logger = \OC::$server->get(LoggerInterface::class);
- $plainSkeletonDirectory = \OC::$server->getConfig()->getSystemValue('skeletondirectory', \OC::$SERVERROOT . '/core/skeleton');
- $userLang = \OC::$server->getL10NFactory()->findLanguage();
+ $plainSkeletonDirectory = \OC::$server->getConfig()->getSystemValueString('skeletondirectory', \OC::$SERVERROOT . '/core/skeleton');
+ $userLang = \OC::$server->get(IFactory::class)->findLanguage();
$skeletonDirectory = str_replace('{lang}', $userLang, $plainSkeletonDirectory);
if (!file_exists($skeletonDirectory)) {
@@ -213,7 +152,7 @@ class OC_Util {
}
if (!empty($skeletonDirectory)) {
- $logger->debug('copying skeleton for '.$userId.' from '.$skeletonDirectory.' to '.$userDirectory->getFullPath('/'), ['app' => 'files_skeleton']);
+ $logger->debug('copying skeleton for ' . $userId . ' from ' . $skeletonDirectory . ' to ' . $userDirectory->getFullPath('/'), ['app' => 'files_skeleton']);
self::copyr($skeletonDirectory, $userDirectory);
// update the file cache
$userDirectory->getStorage()->getScanner()->scan('', \OC\Files\Cache\Scanner::SCAN_RECURSIVE);
@@ -232,7 +171,7 @@ class OC_Util {
* @return void
*/
public static function copyr($source, \OCP\Files\Folder $target) {
- $logger = \OC::$server->getLogger();
+ $logger = \OCP\Server::get(LoggerInterface::class);
// Verify if folder exists
$dir = opendir($source);
@@ -248,14 +187,13 @@ class OC_Util {
$child = $target->newFolder($file);
self::copyr($source . '/' . $file, $child);
} else {
- $child = $target->newFile($file);
$sourceStream = fopen($source . '/' . $file, 'r');
if ($sourceStream === false) {
$logger->error(sprintf('Could not fopen "%s"', $source . '/' . $file), ['app' => 'core']);
closedir($dir);
return;
}
- $child->putContent($sourceStream);
+ $target->newFile($file, $sourceStream);
}
}
}
@@ -263,97 +201,24 @@ class OC_Util {
}
/**
- * @return void
- * @suppress PhanUndeclaredMethod
+ * @deprecated 32.0.0 Call tearDown directly on SetupManager
*/
- public static function tearDownFS() {
- /** @var SetupManager $setupManager */
- $setupManager = \OC::$server->get(SetupManager::class);
+ public static function tearDownFS(): void {
+ $setupManager = \OCP\Server::get(SetupManager::class);
$setupManager->tearDown();
}
/**
- * get the current installed version of ownCloud
- *
- * @return array
- */
- public static function getVersion() {
- OC_Util::loadVersion();
- return self::$versionCache['OC_Version'];
- }
-
- /**
- * get the current installed version string of ownCloud
- *
- * @return string
- */
- public static function getVersionString() {
- OC_Util::loadVersion();
- return self::$versionCache['OC_VersionString'];
- }
-
- /**
- * @deprecated the value is of no use anymore
- * @return string
- */
- public static function getEditionString() {
- return '';
- }
-
- /**
- * @description get the update channel of the current installed of ownCloud.
- * @return string
- */
- public static function getChannel() {
- OC_Util::loadVersion();
- return \OC::$server->getConfig()->getSystemValue('updater.release.channel', self::$versionCache['OC_Channel']);
- }
-
- /**
- * @description get the build number of the current installed of ownCloud.
- * @return string
- */
- public static function getBuild() {
- OC_Util::loadVersion();
- return self::$versionCache['OC_Build'];
- }
-
- /**
- * @description load the version.php into the session as cache
- * @suppress PhanUndeclaredVariable
- */
- private static function loadVersion() {
- if (self::$versionCache !== null) {
- return;
- }
-
- $timestamp = filemtime(OC::$SERVERROOT . '/version.php');
- require OC::$SERVERROOT . '/version.php';
- /** @var int $timestamp */
- self::$versionCache['OC_Version_Timestamp'] = $timestamp;
- /** @var string $OC_Version */
- self::$versionCache['OC_Version'] = $OC_Version;
- /** @var string $OC_VersionString */
- self::$versionCache['OC_VersionString'] = $OC_VersionString;
- /** @var string $OC_Build */
- self::$versionCache['OC_Build'] = $OC_Build;
-
- /** @var string $OC_Channel */
- self::$versionCache['OC_Channel'] = $OC_Channel;
- }
-
- /**
* generates a path for JS/CSS files. If no application is provided it will create the path for core.
*
* @param string $application application to get the files from
* @param string $directory directory within this application (css, js, vendor, etc)
- * @param string $file the file inside of the above folder
- * @return string the path
+ * @param ?string $file the file inside of the above folder
*/
- private static function generatePath($application, $directory, $file) {
+ private static function generatePath($application, $directory, $file): string {
if (is_null($file)) {
$file = $application;
- $application = "";
+ $application = '';
}
if (!empty($application)) {
return "$application/$directory/$file";
@@ -363,70 +228,16 @@ class OC_Util {
}
/**
- * add a javascript file
- *
- * @deprecated 24.0.0 - Use \OCP\Util::addScript
- *
- * @param string $application application id
- * @param string|null $file filename
- * @param bool $prepend prepend the Script to the beginning of the list
- * @return void
- */
- public static function addScript($application, $file = null, $prepend = false) {
- $path = OC_Util::generatePath($application, 'js', $file);
-
- // core js files need separate handling
- if ($application !== 'core' && $file !== null) {
- self::addTranslations($application);
- }
- self::addExternalResource($application, $prepend, $path, "script");
- }
-
- /**
- * add a javascript file from the vendor sub folder
- *
- * @param string $application application id
- * @param string|null $file filename
- * @param bool $prepend prepend the Script to the beginning of the list
- * @return void
- */
- public static function addVendorScript($application, $file = null, $prepend = false) {
- $path = OC_Util::generatePath($application, 'vendor', $file);
- self::addExternalResource($application, $prepend, $path, "script");
- }
-
- /**
- * add a translation JS file
- *
- * @deprecated 24.0.0
- *
- * @param string $application application id
- * @param string|null $languageCode language code, defaults to the current language
- * @param bool|null $prepend prepend the Script to the beginning of the list
- */
- public static function addTranslations($application, $languageCode = null, $prepend = false) {
- if (is_null($languageCode)) {
- $languageCode = \OC::$server->getL10NFactory()->findLanguage($application);
- }
- if (!empty($application)) {
- $path = "$application/l10n/$languageCode";
- } else {
- $path = "l10n/$languageCode";
- }
- self::addExternalResource($application, $prepend, $path, "script");
- }
-
- /**
* add a css file
*
* @param string $application application id
* @param string|null $file filename
* @param bool $prepend prepend the Style to the beginning of the list
- * @return void
+ * @deprecated 32.0.0 Use \OCP\Util::addStyle
*/
- public static function addStyle($application, $file = null, $prepend = false) {
+ public static function addStyle($application, $file = null, $prepend = false): void {
$path = OC_Util::generatePath($application, 'css', $file);
- self::addExternalResource($application, $prepend, $path, "style");
+ self::addExternalResource($application, $prepend, $path, 'style');
}
/**
@@ -435,11 +246,11 @@ class OC_Util {
* @param string $application application id
* @param string|null $file filename
* @param bool $prepend prepend the Style to the beginning of the list
- * @return void
+ * @deprecated 32.0.0
*/
- public static function addVendorStyle($application, $file = null, $prepend = false) {
+ public static function addVendorStyle($application, $file = null, $prepend = false): void {
$path = OC_Util::generatePath($application, 'vendor', $file);
- self::addExternalResource($application, $prepend, $path, "style");
+ self::addExternalResource($application, $prepend, $path, 'style');
}
/**
@@ -449,10 +260,9 @@ class OC_Util {
* @param bool $prepend prepend the file to the beginning of the list
* @param string $path
* @param string $type (script or style)
- * @return void
*/
- private static function addExternalResource($application, $prepend, $path, $type = "script") {
- if ($type === "style") {
+ private static function addExternalResource($application, $prepend, $path, $type = 'script'): void {
+ if ($type === 'style') {
if (!in_array($path, self::$styles)) {
if ($prepend === true) {
array_unshift(self::$styles, $path);
@@ -460,14 +270,6 @@ class OC_Util {
self::$styles[] = $path;
}
}
- } elseif ($type === "script") {
- if (!in_array($path, self::$scripts)) {
- if ($prepend === true) {
- array_unshift(self::$scripts, $path);
- } else {
- self::$scripts [] = $path;
- }
- }
}
}
@@ -479,8 +281,9 @@ class OC_Util {
* @param array $attributes array of attributes for the element
* @param string $text the text content for the element
* @param bool $prepend prepend the header to the beginning of the list
+ * @deprecated 32.0.0 Use \OCP\Util::addHeader instead
*/
- public static function addHeader($tag, $attributes, $text = null, $prepend = false) {
+ public static function addHeader($tag, $attributes, $text = null, $prepend = false): void {
$header = [
'tag' => $tag,
'attributes' => $attributes,
@@ -496,7 +299,6 @@ class OC_Util {
/**
* check if the current server configuration is suitable for ownCloud
*
- * @param \OC\SystemConfig $config
* @return array arrays with error messages and hints
*/
public static function checkServer(\OC\SystemConfig $config) {
@@ -515,15 +317,7 @@ class OC_Util {
}
$webServerRestart = false;
- $setup = new \OC\Setup(
- $config,
- \OC::$server->get(IniGetWrapper::class),
- \OC::$server->getL10N('lib'),
- \OC::$server->get(\OCP\Defaults::class),
- \OC::$server->get(LoggerInterface::class),
- \OC::$server->getSecureRandom(),
- \OC::$server->get(\OC\Installer::class)
- );
+ $setup = \OCP\Server::get(\OC\Setup::class);
$urlGenerator = \OC::$server->getURLGenerator();
@@ -537,7 +331,7 @@ class OC_Util {
}
// Check if config folder is writable.
- if (!OC_Helper::isReadOnlyConfigEnabled()) {
+ if (!(bool)$config->getValue('config_is_read_only', false)) {
if (!is_writable(OC::$configDir) or !is_readable(OC::$configDir)) {
$errors[] = [
'error' => $l->t('Cannot write into "config" directory.'),
@@ -549,19 +343,6 @@ class OC_Util {
}
}
- // Check if there is a writable install folder.
- if ($config->getValue('appstoreenabled', true)) {
- if (OC_App::getInstallPath() === null
- || !is_writable(OC_App::getInstallPath())
- || !is_readable(OC_App::getInstallPath())
- ) {
- $errors[] = [
- 'error' => $l->t('Cannot write into "apps" directory.'),
- 'hint' => $l->t('This can usually be fixed by giving the web server write access to the apps directory'
- . ' or disabling the App Store in the config file.')
- ];
- }
- }
// Create root dir.
if ($config->getValue('installed', false)) {
if (!is_dir($CONFIG_DATADIRECTORY)) {
@@ -610,8 +391,7 @@ class OC_Util {
// defined = defined
// ini = ini_get
// If the dependency is not found the missing module name is shown to the EndUser
- // When adding new checks always verify that they pass on Travis as well
- // for ini settings, see https://github.com/owncloud/administration/blob/master/travis-ci/custom.ini
+ // When adding new checks always verify that they pass on CI as well
$dependencies = [
'classes' => [
'ZipArchive' => 'zip',
@@ -686,28 +466,14 @@ class OC_Util {
* TODO: Should probably be implemented in the above generic dependency
* check somehow in the long-term.
*/
- if ($iniWrapper->getBool('mbstring.func_overload') !== null &&
- $iniWrapper->getBool('mbstring.func_overload') === true) {
+ if ($iniWrapper->getBool('mbstring.func_overload') !== null
+ && $iniWrapper->getBool('mbstring.func_overload') === true) {
$errors[] = [
'error' => $l->t('<code>mbstring.func_overload</code> is set to <code>%s</code> instead of the expected value <code>0</code>.', [$iniWrapper->getString('mbstring.func_overload')]),
'hint' => $l->t('To fix this issue set <code>mbstring.func_overload</code> to <code>0</code> in your php.ini.')
];
}
- if (function_exists('xml_parser_create') &&
- LIBXML_LOADED_VERSION < 20700) {
- $version = LIBXML_LOADED_VERSION;
- $major = floor($version / 10000);
- $version -= ($major * 10000);
- $minor = floor($version / 100);
- $version -= ($minor * 100);
- $patch = $version;
- $errors[] = [
- 'error' => $l->t('libxml2 2.7.0 is at least required. Currently %s is installed.', [$major . '.' . $minor . '.' . $patch]),
- 'hint' => $l->t('To fix this issue update your libxml2 version and restart your web server.')
- ];
- }
-
if (!self::isAnnotationsWorking()) {
$errors[] = [
'error' => $l->t('PHP is apparently set up to strip inline doc blocks. This will make several core apps inaccessible.'),
@@ -731,8 +497,6 @@ class OC_Util {
}
}
- $errors = array_merge($errors, self::checkDatabaseVersion());
-
// Cache the result of this function
\OC::$server->getSession()->set('checkServer_succeeded', count($errors) == 0);
@@ -740,50 +504,14 @@ class OC_Util {
}
/**
- * Check the database version
- *
- * @return array errors array
- */
- public static function checkDatabaseVersion() {
- $l = \OC::$server->getL10N('lib');
- $errors = [];
- $dbType = \OC::$server->getSystemConfig()->getValue('dbtype', 'sqlite');
- if ($dbType === 'pgsql') {
- // check PostgreSQL version
- // TODO latest postgresql 8 released was 8 years ago, maybe remove the
- // check completely?
- try {
- /** @var IDBConnection $connection */
- $connection = \OC::$server->get(IDBConnection::class);
- $result = $connection->executeQuery('SHOW SERVER_VERSION');
- $data = $result->fetch();
- $result->closeCursor();
- if (isset($data['server_version'])) {
- $version = $data['server_version'];
- if (version_compare($version, '9.0.0', '<')) {
- $errors[] = [
- 'error' => $l->t('PostgreSQL >= 9 required.'),
- 'hint' => $l->t('Please upgrade your database version.')
- ];
- }
- }
- } catch (\Doctrine\DBAL\Exception $e) {
- $logger = \OC::$server->getLogger();
- $logger->warning('Error occurred while checking PostgreSQL version, assuming >= 9');
- $logger->logException($e);
- }
- }
- return $errors;
- }
-
- /**
* Check for correct file permissions of data directory
*
* @param string $dataDirectory
* @return array arrays with error messages and hints
+ * @internal
*/
public static function checkDataDirectoryPermissions($dataDirectory) {
- if (\OC::$server->getConfig()->getSystemValue('check_data_directory_permissions', true) === false) {
+ if (!\OC::$server->getConfig()->getSystemValueBool('check_data_directory_permissions', true)) {
return [];
}
@@ -795,8 +523,8 @@ class OC_Util {
if ($perms[2] !== '0') {
$l = \OC::$server->getL10N('lib');
return [[
- 'error' => $l->t('Your data directory is readable by other users.'),
- 'hint' => $l->t('Please change the permissions to 0770 so that the directory cannot be listed by other users.'),
+ 'error' => $l->t('Your data directory is readable by other people.'),
+ 'hint' => $l->t('Please change the permissions to 0770 so that the directory cannot be listed by other people.'),
]];
}
}
@@ -805,10 +533,11 @@ class OC_Util {
/**
* Check that the data directory exists and is valid by
- * checking the existence of the ".ocdata" file.
+ * checking the existence of the ".ncdata" file.
*
* @param string $dataDirectory data directory path
* @return array errors found
+ * @internal
*/
public static function checkDataDirectoryValidity($dataDirectory) {
$l = \OC::$server->getL10N('lib');
@@ -819,11 +548,11 @@ class OC_Util {
'hint' => $l->t('Check the value of "datadirectory" in your configuration.')
];
}
- if (!file_exists($dataDirectory . '/.ocdata')) {
+
+ if (!file_exists($dataDirectory . '/.ncdata')) {
$errors[] = [
'error' => $l->t('Your data directory is invalid.'),
- 'hint' => $l->t('Ensure there is a file called ".ocdata"' .
- ' in the root of the data directory.')
+ 'hint' => $l->t('Ensure there is a file called "%1$s" in the root of the data directory. It should have the content: "%2$s"', ['.ncdata', '# Nextcloud data directory']),
];
}
return $errors;
@@ -833,9 +562,9 @@ class OC_Util {
* Check if the user is logged in, redirects to home if not. With
* redirect URL parameter to the request URI.
*
- * @return void
+ * @deprecated 32.0.0
*/
- public static function checkLoggedIn() {
+ public static function checkLoggedIn(): void {
// Check if we are a user
if (!\OC::$server->getUserSession()->isLoggedIn()) {
header('Location: ' . \OC::$server->getURLGenerator()->linkToRoute(
@@ -848,7 +577,7 @@ class OC_Util {
exit();
}
// Redirect to 2FA challenge selection if 2FA challenge was not solved yet
- if (\OC::$server->getTwoFactorAuthManager()->needsSecondFactor(\OC::$server->getUserSession()->getUser())) {
+ if (\OC::$server->get(TwoFactorAuthManager::class)->needsSecondFactor(\OC::$server->getUserSession()->getUser())) {
header('Location: ' . \OC::$server->getURLGenerator()->linkToRoute('core.TwoFactorChallenge.selectChallenge'));
exit();
}
@@ -857,10 +586,10 @@ class OC_Util {
/**
* Check if the user is a admin, redirects to home if not
*
- * @return void
+ * @deprecated 32.0.0
*/
- public static function checkAdminUser() {
- OC_Util::checkLoggedIn();
+ public static function checkAdminUser(): void {
+ self::checkLoggedIn();
if (!OC_User::isAdminUser(OC_User::getUser())) {
header('Location: ' . \OCP\Util::linkToAbsolute('', 'index.php'));
exit();
@@ -873,7 +602,7 @@ class OC_Util {
* the apps visible for the current user
*
* @return string URL
- * @suppress PhanDeprecatedFunction
+ * @deprecated 32.0.0 use IURLGenerator's linkToDefaultPageUrl directly
*/
public static function getDefaultPageUrl() {
/** @var IURLGenerator $urlGenerator */
@@ -884,9 +613,9 @@ class OC_Util {
/**
* Redirect to the user default page
*
- * @return void
+ * @deprecated 32.0.0
*/
- public static function redirectToDefaultPage() {
+ public static function redirectToDefaultPage(): void {
$location = self::getDefaultPageUrl();
header('Location: ' . $location);
exit();
@@ -897,11 +626,11 @@ class OC_Util {
*
* @return string
*/
- public static function getInstanceId() {
+ public static function getInstanceId(): string {
$id = \OC::$server->getSystemConfig()->getValue('instanceid', null);
if (is_null($id)) {
// We need to guarantee at least one letter in instanceid so it can be used as the session_name
- $id = 'oc' . \OC::$server->getSecureRandom()->generate(10, \OCP\Security\ISecureRandom::CHAR_LOWER.\OCP\Security\ISecureRandom::CHAR_DIGITS);
+ $id = 'oc' . \OC::$server->get(ISecureRandom::class)->generate(10, \OCP\Security\ISecureRandom::CHAR_LOWER . \OCP\Security\ISecureRandom::CHAR_DIGITS);
\OC::$server->getSystemConfig()->setValue('instanceid', $id);
}
return $id;
@@ -914,11 +643,11 @@ class OC_Util {
* string or array of strings before displaying it on a web page.
*
* @param string|string[] $value
- * @return string|string[] an array of sanitized strings or a single sanitized string, depends on the input parameter.
+ * @return ($value is array ? string[] : string)
+ * @deprecated 32.0.0 use \OCP\Util::sanitizeHTML instead
*/
public static function sanitizeHTML($value) {
if (is_array($value)) {
- /** @var string[] $value */
$value = array_map(function ($value) {
return self::sanitizeHTML($value);
}, $value);
@@ -938,6 +667,7 @@ class OC_Util {
*
* @param string $component part of URI to encode
* @return string
+ * @deprecated 32.0.0 use \OCP\Util::encodePath instead
*/
public static function encodePath($component) {
$encoded = rawurlencode($component);
@@ -945,86 +675,6 @@ class OC_Util {
return $encoded;
}
-
- public function createHtaccessTestFile(\OCP\IConfig $config) {
- // php dev server does not support htaccess
- if (php_sapi_name() === 'cli-server') {
- return false;
- }
-
- // testdata
- $fileName = '/htaccesstest.txt';
- $testContent = 'This is used for testing whether htaccess is properly enabled to disallow access from the outside. This file can be safely removed.';
-
- // creating a test file
- $testFile = $config->getSystemValue('datadirectory', OC::$SERVERROOT . '/data') . '/' . $fileName;
-
- if (file_exists($testFile)) {// already running this test, possible recursive call
- return false;
- }
-
- $fp = @fopen($testFile, 'w');
- if (!$fp) {
- throw new \OCP\HintException('Can\'t create test file to check for working .htaccess file.',
- 'Make sure it is possible for the web server to write to ' . $testFile);
- }
- fwrite($fp, $testContent);
- fclose($fp);
-
- return $testContent;
- }
-
- /**
- * Check if the .htaccess file is working
- *
- * @param \OCP\IConfig $config
- * @return bool
- * @throws Exception
- * @throws \OCP\HintException If the test file can't get written.
- */
- public function isHtaccessWorking(\OCP\IConfig $config) {
- if (\OC::$CLI || !$config->getSystemValue('check_for_working_htaccess', true)) {
- return true;
- }
-
- $testContent = $this->createHtaccessTestFile($config);
- if ($testContent === false) {
- return false;
- }
-
- $fileName = '/htaccesstest.txt';
- $testFile = $config->getSystemValue('datadirectory', OC::$SERVERROOT . '/data') . '/' . $fileName;
-
- // accessing the file via http
- $url = \OC::$server->getURLGenerator()->getAbsoluteURL(OC::$WEBROOT . '/data' . $fileName);
- try {
- $content = \OC::$server->getHTTPClientService()->newClient()->get($url)->getBody();
- } catch (\Exception $e) {
- $content = false;
- }
-
- if (strpos($url, 'https:') === 0) {
- $url = 'http:' . substr($url, 6);
- } else {
- $url = 'https:' . substr($url, 5);
- }
-
- try {
- $fallbackContent = \OC::$server->getHTTPClientService()->newClient()->get($url)->getBody();
- } catch (\Exception $e) {
- $fallbackContent = false;
- }
-
- // cleanup
- @unlink($testFile);
-
- /*
- * If the content is not equal to test content our .htaccess
- * is working as required
- */
- return $content !== $testContent && $fallbackContent !== $testContent;
- }
-
/**
* Check if current locale is non-UTF8
*
@@ -1032,11 +682,11 @@ class OC_Util {
*/
private static function isNonUTF8Locale() {
if (function_exists('escapeshellcmd')) {
- return '' === escapeshellcmd('§');
+ return escapeshellcmd('§') === '';
} elseif (function_exists('escapeshellarg')) {
- return '\'\'' === escapeshellarg('§');
+ return escapeshellarg('§') === '\'\'';
} else {
- return 0 === preg_match('/utf-?8/i', setlocale(LC_CTYPE, 0));
+ return preg_match('/utf-?8/i', setlocale(LC_CTYPE, 0)) === 0;
}
}
@@ -1044,9 +694,9 @@ class OC_Util {
* Check if the setlocale call does not work. This can happen if the right
* local packages are not available on the server.
*
- * @return bool
+ * @internal
*/
- public static function isSetLocaleWorking() {
+ public static function isSetLocaleWorking(): bool {
if (self::isNonUTF8Locale()) {
// Borrowed from \Patchwork\Utf8\Bootup::initLocale
setlocale(LC_ALL, 'C.UTF-8', 'C');
@@ -1064,10 +714,15 @@ class OC_Util {
/**
* Check if it's possible to get the inline annotations
*
- * @return bool
+ * @internal
*/
- public static function isAnnotationsWorking() {
- $reflection = new \ReflectionMethod(__METHOD__);
+ public static function isAnnotationsWorking(): bool {
+ if (PHP_VERSION_ID >= 80300) {
+ /** @psalm-suppress UndefinedMethod */
+ $reflection = \ReflectionMethod::createFromMethodName(__METHOD__);
+ } else {
+ $reflection = new \ReflectionMethod(__METHOD__);
+ }
$docs = $reflection->getDocComment();
return (is_string($docs) && strlen($docs) > 50);
@@ -1076,9 +731,9 @@ class OC_Util {
/**
* Check if the PHP module fileinfo is loaded.
*
- * @return bool
+ * @internal
*/
- public static function fileInfoLoaded() {
+ public static function fileInfoLoaded(): bool {
return function_exists('finfo_open');
}
@@ -1109,7 +764,7 @@ class OC_Util {
* @return string the theme
*/
public static function getTheme() {
- $theme = \OC::$server->getSystemConfig()->getValue("theme", '');
+ $theme = \OC::$server->getSystemConfig()->getValue('theme', '');
if ($theme === '') {
if (is_dir(OC::$SERVERROOT . '/themes/default')) {
@@ -1124,16 +779,16 @@ class OC_Util {
* Normalize a unicode string
*
* @param string $value a not normalized string
- * @return bool|string
+ * @return string The normalized string or the input if the normalization failed
*/
- public static function normalizeUnicode($value) {
+ public static function normalizeUnicode(string $value): string {
if (Normalizer::isNormalized($value)) {
return $value;
}
$normalizedValue = Normalizer::normalize($value);
- if ($normalizedValue === null || $normalizedValue === false) {
- \OC::$server->getLogger()->warning('normalizing failed for "' . $value . '"', ['app' => 'core']);
+ if ($normalizedValue === false) {
+ \OCP\Server::get(LoggerInterface::class)->warning('normalizing failed for "' . $value . '"', ['app' => 'core']);
return $value;
}
@@ -1141,49 +796,6 @@ class OC_Util {
}
/**
- * A human readable string is generated based on version and build number
- *
- * @return string
- */
- public static function getHumanVersion() {
- $version = OC_Util::getVersionString();
- $build = OC_Util::getBuild();
- if (!empty($build) and OC_Util::getChannel() === 'daily') {
- $version .= ' Build:' . $build;
- }
- return $version;
- }
-
- /**
- * Returns whether the given file name is valid
- *
- * @param string $file file name to check
- * @return bool true if the file name is valid, false otherwise
- * @deprecated use \OC\Files\View::verifyPath()
- */
- public static function isValidFileName($file) {
- $trimmed = trim($file);
- if ($trimmed === '') {
- return false;
- }
- if (\OC\Files\Filesystem::isIgnoredDir($trimmed)) {
- return false;
- }
-
- // detect part files
- if (preg_match('/' . \OCP\Files\FileInfo::BLACKLIST_FILES_REGEX . '/', $trimmed) !== 0) {
- return false;
- }
-
- foreach (str_split($trimmed) as $char) {
- if (strpos(\OCP\Constants::FILENAME_INVALID_CHARS, $char) !== false) {
- return false;
- }
- }
- return true;
- }
-
- /**
* Check whether the instance needs to perform an upgrade,
* either when the core version is higher or any app requires
* an upgrade.
@@ -1191,6 +803,7 @@ class OC_Util {
* @param \OC\SystemConfig $config
* @return bool whether the core or any app needs an upgrade
* @throws \OCP\HintException When the upgrade from the given version is not allowed
+ * @deprecated 32.0.0 Use \OCP\Util::needUpgrade instead
*/
public static function needUpgrade(\OC\SystemConfig $config) {
if ($config->getValue('installed', false)) {
diff --git a/lib/private/legacy/template/functions.php b/lib/private/legacy/template/functions.php
deleted file mode 100644
index 56c488d5abe..00000000000
--- a/lib/private/legacy/template/functions.php
+++ /dev/null
@@ -1,339 +0,0 @@
-<?php
-
-use OCP\Util;
-
-/**
- * @copyright Copyright (c) 2016, ownCloud, Inc.
- *
- * @author Bart Visscher <bartv@thisnet.nl>
- * @author Bernhard Posselt <dev@bernhard-posselt.com>
- * @author Christoph Wurst <christoph@winzerhof-wurst.at>
- * @author Joas Schilling <coding@schilljs.com>
- * @author Jörn Friedrich Dreyer <jfd@butonic.de>
- * @author Julius Härtl <jus@bitgrid.net>
- * @author Lukas Reschke <lukas@statuscode.ch>
- * @author Michael Letzgus <www@chronos.michael-letzgus.de>
- * @author Morris Jobke <hey@morrisjobke.de>
- * @author Robin McCorkell <robin@mccorkell.me.uk>
- * @author Roeland Jago Douma <roeland@famdouma.nl>
- * @author Thomas Müller <thomas.mueller@tmit.eu>
- * @author Vincent Petry <vincent@nextcloud.com>
- *
- * @license AGPL-3.0
- *
- * This code is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License, version 3,
- * as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License, version 3,
- * along with this program. If not, see <http://www.gnu.org/licenses/>
- *
- */
-function p($string) {
- print(\OCP\Util::sanitizeHTML($string));
-}
-
-
-/**
- * Prints a <link> tag for loading css
- * @param string $href the source URL, ignored when empty
- * @param string $opts, additional optional options
- */
-function emit_css_tag($href, $opts = '') {
- $s = '<link rel="stylesheet"';
- if (!empty($href)) {
- $s .= ' href="' . $href .'"';
- }
- if (!empty($opts)) {
- $s .= ' '.$opts;
- }
- print_unescaped($s.">\n");
-}
-
-/**
- * Prints all tags for CSS loading
- * @param array $obj all the script information from template
- */
-function emit_css_loading_tags($obj) {
- foreach ($obj['cssfiles'] as $css) {
- emit_css_tag($css);
- }
- foreach ($obj['printcssfiles'] as $css) {
- emit_css_tag($css, 'media="print"');
- }
-}
-
-/**
- * Prints a <script> tag with nonce and defer depending on config
- * @param string $src the source URL, ignored when empty
- * @param string $script_content the inline script content, ignored when empty
- */
-function emit_script_tag($src, $script_content = '') {
- $defer_str = ' defer';
- $s = '<script nonce="' . \OC::$server->getContentSecurityPolicyNonceManager()->getNonce() . '"';
- if (!empty($src)) {
- // emit script tag for deferred loading from $src
- $s .= $defer_str.' src="' . $src .'">';
- } elseif (!empty($script_content)) {
- // emit script tag for inline script from $script_content without defer (see MDN)
- $s .= ">\n".$script_content."\n";
- } else {
- // no $src nor $src_content, really useless empty tag
- $s .= '>';
- }
- $s .= '</script>';
- print_unescaped($s."\n");
-}
-
-/**
- * Print all <script> tags for loading JS
- * @param array $obj all the script information from template
- */
-function emit_script_loading_tags($obj) {
- foreach ($obj['jsfiles'] as $jsfile) {
- emit_script_tag($jsfile, '');
- }
- if (!empty($obj['inline_ocjs'])) {
- emit_script_tag('', $obj['inline_ocjs']);
- }
-}
-
-/**
- * Prints an unsanitized string - usage of this function may result into XSS.
- * Consider using p() instead.
- * @param string|array $string the string which will be printed as it is
- */
-function print_unescaped($string) {
- print($string);
-}
-
-/**
- * Shortcut for adding scripts to a page
- * All scripts are forced to be loaded after core since
- * they are coming from a template registration.
- * Please consider moving them into the relevant controller
- *
- * @deprecated 24.0.0 - Use \OCP\Util::addScript
- *
- * @param string $app the appname
- * @param string|string[] $file the filename,
- * if an array is given it will add all scripts
- */
-function script($app, $file = null) {
- if (is_array($file)) {
- foreach ($file as $script) {
- Util::addScript($app, $script, 'core');
- }
- } else {
- Util::addScript($app, $file, 'core');
- }
-}
-
-/**
- * Shortcut for adding vendor scripts to a page
- * @param string $app the appname
- * @param string|string[] $file the filename,
- * if an array is given it will add all scripts
- */
-function vendor_script($app, $file = null) {
- if (is_array($file)) {
- foreach ($file as $f) {
- OC_Util::addVendorScript($app, $f);
- }
- } else {
- OC_Util::addVendorScript($app, $file);
- }
-}
-
-/**
- * Shortcut for adding styles to a page
- * @param string $app the appname
- * @param string|string[] $file the filename,
- * if an array is given it will add all styles
- */
-function style($app, $file = null) {
- if (is_array($file)) {
- foreach ($file as $f) {
- OC_Util::addStyle($app, $f);
- }
- } else {
- OC_Util::addStyle($app, $file);
- }
-}
-
-/**
- * Shortcut for adding vendor styles to a page
- * @param string $app the appname
- * @param string|string[] $file the filename,
- * if an array is given it will add all styles
- */
-function vendor_style($app, $file = null) {
- if (is_array($file)) {
- foreach ($file as $f) {
- OC_Util::addVendorStyle($app, $f);
- }
- } else {
- OC_Util::addVendorStyle($app, $file);
- }
-}
-
-/**
- * Shortcut for adding translations to a page
- * @param string $app the appname
- * if an array is given it will add all styles
- */
-function translation($app) {
- OC_Util::addTranslations($app);
-}
-
-/**
- * Shortcut for HTML imports
- * @param string $app the appname
- * @param string|string[] $file the path relative to the app's component folder,
- * if an array is given it will add all components
- */
-function component($app, $file) {
- if (is_array($file)) {
- foreach ($file as $f) {
- $url = link_to($app, 'component/' . $f . '.html');
- OC_Util::addHeader('link', ['rel' => 'import', 'href' => $url]);
- }
- } else {
- $url = link_to($app, 'component/' . $file . '.html');
- OC_Util::addHeader('link', ['rel' => 'import', 'href' => $url]);
- }
-}
-
-/**
- * make \OCP\IURLGenerator::linkTo available as a simple function
- * @param string $app app
- * @param string $file file
- * @param array $args array with param=>value, will be appended to the returned url
- * @return string link to the file
- *
- * For further information have a look at \OCP\IURLGenerator::linkTo
- */
-function link_to($app, $file, $args = []) {
- return \OC::$server->getURLGenerator()->linkTo($app, $file, $args);
-}
-
-/**
- * @param $key
- * @return string url to the online documentation
- */
-function link_to_docs($key) {
- return \OC::$server->getURLGenerator()->linkToDocs($key);
-}
-
-/**
- * make \OCP\IURLGenerator::imagePath available as a simple function
- * @param string $app app
- * @param string $image image
- * @return string link to the image
- *
- * For further information have a look at \OCP\IURLGenerator::imagePath
- */
-function image_path($app, $image) {
- return \OC::$server->getURLGenerator()->imagePath($app, $image);
-}
-
-/**
- * make OC_Helper::mimetypeIcon available as a simple function
- * @param string $mimetype mimetype
- * @return string link to the image
- */
-function mimetype_icon($mimetype) {
- return \OC::$server->getMimeTypeDetector()->mimeTypeIcon($mimetype);
-}
-
-/**
- * make preview_icon available as a simple function
- * Returns the path to the preview of the image.
- * @param string $path path of file
- * @return string link to the preview
- */
-function preview_icon($path) {
- return \OC::$server->getURLGenerator()->linkToRoute('core.Preview.getPreview', ['x' => 32, 'y' => 32, 'file' => $path]);
-}
-
-/**
- * @param string $path
- * @param string $token
- * @return string
- */
-function publicPreview_icon($path, $token) {
- return \OC::$server->getURLGenerator()->linkToRoute('files_sharing.PublicPreview.getPreview', ['x' => 32, 'y' => 32, 'file' => $path, 'token' => $token]);
-}
-
-/**
- * make OC_Helper::humanFileSize available as a simple function
- * @param int $bytes size in bytes
- * @return string size as string
- *
- * For further information have a look at OC_Helper::humanFileSize
- */
-function human_file_size($bytes) {
- return OC_Helper::humanFileSize($bytes);
-}
-
-/**
- * Strips the timestamp of its time value
- * @param int $timestamp UNIX timestamp to strip
- * @return int timestamp without time value
- */
-function strip_time($timestamp) {
- $date = new \DateTime("@{$timestamp}");
- $date->setTime(0, 0, 0);
- return (int)$date->format('U');
-}
-
-/**
- * Formats timestamp relatively to the current time using
- * a human-friendly format like "x minutes ago" or "yesterday"
- * @param int $timestamp timestamp to format
- * @param int|null $fromTime timestamp to compare from, defaults to current time
- * @param bool|null $dateOnly whether to strip time information
- * @return string timestamp
- */
-function relative_modified_date($timestamp, $fromTime = null, $dateOnly = false) {
- /** @var \OC\DateTimeFormatter $formatter */
- $formatter = \OC::$server->query('DateTimeFormatter');
-
- if ($dateOnly) {
- return $formatter->formatDateSpan($timestamp, $fromTime);
- }
- return $formatter->formatTimeSpan($timestamp, $fromTime);
-}
-
-function html_select_options($options, $selected, $params = []) {
- if (!is_array($selected)) {
- $selected = [$selected];
- }
- if (isset($params['combine']) && $params['combine']) {
- $options = array_combine($options, $options);
- }
- $value_name = $label_name = false;
- if (isset($params['value'])) {
- $value_name = $params['value'];
- }
- if (isset($params['label'])) {
- $label_name = $params['label'];
- }
- $html = '';
- foreach ($options as $value => $label) {
- if ($value_name && is_array($label)) {
- $value = $label[$value_name];
- }
- if ($label_name && is_array($label)) {
- $label = $label[$label_name];
- }
- $select = in_array($value, $selected) ? ' selected="selected"' : '';
- $html .= '<option value="' . \OCP\Util::sanitizeHTML($value) . '"' . $select . '>' . \OCP\Util::sanitizeHTML($label) . '</option>'."\n";
- }
- return $html;
-}