Merge remote-tracking branch 'upstream/develop' into server-detection

This commit is contained in:
Michael 2022-07-16 12:44:21 +00:00
commit 8b7cb5d9ef
328 changed files with 13242 additions and 10211 deletions

8
.gitignore vendored
View File

@ -90,3 +90,11 @@ venv/
#ignore avatar picture cache path
/avatar
#Ignore autotest results
autotest-results.xml
#ignore phpunit result cache
tests/.phpunit.result.cache
#ignore .php_cs (local copy)
.php_cs

View File

@ -9,7 +9,10 @@ depends_on:
- database_checks
- messages.po_check
platform: releaser/release # This prevents executing this pipeline at other servers than ci.friendi.ca
# This prevents executing this pipeline at other servers than ci.friendi.ca
labels:
location: friendica
type: releaser
skip_clone: true

View File

@ -7,7 +7,10 @@ depends_on:
- phpunit
- code_standards_check
platform: releaser/release # This prevents executing this pipeline at other servers than ci.friendi.ca
# This prevents executing this pipeline at other servers than ci.friendi.ca
labels:
location: friendica
type: releaser
skip_clone: true

Binary file not shown.

View File

@ -26,7 +26,7 @@
* This script was taken from http://php.net/manual/en/function.pcntl-fork.php
*/
if (php_sapi_name() !== 'cli') {
header($_SERVER["SERVER_PROTOCOL"] . ' 403 Forbidden');
header($_SERVER['SERVER_PROTOCOL'] . ' 403 Forbidden');
exit();
}
@ -45,13 +45,13 @@ $longopts = ['foreground'];
$options = getopt($shortopts, $longopts);
// Ensure that daemon.php is executed from the base path of the installation
if (!file_exists("boot.php") && (sizeof($_SERVER["argv"]) != 0)) {
$directory = dirname($_SERVER["argv"][0]);
if (!file_exists('boot.php') && (sizeof($_SERVER['argv']) != 0)) {
$directory = dirname($_SERVER['argv'][0]);
if (substr($directory, 0, 1) != "/") {
$directory = $_SERVER["PWD"] . "/" . $directory;
if (substr($directory, 0, 1) != '/') {
$directory = $_SERVER['PWD'] . '/' . $directory;
}
$directory = realpath($directory . "/..");
$directory = realpath($directory . '/..');
chdir($directory);
}
@ -86,16 +86,16 @@ TXT
$pidfile = DI::config()->get('system', 'pidfile');
if (in_array("start", $_SERVER["argv"])) {
$mode = "start";
if (in_array('start', $_SERVER['argv'])) {
$mode = 'start';
}
if (in_array("stop", $_SERVER["argv"])) {
$mode = "stop";
if (in_array('stop', $_SERVER['argv'])) {
$mode = 'stop';
}
if (in_array("status", $_SERVER["argv"])) {
$mode = "status";
if (in_array('status', $_SERVER['argv'])) {
$mode = 'status';
}
$foreground = array_key_exists('f', $options) || array_key_exists('foreground', $options);
@ -104,7 +104,7 @@ if (!isset($mode)) {
die("Please use either 'start', 'stop' or 'status'.\n");
}
if (empty($_SERVER["argv"][0])) {
if (empty($_SERVER['argv'][0])) {
die("Unexpected script behaviour. This message should never occur.\n");
}
@ -114,12 +114,12 @@ if (is_readable($pidfile)) {
$pid = intval(file_get_contents($pidfile));
}
if (empty($pid) && in_array($mode, ["stop", "status"])) {
if (empty($pid) && in_array($mode, ['stop', 'status'])) {
DI::config()->set('system', 'worker_daemon_mode', false);
die("Pidfile wasn't found. Is the daemon running?\n");
}
if ($mode == "status") {
if ($mode == 'status') {
if (posix_kill($pid, 0)) {
die("Daemon process $pid is running.\n");
}
@ -130,12 +130,12 @@ if ($mode == "status") {
die("Daemon process $pid isn't running.\n");
}
if ($mode == "stop") {
if ($mode == 'stop') {
posix_kill($pid, SIGTERM);
unlink($pidfile);
Logger::notice("Worker daemon process was killed", ["pid" => $pid]);
Logger::notice('Worker daemon process was killed', ['pid' => $pid]);
DI::config()->set('system', 'worker_daemon_mode', false);
die("Worker daemon process $pid was killed.\n");
@ -145,7 +145,7 @@ if (!empty($pid) && posix_kill($pid, 0)) {
die("Daemon process $pid is already running.\n");
}
Logger::notice('Starting worker daemon.', ["pid" => $pid]);
Logger::notice('Starting worker daemon.', ['pid' => $pid]);
if (!$foreground) {
echo "Starting worker daemon.\n";
@ -194,7 +194,7 @@ $last_cron = 0;
// Now running as a daemon.
while (true) {
if (!$do_cron && ($last_cron + $wait_interval) < time()) {
Logger::info('Forcing cron worker call.', ["pid" => $pid]);
Logger::info('Forcing cron worker call.', ['pid' => $pid]);
$do_cron = true;
}
@ -214,7 +214,7 @@ while (true) {
}
$start = time();
Logger::info("Sleeping", ["pid" => $pid, 'until' => gmdate(DateTimeFormat::MYSQL, $start + $wait_interval)]);
Logger::info('Sleeping', ['pid' => $pid, 'until' => gmdate(DateTimeFormat::MYSQL, $start + $wait_interval)]);
do {
$seconds = (time() - $start);
@ -236,10 +236,10 @@ while (true) {
if ($timeout) {
$do_cron = true;
Logger::info("Woke up after $wait_interval seconds.", ["pid" => $pid, 'sleep' => $wait_interval]);
Logger::info('Woke up after $wait_interval seconds.', ['pid' => $pid, 'sleep' => $wait_interval]);
} else {
$do_cron = false;
Logger::info("Worker jobs are calling to be forked.", ["pid" => $pid]);
Logger::info('Worker jobs are calling to be forked.', ['pid' => $pid]);
}
}

View File

@ -15,33 +15,34 @@
# - TEST_SELECTION= ... Specify which tests are used to run (based on the test-labeling)
# - XDEBUG_CONFIG= ... Set some XDEBUG specific environment settings for development
DATABASENAME=${MYSQL_DATABASE:-test}
DATABASEUSER=${MYSQL_USERNAME:-friendica}
DATABASEHOST=${MYSQL_HOST:-localhost}
BASEDIR=$PWD
DATABASE_NAME=${FRIENDICA_MYSQL_DATABASE:-test}
DATABASE_USER=${FRIENDICA_MYSQL_USERNAME:-friendica}
DATABASE_HOST=${FRIENDICA_MYSQL_HOST:-localhost}
DATABASE_PASSWORD=${FRIENDICA_MYSQL_PASSWORD:-friendica}
BASEDIR=${PWD}
DBCONFIGS="mysql mariadb"
TESTS="REDIS MEMCACHE MEMCACHED APCU NODB"
export MYSQL_DATABASE="$DATABASENAME"
export MYSQL_USERNAME="$DATABASEUSER"
export MYSQL_PASSWORD="friendica"
export MYSQL_DATABASE="${DATABASE_NAME}"
export MYSQL_USERNAME="${DATABASE_USER}"
export MYSQL_PASSWORD="${DATABASE_PASSWORD}"
if [ -z "$PHP_EXE" ]; then
if [ -z "${PHP_EXE}" ]; then
PHP_EXE=php
fi
PHP=$(which "$PHP_EXE")
PHP=$(which "${PHP_EXE}")
# Use the Friendica internal composer
COMPOSER="$BASEDIR/bin/composer.phar"
COMPOSER="${BASEDIR}/bin/composer.phar"
set -e
_XDEBUG_CONFIG=$XDEBUG_CONFIG
_XDEBUG_CONFIG=${XDEBUG_CONFIG}
unset XDEBUG_CONFIG
function show_syntax() {
echo -e "Syntax: ./autotest.sh [dbconfigname] [testfile]\n" >&2
echo -e "\t\"dbconfigname\" can be one of: $DBCONFIGS" >&2
echo -e "\t\"dbconfigname\" can be one of: ${DBCONFIGS}" >&2
echo -e "\t\"testfile\" is the name of a test file, for example lib/template.php" >&2
echo -e "\nDatabase environment variables:\n" >&2
echo -e "\t\"MYSQL_HOST\" Mysql Hostname (Default: localhost)" >&2
@ -57,22 +58,22 @@ function show_syntax() {
echo -e "\nIf no arguments are specified, all tests will be run with all database configs" >&2
}
if [ -x "$PHP" ]; then
echo "Using PHP executable $PHP"
if [ -x "${PHP}" ]; then
echo "Using PHP executable ${PHP}"
else
echo "Could not find PHP executable $PHP_EXE" >&2
echo "Could not find PHP executable ${PHP_EXE}" >&2
exit 3
fi
echo "Installing depdendencies"
$PHP "$COMPOSER" install
${PHP} "$COMPOSER" install
PHPUNIT="$BASEDIR/vendor/bin/phpunit"
PHPUNIT="${BASEDIR}/vendor/bin/phpunit"
if [ -x "$PHPUNIT" ]; then
echo "Using PHPUnit executable $PHPUNIT"
if [ -x "${PHPUNIT}" ]; then
echo "Using PHPUnit executable ${PHPUNIT}"
else
echo "Could not find PHPUnit executable after composer $PHPUNIT" >&2
echo "Could not find PHPUnit executable after composer ${PHPUNIT}" >&2
exit 3
fi
@ -83,8 +84,8 @@ fi
if [ "$1" ]; then
FOUND=0
for DBCONFIG in $DBCONFIGS; do
if [ "$1" = "$DBCONFIG" ]; then
for DBCONFIG in ${DBCONFIGS}; do
if [ "$1" = "${DBCONFIG}" ]; then
FOUND=1
break
fi
@ -103,13 +104,13 @@ fi
function cleanup_config() {
if [ -n "$DOCKER_CONTAINER_ID" ]; then
echo "Kill the docker $DOCKER_CONTAINER_ID"
docker stop "$DOCKER_CONTAINER_ID"
docker rm -f "$DOCKER_CONTAINER_ID"
if [ -n "${DOCKER_CONTAINER_ID}" ]; then
echo "Kill the docker ${DOCKER_CONTAINER_ID}"
docker stop "${DOCKER_CONTAINER_ID}"
docker rm -f "${DOCKER_CONTAINER_ID}"
fi
cd "$BASEDIR"
cd "${BASEDIR}"
# Restore existing config
if [ -f config/local.config-autotest-backup.php ]; then
@ -122,77 +123,77 @@ trap cleanup_config EXIT
function execute_tests() {
DB=$1
echo "Setup environment for $DB testing ..."
echo "Setup environment for ${DB} testing ..."
# back to root folder
cd "$BASEDIR"
cd "${BASEDIR}"
# backup current config
if [ -f config/local.config.php ]; then
mv config/local.config.php config/local.config-autotest-backup.php
fi
if [ -z "$NOINSTALL" ]; then
if [ -z "${NOINSTALL}" ]; then
#drop database
if [ "$DB" == "mysql" ]; then
if [ -n "$USEDOCKER" ]; then
if [ "${DB}" == "mysql" ]; then
if [ -n "${USEDOCKER}" ]; then
echo "Fire up the mysql docker"
DOCKER_CONTAINER_ID=$(docker run \
-e MYSQL_ROOT_PASSWORD=friendica \
-e MYSQL_USER="$DATABASEUSER" \
-e MYSQL_USER="${DATABASE_USER}" \
-e MYSQL_PASSWORD=friendica \
-e MYSQL_DATABASE="$DATABASENAME" \
-e MYSQL_DATABASE="${DATABASE_NAME}" \
-d mysql)
DATABASEHOST=$(docker inspect --format="{{.NetworkSettings.IPAddress}}" "$DOCKER_CONTAINER_ID")
DATABASE_HOST=$(docker inspect --format="{{.NetworkSettings.IPAddress}}" "${DOCKER_CONTAINER_ID}")
else
if [ -z "$DRONE" ]; then # no need to drop the DB when we are on CI
if [ -z "${DRONE}" ]; then # no need to drop the DB when we are on CI
if [ "mysql" != "$(mysql --version | grep -o mysql)" ]; then
echo "Your mysql binary is not provided by mysql"
echo "To use the docker container set the USEDOCKER environment variable"
exit 3
fi
mysql -u "$DATABASEUSER" -pfriendica -e "DROP DATABASE IF EXISTS $DATABASENAME" -h $DATABASEHOST || true
mysql -u "$DATABASEUSER" -pfriendica -e "CREATE DATABASE $DATABASENAME DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci" -h $DATABASEHOST
mysql -u "${DATABASE_USER}" -pfriendica -e "DROP DATABASE IF EXISTS ${DATABASE_NAME}" -h ${DATABASE_HOST} || true
mysql -u "${DATABASE_USER}" -pfriendica -e "CREATE DATABASE ${DATABASE_NAME} DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci" -h ${DATABASE_HOST}
else
DATABASEHOST=mysql
DATABASE_HOST=mysql
fi
fi
echo "Waiting for MySQL $DATABASEHOST initialization..."
if ! bin/wait-for-connection $DATABASEHOST 3306 300; then
echo "Waiting for MySQL ${DATABASE_HOST} initialization..."
if ! bin/wait-for-connection ${DATABASE_HOST} 3306 300; then
echo "[ERROR] Waited 300 seconds, no response" >&2
exit 1
fi
echo "MySQL is up."
fi
if [ "$DB" == "mariadb" ]; then
if [ -n "$USEDOCKER" ]; then
if [ "${DB}" == "mariadb" ]; then
if [ -n "${USEDOCKER}" ]; then
echo "Fire up the mariadb docker"
DOCKER_CONTAINER_ID=$(docker run \
-e MYSQL_ROOT_PASSWORD=friendica \
-e MYSQL_USER="$DATABASEUSER" \
-e MYSQL_USER="${DATABASE_USER}" \
-e MYSQL_PASSWORD=friendica \
-e MYSQL_DATABASE="$DATABASENAME" \
-e MYSQL_DATABASE="${DATABASE_NAME}" \
-d mariadb)
DATABASEHOST=$(docker inspect --format="{{.NetworkSettings.IPAddress}}" "$DOCKER_CONTAINER_ID")
DATABASE_HOST=$(docker inspect --format="{{.NetworkSettings.IPAddress}}" "${DOCKER_CONTAINER_ID}")
else
if [ -z "$DRONE" ]; then # no need to drop the DB when we are on CI
if [ -z "${DRONE}" ]; then # no need to drop the DB when we are on CI
if [ "MariaDB" != "$(mysql --version | grep -o MariaDB)" ]; then
echo "Your mysql binary is not provided by mysql"
echo "To use the docker container set the USEDOCKER environment variable"
exit 3
fi
mysql -u "$DATABASEUSER" -pfriendica -e "DROP DATABASE IF EXISTS $DATABASENAME" -h $DATABASEHOST || true
mysql -u "$DATABASEUSER" -pfriendica -e "CREATE DATABASE $DATABASENAME DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci" -h $DATABASEHOST
mysql -u "${DATABASE_USER}" -pfriendica -e "DROP DATABASE IF EXISTS ${DATABASE_NAME}" -h ${DATABASE_HOST} || true
mysql -u "${DATABASE_USER}" -pfriendica -e "CREATE DATABASE ${DATABASE_NAME} DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci" -h ${DATABASE_HOST}
else
DATABASEHOST=mariadb
DATABASE_HOST=mariadb
fi
fi
echo "Waiting for MariaDB $DATABASEHOST initialization..."
if ! bin/wait-for-connection $DATABASEHOST 3306 300; then
echo "Waiting for MariaDB ${DATABASE_HOST} initialization..."
if ! bin/wait-for-connection ${DATABASE_HOST} 3306 300; then
echo "[ERROR] Waited 300 seconds, no response" >&2
exit 1
fi
@ -200,28 +201,28 @@ function execute_tests() {
echo "MariaDB is up."
fi
if [ -n "$USEDOCKER" ]; then
if [ -n "${USEDOCKER}" ]; then
echo "Initialize database..."
docker exec $DOCKER_CONTAINER_ID mysql -u root -pfriendica -e 'CREATE DATABASE IF NOT EXISTS $DATABASENAME;'
docker exec ${DOCKER_CONTAINER_ID} mysql -u root -pfriendica -e "CREATE DATABASE IF NOT EXISTS ${DATABASE_NAME};"
fi
export MYSQL_HOST="$DATABASEHOST"
export MYSQL_HOST="${DATABASE_HOST}"
#call installer
echo "Installing Friendica..."
"$PHP" ./bin/console.php autoinstall --dbuser="$DATABASEUSER" --dbpass=friendica --dbdata="$DATABASENAME" --dbhost="$DATABASEHOST" --url=https://friendica.local --admin=admin@friendica.local
"${PHP}" ./bin/console.php autoinstall --dbuser="${DATABASE_USER}" --dbpass=friendica --dbdata="${DATABASE_NAME}" --dbhost="${DATABASE_HOST}" --url=https://friendica.local --admin=admin@friendica.local
fi
#test execution
echo "Testing..."
rm -fr "coverage-html"
mkdir "coverage-html"
if [[ "$_XDEBUG_CONFIG" ]]; then
export XDEBUG_CONFIG=$_XDEBUG_CONFIG
if [[ "${_XDEBUG_CONFIG}" ]]; then
export XDEBUG_CONFIG=${_XDEBUG_CONFIG}
fi
COVER=''
if [ -z "$NOCOVERAGE" ]; then
if [ -z "${NOCOVERAGE}" ]; then
COVER="--coverage-clover tests/autotest-clover.xml"
else
echo "No coverage"
@ -229,51 +230,51 @@ function execute_tests() {
# per default, there is no cache installed
GROUP='--exclude-group REDIS,MEMCACHE,MEMCACHED,APCU'
if [ "$TEST_SELECTION" == "REDIS" ]; then
if [ "${TEST_SELECTION}" == "REDIS" ]; then
GROUP="--group REDIS"
fi
if [ "$TEST_SELECTION" == "MEMCACHE" ]; then
if [ "${TEST_SELECTION}" == "MEMCACHE" ]; then
GROUP="--group MEMCACHE"
fi
if [ "$TEST_SELECTION" == "MEMCACHED" ]; then
if [ "${TEST_SELECTION}" == "MEMCACHED" ]; then
GROUP="--group MEMCACHED"
fi
if [ "$TEST_SELECTION" == "APCU" ]; then
if [ "${TEST_SELECTION}" == "APCU" ]; then
GROUP="--group APCU"
fi
if [ "$TEST_SELECTION" == "NODB" ]; then
if [ "${TEST_SELECTION}" == "NODB" ]; then
GROUP="--exclude-group DB,SLOWDB"
fi
INPUT="$BASEDIR/tests"
INPUT="${BASEDIR}/tests"
if [ -n "$2" ]; then
INPUT="$INPUT/$2"
INPUT="${INPUT}/$2"
fi
echo "${PHPUNIT[@]}" --configuration tests/phpunit.xml $GROUP $COVER --log-junit "autotest-results.xml" "$INPUT" "$3"
"${PHPUNIT[@]}" --configuration tests/phpunit.xml $GROUP $COVER --log-junit "autotest-results.xml" "$INPUT" "$3"
echo "${PHPUNIT[@]}" --configuration tests/phpunit.xml ${GROUP} ${COVER} --log-junit "autotest-results.xml" "${INPUT}" "$3"
"${PHPUNIT[@]}" --configuration tests/phpunit.xml ${GROUP} ${COVER} --log-junit "autotest-results.xml" "${INPUT}" "$3"
RESULT=$?
if [ -n "$DOCKER_CONTAINER_ID" ]; then
echo "Kill the docker $DOCKER_CONTAINER_ID"
docker stop $DOCKER_CONTAINER_ID
docker rm -f $DOCKER_CONTAINER_ID
unset $DOCKER_CONTAINER_ID
if [ -n "${DOCKER_CONTAINER_ID}" ]; then
echo "Kill the docker ${DOCKER_CONTAINER_ID}"
docker stop ${DOCKER_CONTAINER_ID}
docker rm -f ${DOCKER_CONTAINER_ID}
unset ${DOCKER_CONTAINER_ID}
fi
}
#
# Start the test execution
#
if [ -z "$1" ] && [ -n "$TEST_SELECTION" ]; then
if [ -z "$1" ] && [ -n "${TEST_SELECTION}" ]; then
# run all known database configs
for DBCONFIG in $DBCONFIGS; do
execute_tests "$DBCONFIG"
for DBCONFIG in ${DBCONFIGS}; do
execute_tests "${DBCONFIG}"
done
else
FILENAME="$2"
if [ -n "$2" ] && [ ! -f "tests/$FILENAME" ] && [ "${FILENAME:0:2}" != "--" ]; then
FILENAME="../$FILENAME"
if [ -n "$2" ] && [ ! -f "tests/${FILENAME}" ] && [ "${FILENAME:0:2}" != "--" ]; then
FILENAME="../${FILENAME}"
fi
execute_tests "$1" "$FILENAME" "$3"
execute_tests "$1" "${FILENAME}" "$3"
fi

View File

@ -87,8 +87,8 @@ define('PRIORITIES', [PRIORITY_CRITICAL, PRIORITY_HIGH, PRIORITY_MEDIUM, PRIORIT
/* @}*/
// Normally this constant is defined - but not if "pcntl" isn't installed
if (!defined("SIGTERM")) {
define("SIGTERM", 15);
if (!defined('SIGTERM')) {
define('SIGTERM', 15);
}
/**
@ -117,6 +117,7 @@ function local_user()
if (!empty($_SESSION['authenticated']) && !empty($_SESSION['uid'])) {
return intval($_SESSION['uid']);
}
return false;
}
@ -169,7 +170,7 @@ function remote_user()
*
* @param string $s - Text of notice
*/
function notice($s)
function notice(string $s)
{
if (empty($_SESSION)) {
return;
@ -189,7 +190,7 @@ function notice($s)
*
* @param string $s - Text of notice
*/
function info($s)
function info(string $s)
{
if (empty($_SESSION)) {
return;

204
composer.lock generated
View File

@ -545,12 +545,12 @@
},
"type": "library",
"autoload": {
"psr-4": {
"DivineOmega\\PasswordExposed\\": "src/"
},
"files": [
"src/PasswordExposedFunction.php"
]
],
"psr-4": {
"DivineOmega\\PasswordExposed\\": "src/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
@ -587,12 +587,12 @@
},
"type": "library",
"autoload": {
"psr-0": {
"HTMLPurifier": "library/"
},
"files": [
"library/HTMLPurifier.composer.php"
],
"psr-0": {
"HTMLPurifier": "library/"
},
"exclude-from-classmap": [
"/library/HTMLPurifier/Language/"
]
@ -839,24 +839,24 @@
},
{
"name": "guzzlehttp/guzzle",
"version": "6.5.5",
"version": "6.5.8",
"source": {
"type": "git",
"url": "https://github.com/guzzle/guzzle.git",
"reference": "9d4290de1cfd701f38099ef7e183b64b4b7b0c5e"
"reference": "a52f0440530b54fa079ce76e8c5d196a42cad981"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/guzzle/guzzle/zipball/9d4290de1cfd701f38099ef7e183b64b4b7b0c5e",
"reference": "9d4290de1cfd701f38099ef7e183b64b4b7b0c5e",
"url": "https://api.github.com/repos/guzzle/guzzle/zipball/a52f0440530b54fa079ce76e8c5d196a42cad981",
"reference": "a52f0440530b54fa079ce76e8c5d196a42cad981",
"shasum": ""
},
"require": {
"ext-json": "*",
"guzzlehttp/promises": "^1.0",
"guzzlehttp/psr7": "^1.6.1",
"guzzlehttp/psr7": "^1.9",
"php": ">=5.5",
"symfony/polyfill-intl-idn": "^1.17.0"
"symfony/polyfill-intl-idn": "^1.17"
},
"require-dev": {
"ext-curl": "*",
@ -873,22 +873,52 @@
}
},
"autoload": {
"psr-4": {
"GuzzleHttp\\": "src/"
},
"files": [
"src/functions_include.php"
]
],
"psr-4": {
"GuzzleHttp\\": "src/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Graham Campbell",
"email": "hello@gjcampbell.co.uk",
"homepage": "https://github.com/GrahamCampbell"
},
{
"name": "Michael Dowling",
"email": "mtdowling@gmail.com",
"homepage": "https://github.com/mtdowling"
},
{
"name": "Jeremy Lindblom",
"email": "jeremeamia@gmail.com",
"homepage": "https://github.com/jeremeamia"
},
{
"name": "George Mponos",
"email": "gmponos@gmail.com",
"homepage": "https://github.com/gmponos"
},
{
"name": "Tobias Nyholm",
"email": "tobias.nyholm@gmail.com",
"homepage": "https://github.com/Nyholm"
},
{
"name": "Márk Sági-Kazár",
"email": "mark.sagikazar@gmail.com",
"homepage": "https://github.com/sagikazarmark"
},
{
"name": "Tobias Schultze",
"email": "webmaster@tubo-world.de",
"homepage": "https://github.com/Tobion"
}
],
"description": "Guzzle is a PHP HTTP client library",
@ -902,7 +932,21 @@
"rest",
"web service"
],
"time": "2020-06-16T21:01:06+00:00"
"funding": [
{
"url": "https://github.com/GrahamCampbell",
"type": "github"
},
{
"url": "https://github.com/Nyholm",
"type": "github"
},
{
"url": "https://tidelift.com/funding/github/packagist/guzzlehttp/guzzle",
"type": "tidelift"
}
],
"time": "2022-06-20T22:16:07+00:00"
},
{
"name": "guzzlehttp/promises",
@ -931,12 +975,12 @@
}
},
"autoload": {
"psr-4": {
"GuzzleHttp\\Promise\\": "src/"
},
"files": [
"src/functions_include.php"
]
],
"psr-4": {
"GuzzleHttp\\Promise\\": "src/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
@ -986,16 +1030,16 @@
},
{
"name": "guzzlehttp/psr7",
"version": "1.8.3",
"version": "1.9.0",
"source": {
"type": "git",
"url": "https://github.com/guzzle/psr7.git",
"reference": "1afdd860a2566ed3c2b0b4a3de6e23434a79ec85"
"reference": "e98e3e6d4f86621a9b75f623996e6bbdeb4b9318"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/guzzle/psr7/zipball/1afdd860a2566ed3c2b0b4a3de6e23434a79ec85",
"reference": "1afdd860a2566ed3c2b0b4a3de6e23434a79ec85",
"url": "https://api.github.com/repos/guzzle/psr7/zipball/e98e3e6d4f86621a9b75f623996e6bbdeb4b9318",
"reference": "e98e3e6d4f86621a9b75f623996e6bbdeb4b9318",
"shasum": ""
},
"require": {
@ -1016,16 +1060,16 @@
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "1.7-dev"
"dev-master": "1.9-dev"
}
},
"autoload": {
"psr-4": {
"GuzzleHttp\\Psr7\\": "src/"
},
"files": [
"src/functions_include.php"
]
],
"psr-4": {
"GuzzleHttp\\Psr7\\": "src/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
@ -1088,7 +1132,7 @@
"type": "tidelift"
}
],
"time": "2021-10-05T13:56:00+00:00"
"time": "2022-06-20T21:43:03+00:00"
},
{
"name": "league/html-to-markdown",
@ -1471,12 +1515,12 @@
},
"type": "library",
"autoload": {
"classmap": [
"Mobile_Detect.php"
],
"psr-0": {
"Detection": "namespaced/"
}
},
"classmap": [
"Mobile_Detect.php"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
@ -1611,12 +1655,12 @@
},
"type": "library",
"autoload": {
"psr-4": {
"FastRoute\\": "src/"
},
"files": [
"src/functions.php"
]
],
"psr-4": {
"FastRoute\\": "src/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
@ -3803,16 +3847,16 @@
},
{
"name": "symfony/polyfill-intl-idn",
"version": "v1.23.0",
"version": "v1.26.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/polyfill-intl-idn.git",
"reference": "65bd267525e82759e7d8c4e8ceea44f398838e65"
"reference": "59a8d271f00dd0e4c2e518104cc7963f655a1aa8"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/polyfill-intl-idn/zipball/65bd267525e82759e7d8c4e8ceea44f398838e65",
"reference": "65bd267525e82759e7d8c4e8ceea44f398838e65",
"url": "https://api.github.com/repos/symfony/polyfill-intl-idn/zipball/59a8d271f00dd0e4c2e518104cc7963f655a1aa8",
"reference": "59a8d271f00dd0e4c2e518104cc7963f655a1aa8",
"shasum": ""
},
"require": {
@ -3826,7 +3870,7 @@
"type": "library",
"extra": {
"branch-alias": {
"dev-main": "1.23-dev"
"dev-main": "1.26-dev"
},
"thanks": {
"name": "symfony/polyfill",
@ -3834,12 +3878,12 @@
}
},
"autoload": {
"psr-4": {
"Symfony\\Polyfill\\Intl\\Idn\\": ""
},
"files": [
"bootstrap.php"
]
],
"psr-4": {
"Symfony\\Polyfill\\Intl\\Idn\\": ""
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
@ -3883,20 +3927,20 @@
"type": "tidelift"
}
],
"time": "2021-05-27T09:27:20+00:00"
"time": "2022-05-24T11:49:31+00:00"
},
{
"name": "symfony/polyfill-intl-normalizer",
"version": "v1.23.0",
"version": "v1.26.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/polyfill-intl-normalizer.git",
"reference": "8590a5f561694770bdcd3f9b5c69dde6945028e8"
"reference": "219aa369ceff116e673852dce47c3a41794c14bd"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/polyfill-intl-normalizer/zipball/8590a5f561694770bdcd3f9b5c69dde6945028e8",
"reference": "8590a5f561694770bdcd3f9b5c69dde6945028e8",
"url": "https://api.github.com/repos/symfony/polyfill-intl-normalizer/zipball/219aa369ceff116e673852dce47c3a41794c14bd",
"reference": "219aa369ceff116e673852dce47c3a41794c14bd",
"shasum": ""
},
"require": {
@ -3908,7 +3952,7 @@
"type": "library",
"extra": {
"branch-alias": {
"dev-main": "1.23-dev"
"dev-main": "1.26-dev"
},
"thanks": {
"name": "symfony/polyfill",
@ -3916,12 +3960,12 @@
}
},
"autoload": {
"psr-4": {
"Symfony\\Polyfill\\Intl\\Normalizer\\": ""
},
"files": [
"bootstrap.php"
],
"psr-4": {
"Symfony\\Polyfill\\Intl\\Normalizer\\": ""
},
"classmap": [
"Resources/stubs"
]
@ -3964,7 +4008,7 @@
"type": "tidelift"
}
],
"time": "2021-02-19T12:13:01+00:00"
"time": "2022-05-24T11:49:31+00:00"
},
{
"name": "symfony/polyfill-php56",
@ -4033,16 +4077,16 @@
},
{
"name": "symfony/polyfill-php72",
"version": "v1.23.0",
"version": "v1.26.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/polyfill-php72.git",
"reference": "9a142215a36a3888e30d0a9eeea9766764e96976"
"reference": "bf44a9fd41feaac72b074de600314a93e2ae78e2"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/polyfill-php72/zipball/9a142215a36a3888e30d0a9eeea9766764e96976",
"reference": "9a142215a36a3888e30d0a9eeea9766764e96976",
"url": "https://api.github.com/repos/symfony/polyfill-php72/zipball/bf44a9fd41feaac72b074de600314a93e2ae78e2",
"reference": "bf44a9fd41feaac72b074de600314a93e2ae78e2",
"shasum": ""
},
"require": {
@ -4051,7 +4095,7 @@
"type": "library",
"extra": {
"branch-alias": {
"dev-main": "1.23-dev"
"dev-main": "1.26-dev"
},
"thanks": {
"name": "symfony/polyfill",
@ -4059,12 +4103,12 @@
}
},
"autoload": {
"psr-4": {
"Symfony\\Polyfill\\Php72\\": ""
},
"files": [
"bootstrap.php"
]
],
"psr-4": {
"Symfony\\Polyfill\\Php72\\": ""
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
@ -4102,7 +4146,7 @@
"type": "tidelift"
}
],
"time": "2021-05-27T09:17:38+00:00"
"time": "2022-05-24T11:49:31+00:00"
},
{
"name": "ua-parser/uap-php",
@ -4865,12 +4909,12 @@
},
"type": "library",
"autoload": {
"psr-4": {
"DeepCopy\\": "src/DeepCopy/"
},
"files": [
"src/DeepCopy/deep_copy.php"
]
],
"psr-4": {
"DeepCopy\\": "src/DeepCopy/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
@ -5618,11 +5662,11 @@
}
},
"autoload": {
"classmap": [
"src/"
],
"files": [
"src/Framework/Assert/Functions.php"
],
"classmap": [
"src/"
]
},
"notification-url": "https://packagist.org/downloads/",
@ -6586,12 +6630,12 @@
}
},
"autoload": {
"psr-4": {
"Symfony\\Polyfill\\Ctype\\": ""
},
"files": [
"bootstrap.php"
]
],
"psr-4": {
"Symfony\\Polyfill\\Ctype\\": ""
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [

View File

@ -1,6 +1,6 @@
-- ------------------------------------------
-- Friendica 2022.09-dev (Giant Rhubarb)
-- DB_UPDATE_VERSION 1469
-- DB_UPDATE_VERSION 1473
-- ------------------------------------------
@ -297,6 +297,7 @@ CREATE TABLE IF NOT EXISTS `2fa_trusted_browser` (
`cookie_hash` varchar(80) NOT NULL COMMENT 'Trusted cookie hash',
`uid` mediumint unsigned NOT NULL COMMENT 'User ID',
`user_agent` text COMMENT 'User agent string',
`trusted` boolean NOT NULL DEFAULT '1' COMMENT 'Whenever this browser should be trusted or not',
`created` datetime NOT NULL COMMENT 'Datetime the trusted browser was recorded',
`last_used` datetime COMMENT 'Datetime the trusted browser was last used',
PRIMARY KEY(`cookie_hash`),
@ -1216,13 +1217,13 @@ CREATE TABLE IF NOT EXISTS `post-link` (
CREATE TABLE IF NOT EXISTS `post-media` (
`id` int unsigned NOT NULL auto_increment COMMENT 'sequential ID',
`uri-id` int unsigned NOT NULL COMMENT 'Id of the item-uri table entry that contains the item uri',
`url` varbinary(511) NOT NULL COMMENT 'Media URL',
`url` varbinary(1024) NOT NULL COMMENT 'Media URL',
`type` tinyint unsigned NOT NULL DEFAULT 0 COMMENT 'Media type',
`mimetype` varchar(60) COMMENT '',
`height` smallint unsigned COMMENT 'Height of the media',
`width` smallint unsigned COMMENT 'Width of the media',
`size` int unsigned COMMENT 'Media size',
`preview` varbinary(255) COMMENT 'Preview URL',
`size` bigint unsigned COMMENT 'Media size',
`preview` varbinary(512) COMMENT 'Preview URL',
`preview-height` smallint unsigned COMMENT 'Height of the preview picture',
`preview-width` smallint unsigned COMMENT 'Width of the preview picture',
`description` text COMMENT '',
@ -1234,7 +1235,7 @@ CREATE TABLE IF NOT EXISTS `post-media` (
`publisher-name` varchar(255) COMMENT 'Name of the publisher of the media',
`publisher-image` varbinary(255) COMMENT 'Image of the publisher of the media',
PRIMARY KEY(`id`),
UNIQUE INDEX `uri-id-url` (`uri-id`,`url`),
UNIQUE INDEX `uri-id-url` (`uri-id`,`url`(512)),
INDEX `uri-id-id` (`uri-id`,`id`),
FOREIGN KEY (`uri-id`) REFERENCES `item-uri` (`id`) ON UPDATE RESTRICT ON DELETE CASCADE
) DEFAULT COLLATE utf8mb4_general_ci COMMENT='Attached media';

View File

@ -82,6 +82,7 @@ General
../settings
---------
* o - Account
* 2 - Two-factor authentication
* p - Profiles
* t - Additional features
* w - Social Networks

View File

@ -7,10 +7,11 @@ Fields
------
| Field | Description | Type | Null | Key | Default | Extra |
| ----------- | ------------------------------------------ | ------------------ | ---- | --- | ------- | ----- |
| ----------- | ---------------------------------------------- | ------------------ | ---- | --- | ------- | ----- |
| cookie_hash | Trusted cookie hash | varchar(80) | NO | PRI | NULL | |
| uid | User ID | mediumint unsigned | NO | | NULL | |
| user_agent | User agent string | text | YES | | NULL | |
| trusted | Whenever this browser should be trusted or not | boolean | NO | | 1 | |
| created | Datetime the trusted browser was recorded | datetime | NO | | NULL | |
| last_used | Datetime the trusted browser was last used | datetime | YES | | NULL | |

View File

@ -10,13 +10,13 @@ Fields
| --------------- | --------------------------------------------------------- | ----------------- | ---- | --- | ------- | -------------- |
| id | sequential ID | int unsigned | NO | PRI | NULL | auto_increment |
| uri-id | Id of the item-uri table entry that contains the item uri | int unsigned | NO | | NULL | |
| url | Media URL | varbinary(511) | NO | | NULL | |
| url | Media URL | varbinary(1024) | NO | | NULL | |
| type | Media type | tinyint unsigned | NO | | 0 | |
| mimetype | | varchar(60) | YES | | NULL | |
| height | Height of the media | smallint unsigned | YES | | NULL | |
| width | Width of the media | smallint unsigned | YES | | NULL | |
| size | Media size | int unsigned | YES | | NULL | |
| preview | Preview URL | varbinary(255) | YES | | NULL | |
| size | Media size | bigint unsigned | YES | | NULL | |
| preview | Preview URL | varbinary(512) | YES | | NULL | |
| preview-height | Height of the preview picture | smallint unsigned | YES | | NULL | |
| preview-width | Width of the preview picture | smallint unsigned | YES | | NULL | |
| description | | text | YES | | NULL | |
@ -32,9 +32,9 @@ Indexes
------------
| Name | Fields |
| ---------- | ------------------- |
| ---------- | ------------------------ |
| PRIMARY | id |
| uri-id-url | UNIQUE, uri-id, url |
| uri-id-url | UNIQUE, uri-id, url(512) |
| uri-id-id | uri-id, id |
Foreign Keys

View File

@ -302,7 +302,7 @@ function display_content(App $a, $update = false, $update_uid = 0)
// Preparing the meta header
$description = trim(BBCode::toPlaintext($item['body']));
$title = trim(BBCode::toPlaintext($item['title']));
$title = trim(BBCode::toPlaintext($item['title'] ?? ''));
$author_name = $item['author-name'];
$image = DI::baseUrl()->remove($item['author-avatar']);

View File

@ -83,7 +83,7 @@ function editpost_content(App $a)
Hook::callAll('jot_tool', $jotplugins);
$tpl = Renderer::getMarkupTemplate("jot.tpl");
$tpl = Renderer::getMarkupTemplate('jot.tpl');
$o .= Renderer::replaceMacros($tpl, [
'$is_edit' => true,
'$return_path' => '/display/' . $item['guid'],

View File

@ -47,7 +47,7 @@ function fbrowser_content(App $a)
}
// Needed to match the correct template in a module that uses a different theme than the user/site/default
$theme = Strings::sanitizeFilePathItem($_GET['theme'] ?? null);
$theme = Strings::sanitizeFilePathItem($_GET['theme'] ?? '');
if ($theme && is_file("view/theme/$theme/config.php")) {
$a->setCurrentTheme($theme);
}

View File

@ -439,8 +439,13 @@ function item_post(App $a) {
// Ensure to only modify attachments that you own
$srch = '<' . intval($contact_id) . '>';
$condition = ['allow_cid' => $srch, 'allow_gid' => '', 'deny_cid' => '', 'deny_gid' => '',
'id' => $attach];
$condition = [
'allow_cid' => $srch,
'allow_gid' => '',
'deny_cid' => '',
'deny_gid' => '',
'id' => $attach,
];
if (!Attach::exists($condition)) {
continue;
}
@ -520,7 +525,7 @@ function item_post(App $a) {
$origin = $_REQUEST['origin'];
}
$uri = Item::newURI($api_source ? $profile_uid : $uid, $guid);
$uri = Item::newURI($guid);
// Fallback so that we alway have a parent uri
if (!$thr_parent_uri || !$toplevel_item_id) {

View File

@ -187,7 +187,7 @@ function photos_post(App $a)
}
if (DI::args()->getArgc() > 3 && DI::args()->getArgv()[2] === 'album') {
if (!Strings::isHex(DI::args()->getArgv()[3])) {
if (!Strings::isHex(DI::args()->getArgv()[3] ?? '')) {
DI::baseUrl()->redirect('photos/' . $user['nickname'] . '/album');
}
$album = hex2bin(DI::args()->getArgv()[3]);
@ -360,7 +360,7 @@ function photos_post(App $a)
if (DBA::isResult($photos) && !$item_id) {
// Create item container
$title = '';
$uri = Item::newURI($page_owner_uid);
$uri = Item::newURI();
$arr = [];
$arr['guid'] = System::createUUID();
@ -524,7 +524,7 @@ function photos_post(App $a)
if (count($taginfo)) {
foreach ($taginfo as $tagged) {
$uri = Item::newURI($page_owner_uid);
$uri = Item::newURI();
$arr = [];
$arr['guid'] = System::createUUID();
@ -728,7 +728,7 @@ function photos_post(App $a)
$smallest = 2;
}
$uri = Item::newURI($page_owner_uid);
$uri = Item::newURI();
// Create item container
$lat = $lon = null;
@ -892,7 +892,7 @@ function photos_content(App $a)
return;
}
$selname = Strings::isHex($datum) ? hex2bin($datum) : '';
$selname = (!is_null($datum) && Strings::isHex($datum)) ? hex2bin($datum) : '';
$albumselect = '';
@ -954,7 +954,7 @@ function photos_content(App $a)
// Display a single photo album
if ($datatype === 'album') {
// if $datum is not a valid hex, redirect to the default page
if (!Strings::isHex($datum)) {
if (is_null($datum) || !Strings::isHex($datum)) {
DI::baseUrl()->redirect('photos/' . $user['nickname']. '/album');
}
$album = hex2bin($datum);
@ -977,7 +977,7 @@ function photos_content(App $a)
/// @TODO I have seen this many times, maybe generalize it script-wide and encapsulate it?
$order_field = $_GET['order'] ?? '';
if ($order_field === 'posted') {
if ($order_field === 'created') {
$order = 'ASC';
} else {
$order = 'DESC';
@ -1031,10 +1031,10 @@ function photos_content(App $a)
$drop = [DI::l10n()->t('Drop Album'), 'photos/' . $user['nickname'] . '/album/' . bin2hex($album) . '/drop'];
}
if ($order_field === 'posted') {
if ($order_field === 'created') {
$order = [DI::l10n()->t('Show Newest First'), 'photos/' . $user['nickname'] . '/album/' . bin2hex($album), 'oldest'];
} else {
$order = [DI::l10n()->t('Show Oldest First'), 'photos/' . $user['nickname'] . '/album/' . bin2hex($album) . '?order=posted', 'newest'];
$order = [DI::l10n()->t('Show Oldest First'), 'photos/' . $user['nickname'] . '/album/' . bin2hex($album) . '?order=created', 'newest'];
}
$photos = [];
@ -1054,7 +1054,7 @@ function photos_content(App $a)
'id' => $rr['id'],
'twist' => ' ' . ($twist ? 'rotleft' : 'rotright') . rand(2,4),
'link' => 'photos/' . $user['nickname'] . '/image/' . $rr['resource-id']
. ($order_field === 'posted' ? '?order=posted' : ''),
. ($order_field === 'created' ? '?order=created' : ''),
'title' => DI::l10n()->t('View Photo'),
'src' => 'photo/' . $rr['resource-id'] . '-' . $rr['scale'] . '.' .$ext,
'alt' => $imgalt_e,
@ -1122,7 +1122,7 @@ function photos_content(App $a)
if ($cmd === 'view' && !DI::config()->get('system', 'no_count', false)) {
$order_field = $_GET['order'] ?? '';
if ($order_field === 'posted') {
if ($order_field === 'created') {
$params = ['order' => [$order_field]];
} elseif (!empty($order_field)) {
$params = ['order' => [$order_field => true]];
@ -1150,10 +1150,10 @@ function photos_content(App $a)
}
if (!is_null($prv)) {
$prevlink = 'photos/' . $user['nickname'] . '/image/' . $prvnxt[$prv]['resource-id'] . ($order_field === 'posted' ? '?order=posted' : '');
$prevlink = 'photos/' . $user['nickname'] . '/image/' . $prvnxt[$prv]['resource-id'] . ($order_field === 'created' ? '?order=created' : '');
}
if (!is_null($nxt)) {
$nextlink = 'photos/' . $user['nickname'] . '/image/' . $prvnxt[$nxt]['resource-id'] . ($order_field === 'posted' ? '?order=posted' : '');
$nextlink = 'photos/' . $user['nickname'] . '/image/' . $prvnxt[$nxt]['resource-id'] . ($order_field === 'created' ? '?order=created' : '');
}
$tpl = Renderer::getMarkupTemplate('photo_edit_head.tpl');

View File

@ -73,7 +73,7 @@ function tagger_content(App $a) {
return;
}
$uri = Item::newURI($owner_uid);
$uri = Item::newURI();
$xterm = XML::escape($term);
$post_type = (($item['resource-id']) ? DI::l10n()->t('photo') : DI::l10n()->t('status'));
$targettype = (($item['resource-id']) ? Activity\ObjectType::IMAGE : Activity\ObjectType::NOTE );

View File

@ -157,9 +157,9 @@ function wall_upload_post(App $a, $desktopmode = true)
" - size: " . $filesize . " - type: " . $filetype);
$imagedata = @file_get_contents($src);
$Image = new Image($imagedata, $filetype);
$image = new Image($imagedata, $filetype);
if (!$Image->isValid()) {
if (!$image->isValid()) {
$msg = DI::l10n()->t('Unable to process image.');
@unlink($src);
if ($r_json) {
@ -170,18 +170,18 @@ function wall_upload_post(App $a, $desktopmode = true)
System::exit();
}
$Image->orient($src);
$image->orient($src);
@unlink($src);
$max_length = DI::config()->get('system', 'max_image_length');
if ($max_length > 0) {
$Image->scaleDown($max_length);
$filesize = strlen($Image->asString());
$image->scaleDown($max_length);
$filesize = strlen($image->asString());
Logger::info("File upload: Scaling picture to new size " . $max_length);
}
$width = $Image->getWidth();
$height = $Image->getHeight();
$width = $image->getWidth();
$height = $image->getHeight();
$maximagesize = DI::config()->get('system', 'maximagesize');
@ -190,10 +190,10 @@ function wall_upload_post(App $a, $desktopmode = true)
foreach ([5120, 2560, 1280, 640] as $pixels) {
if (($filesize > $maximagesize) && (max($width, $height) > $pixels)) {
Logger::info('Resize', ['size' => $filesize, 'width' => $width, 'height' => $height, 'max' => $maximagesize, 'pixels' => $pixels]);
$Image->scaleDown($pixels);
$filesize = strlen($Image->asString());
$width = $Image->getWidth();
$height = $Image->getHeight();
$image->scaleDown($pixels);
$filesize = strlen($image->asString());
$width = $image->getWidth();
$height = $image->getHeight();
}
}
if ($filesize > $maximagesize) {
@ -220,7 +220,7 @@ function wall_upload_post(App $a, $desktopmode = true)
$defperm = '<' . $default_cid . '>';
$r = Photo::store($Image, $page_owner_uid, $visitor, $resource_id, $filename, $album, 0, Photo::DEFAULT, $defperm);
$r = Photo::store($image, $page_owner_uid, $visitor, $resource_id, $filename, $album, 0, Photo::DEFAULT, $defperm);
if (!$r) {
$msg = DI::l10n()->t('Image upload failed.');
@ -233,16 +233,16 @@ function wall_upload_post(App $a, $desktopmode = true)
}
if ($width > 640 || $height > 640) {
$Image->scaleDown(640);
$r = Photo::store($Image, $page_owner_uid, $visitor, $resource_id, $filename, $album, 1, Photo::DEFAULT, $defperm);
$image->scaleDown(640);
$r = Photo::store($image, $page_owner_uid, $visitor, $resource_id, $filename, $album, 1, Photo::DEFAULT, $defperm);
if ($r) {
$smallest = 1;
}
}
if ($width > 320 || $height > 320) {
$Image->scaleDown(320);
$r = Photo::store($Image, $page_owner_uid, $visitor, $resource_id, $filename, $album, 2, Photo::DEFAULT, $defperm);
$image->scaleDown(320);
$r = Photo::store($image, $page_owner_uid, $visitor, $resource_id, $filename, $album, 2, Photo::DEFAULT, $defperm);
if ($r && ($smallest == 0)) {
$smallest = 2;
}
@ -264,8 +264,8 @@ function wall_upload_post(App $a, $desktopmode = true)
$picture["height"] = $photo["height"];
$picture["type"] = $photo["type"];
$picture["albumpage"] = DI::baseUrl() . '/photos/' . $page_owner_nick . '/image/' . $resource_id;
$picture["picture"] = DI::baseUrl() . "/photo/{$resource_id}-0." . $Image->getExt();
$picture["preview"] = DI::baseUrl() . "/photo/{$resource_id}-{$smallest}." . $Image->getExt();
$picture["picture"] = DI::baseUrl() . "/photo/{$resource_id}-0." . $image->getExt();
$picture["preview"] = DI::baseUrl() . "/photo/{$resource_id}-{$smallest}." . $image->getExt();
if ($r_json) {
System::jsonExit(['picture' => $picture]);
@ -280,7 +280,7 @@ function wall_upload_post(App $a, $desktopmode = true)
System::jsonExit(['ok' => true]);
}
echo "\n\n" . '[url=' . DI::baseUrl() . '/photos/' . $page_owner_nick . '/image/' . $resource_id . '][img]' . DI::baseUrl() . "/photo/{$resource_id}-{$smallest}.".$Image->getExt()."[/img][/url]\n\n";
echo "\n\n" . '[url=' . DI::baseUrl() . '/photos/' . $page_owner_nick . '/image/' . $resource_id . '][img]' . DI::baseUrl() . "/photo/{$resource_id}-{$smallest}." . $image->getExt() . "[/img][/url]\n\n";
System::exit();
// NOTREACHED
}

View File

@ -145,7 +145,7 @@ class App
$this->nickname = $nickname;
}
public function isLoggedIn()
public function isLoggedIn(): bool
{
return local_user() && $this->user_id && ($this->user_id == local_user());
}
@ -155,7 +155,7 @@ class App
*
* @return bool true if user is an admin
*/
public function isSiteAdmin()
public function isSiteAdmin(): bool
{
$admin_email = $this->config->get('config', 'admin_email');
@ -166,18 +166,18 @@ class App
/**
* Fetch the user id
* @return int
* @return int User id
*/
public function getLoggedInUserId()
public function getLoggedInUserId(): int
{
return $this->user_id;
}
/**
* Fetch the user nick name
* @return string
* @return string User's nickname
*/
public function getLoggedInUserNickname()
public function getLoggedInUserNickname(): string
{
return $this->nickname;
}
@ -260,9 +260,9 @@ class App
/**
* Fetch workerqueue information
*
* @return array
* @return array Worker queue
*/
public function getQueue()
public function getQueue(): array
{
return $this->queue ?? [];
}
@ -270,8 +270,8 @@ class App
/**
* Fetch a specific workerqueue field
*
* @param string $index
* @return mixed
* @param string $index Work queue record to fetch
* @return mixed Work queue item or NULL if not found
*/
public function getQueueValue(string $index)
{
@ -306,9 +306,9 @@ class App
/**
* The basepath of this app
*
* @return string
* @return string Base path from configuration
*/
public function getBasePath()
public function getBasePath(): string
{
// Don't use the basepath of the config table for basepath (it should always be the config-file one)
return $this->config->getCache()->get('system', 'basepath');
@ -396,10 +396,10 @@ class App
/**
* Returns the current theme name. May be overriden by the mobile theme name.
*
* @return string
* @return string Current theme name or empty string in installation phase
* @throws Exception
*/
public function getCurrentTheme()
public function getCurrentTheme(): string
{
if ($this->mode->isInstall()) {
return '';
@ -425,10 +425,10 @@ class App
/**
* Returns the current mobile theme name.
*
* @return string
* @return string Mobile theme name or empty string if installer
* @throws Exception
*/
public function getCurrentMobileTheme()
public function getCurrentMobileTheme(): string
{
if ($this->mode->isInstall()) {
return '';
@ -441,12 +441,22 @@ class App
return $this->currentMobileTheme;
}
public function setCurrentTheme($theme)
/**
* Setter for current theme name
*
* @param string $theme Name of current theme
*/
public function setCurrentTheme(string $theme)
{
$this->currentTheme = $theme;
}
public function setCurrentMobileTheme($theme)
/**
* Setter for current mobile theme name
*
* @param string $theme Name of current mobile theme
*/
public function setCurrentMobileTheme(string $theme)
{
$this->currentMobileTheme = $theme;
}
@ -525,10 +535,10 @@ class App
/**
* Provide a sane default if nothing is chosen or the specified theme does not exist.
*
* @return string
* @return string Current theme's stylsheet path
* @throws Exception
*/
public function getCurrentThemeStylesheetPath()
public function getCurrentThemeStylesheetPath(): string
{
return Core\Theme::getStylesheetPath($this->getCurrentTheme());
}
@ -604,9 +614,9 @@ class App
if (!empty($_GET['zrl']) && $this->mode->isNormal() && !$this->mode->isBackend() && !local_user()) {
// Only continue when the given profile link seems valid
// Valid profile links contain a path with "/profile/" and no query parameters
if ((parse_url($_GET['zrl'], PHP_URL_QUERY) == "") &&
strstr(parse_url($_GET['zrl'], PHP_URL_PATH), "/profile/")) {
if (Core\Session::get('visitor_home') != $_GET["zrl"]) {
if ((parse_url($_GET['zrl'], PHP_URL_QUERY) == '') &&
strstr(parse_url($_GET['zrl'], PHP_URL_PATH), '/profile/')) {
if (Core\Session::get('visitor_home') != $_GET['zrl']) {
Core\Session::set('my_url', $_GET['zrl']);
Core\Session::set('authenticated', 0);
@ -695,7 +705,8 @@ class App
// Initialize module that can set the current theme in the init() method, either directly or via App->setProfileOwner
$page['page_title'] = $moduleName;
if (!$this->mode->isInstall() && !$this->mode->has(App\Mode::MAINTENANCEDISABLED)) {
// The "view" module is required to show the theme CSS
if (!$this->mode->isInstall() && !$this->mode->has(App\Mode::MAINTENANCEDISABLED) && $moduleName !== 'view') {
$module = $router->getModule(Maintenance::class);
} else {
// determine the module class and save it to the module instance
@ -730,7 +741,7 @@ class App
*
* @throws HTTPException\InternalServerErrorException
*/
public function redirect($toUrl)
public function redirect(string $toUrl)
{
if (!empty(parse_url($toUrl, PHP_URL_SCHEME))) {
Core\System::externalRedirect($toUrl);

View File

@ -78,7 +78,7 @@ class Arguments
/**
* @return string The whole command of this call
*/
public function getCommand()
public function getCommand(): string
{
return $this->command;
}
@ -94,7 +94,7 @@ class Arguments
/**
* @return array All arguments of this call
*/
public function getArgv()
public function getArgv(): array
{
return $this->argv;
}
@ -102,7 +102,7 @@ class Arguments
/**
* @return string The used HTTP method
*/
public function getMethod()
public function getMethod(): string
{
return $this->method;
}
@ -110,7 +110,7 @@ class Arguments
/**
* @return int The count of arguments of this call
*/
public function getArgc()
public function getArgc(): int
{
return $this->argc;
}
@ -145,7 +145,7 @@ class Arguments
*
* @return bool if the argument position exists
*/
public function has(int $position)
public function has(int $position): bool
{
return array_key_exists($position, $this->argv);
}
@ -158,7 +158,7 @@ class Arguments
*
* @return Arguments The determined arguments
*/
public function determine(array $server, array $get)
public function determine(array $server, array $get): Arguments
{
// removing leading / - maybe a nginx problem
$server['QUERY_STRING'] = ltrim($server['QUERY_STRING'] ?? '', '/');

View File

@ -107,7 +107,7 @@ class BaseURL
*
* @return string
*/
public function getHostname()
public function getHostname(): string
{
return $this->hostname;
}
@ -117,7 +117,7 @@ class BaseURL
*
* @return string
*/
public function getScheme()
public function getScheme(): string
{
return $this->scheme;
}
@ -127,7 +127,7 @@ class BaseURL
*
* @return int
*/
public function getSSLPolicy()
public function getSSLPolicy(): int
{
return $this->sslPolicy;
}
@ -137,7 +137,7 @@ class BaseURL
*
* @return string
*/
public function getUrlPath()
public function getUrlPath(): string
{
return $this->urlPath;
}
@ -151,7 +151,7 @@ class BaseURL
*
* @return string
*/
public function get($ssl = false)
public function get(bool $ssl = false): string
{
if ($this->sslPolicy === self::SSL_POLICY_SELFSIGN && $ssl) {
return Network::switchScheme($this->url);
@ -168,8 +168,9 @@ class BaseURL
* @param string? $urlPath
*
* @return bool true, if successful
* @TODO Find proper types
*/
public function save($hostname = null, $sslPolicy = null, $urlPath = null)
public function save($hostname = null, $sslPolicy = null, $urlPath = null): bool
{
$currHostname = $this->hostname;
$currSSLPolicy = $this->sslPolicy;
@ -224,11 +225,11 @@ class BaseURL
/**
* Save the current url as base URL
*
* @param $url
* @param string $url
*
* @return bool true, if the save was successful
*/
public function saveByURL($url)
public function saveByURL(string $url): bool
{
$parsed = @parse_url($url);
@ -421,7 +422,7 @@ class BaseURL
*
* @return string The cleaned url
*/
public function remove(string $origURL)
public function remove(string $origURL): string
{
// Remove the hostname from the url if it is an internal link
$nurl = Strings::normaliseLink($origURL);
@ -443,9 +444,13 @@ class BaseURL
* @param string $toUrl The destination URL (Default is empty, which is the default page of the Friendica node)
* @param bool $ssl if true, base URL will try to get called with https:// (works just for relative paths)
*
* @throws HTTPException\FoundException
* @throws HTTPException\MovedPermanentlyException
* @throws HTTPException\TemporaryRedirectException
*
* @throws HTTPException\InternalServerErrorException In Case the given URL is not relative to the Friendica node
*/
public function redirect($toUrl = '', $ssl = false)
public function redirect(string $toUrl = '', bool $ssl = false)
{
if (!empty(parse_url($toUrl, PHP_URL_SCHEME))) {
throw new HTTPException\InternalServerErrorException("'$toUrl is not a relative path, please use System::externalRedirectTo");
@ -458,8 +463,8 @@ class BaseURL
/**
* Returns the base url as string
*/
public function __toString()
public function __toString(): string
{
return $this->get();
return (string) $this->get();
}
}

View File

@ -130,7 +130,7 @@ class Mode
*
* @throws \Exception
*/
public function determine(BasePath $basepath, Database $database, Cache $configCache)
public function determine(BasePath $basepath, Database $database, Cache $configCache): Mode
{
$mode = 0;
@ -178,7 +178,7 @@ class Mode
*
* @return Mode returns the determined mode
*/
public function determineRunMode(bool $isBackend, array $server, Arguments $args, MobileDetect $mobileDetect)
public function determineRunMode(bool $isBackend, array $server, Arguments $args, MobileDetect $mobileDetect): Mode
{
foreach (self::BACKEND_CONTENT_TYPES as $type) {
if (strpos(strtolower($server['HTTP_ACCEPT'] ?? ''), $type) !== false) {
@ -201,7 +201,7 @@ class Mode
*
* @return bool returns true, if the mode is set
*/
public function has($mode)
public function has(int $mode): bool
{
return ($this->mode & $mode) > 0;
}
@ -227,7 +227,7 @@ class Mode
*
* @return int Execution Mode
*/
public function getExecutor()
public function getExecutor(): int
{
return $this->executor;
}
@ -235,9 +235,9 @@ class Mode
/**
* Install mode is when the local config file is missing or the DB schema hasn't been installed yet.
*
* @return bool
* @return bool Whether installation mode is active (local/database configuration files present or not)
*/
public function isInstall()
public function isInstall(): bool
{
return !$this->has(Mode::LOCALCONFIGPRESENT) ||
!$this->has(MODE::DBCONFIGAVAILABLE);
@ -248,7 +248,7 @@ class Mode
*
* @return bool
*/
public function isNormal()
public function isNormal(): bool
{
return $this->has(Mode::LOCALCONFIGPRESENT) &&
$this->has(Mode::DBAVAILABLE) &&
@ -261,7 +261,7 @@ class Mode
*
* @return bool Is it a backend call
*/
public function isBackend()
public function isBackend(): bool
{
return $this->isBackend;
}
@ -271,7 +271,7 @@ class Mode
*
* @return bool true if it was an AJAX request
*/
public function isAjax()
public function isAjax(): bool
{
return $this->isAjax;
}
@ -281,7 +281,7 @@ class Mode
*
* @return bool true if it was an mobile request
*/
public function isMobile()
public function isMobile(): bool
{
return $this->isMobile;
}
@ -291,7 +291,7 @@ class Mode
*
* @return bool true if it was an tablet request
*/
public function isTablet()
public function isTablet(): bool
{
return $this->isTablet;
}

View File

@ -195,7 +195,7 @@ class Page implements ArrayAccess
* @param string $media
* @see Page::initHead()
*/
public function registerStylesheet($path, string $media = 'screen')
public function registerStylesheet(string $path, string $media = 'screen')
{
$path = Network::appendQueryParam($path, ['v' => FRIENDICA_VERSION]);
@ -288,7 +288,7 @@ class Page implements ArrayAccess
*
* Taken from http://webcheatsheet.com/php/get_current_page_url.php
*/
private function curPageURL()
private function curPageURL(): string
{
$pageURL = 'http';
if (!empty($_SERVER["HTTPS"]) && ($_SERVER["HTTPS"] == "on")) {

152
src/App/Request.php Normal file
View File

@ -0,0 +1,152 @@
<?php
/**
* @copyright Copyright (C) 2010-2022, the Friendica project
*
* @license GNU AGPL version 3 or any later version
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* 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
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
*/
namespace Friendica\App;
use Friendica\Core\Config\Capability\IManageConfigValues;
/**
* Container for the whole request
*
* @see https://www.php-fig.org/psr/psr-7/#321-psrhttpmessageserverrequestinterface
*
* @todo future container class for whole requests, currently it's not :-)
*/
class Request
{
/**
* A comma separated list of default headers that could contain the client IP in a proxy request
*
* @var string
*/
const DEFAULT_FORWARD_FOR_HEADER = 'HTTP_X_FORWARDED_FOR';
/** @var string The remote IP address of the current request */
protected $remoteAddress;
/**
* @return string The remote IP address of the current request
*
* Do always use this instead of $_SERVER['REMOTE_ADDR']
*/
public function getRemoteAddress(): string
{
return $this->remoteAddress;
}
public function __construct(IManageConfigValues $config, array $server = [])
{
$this->remoteAddress = $this->determineRemoteAddress($config, $server);
}
/**
* Checks if given $remoteAddress matches given $trustedProxy.
* If $trustedProxy is an IPv4 IP range given in CIDR notation, true will be returned if
* $remoteAddress is an IPv4 address within that IP range.
* Otherwise, $remoteAddress will be compared to $trustedProxy literally and the result
* will be returned.
*
* @param string $trustedProxy The current, trusted proxy to check
* @param string $remoteAddress The current remote IP address
*
*
* @return boolean true if $remoteAddress matches $trustedProxy, false otherwise
*/
protected function matchesTrustedProxy(string $trustedProxy, string $remoteAddress): bool
{
$cidrre = '/^([0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3})\/([0-9]{1,2})$/';
if (preg_match($cidrre, $trustedProxy, $match)) {
$net = $match[1];
$shiftbits = min(32, max(0, 32 - intval($match[2])));
$netnum = ip2long($net) >> $shiftbits;
$ipnum = ip2long($remoteAddress) >> $shiftbits;
return $ipnum === $netnum;
}
return $trustedProxy === $remoteAddress;
}
/**
* Checks if given $remoteAddress matches any entry in the given array $trustedProxies.
* For details regarding what "match" means, refer to `matchesTrustedProxy`.
*
* @param string[] $trustedProxies A list of the trusted proxies
* @param string $remoteAddress The current remote IP address
*
* @return boolean true if $remoteAddress matches any entry in $trustedProxies, false otherwise
*/
protected function isTrustedProxy(array $trustedProxies, string $remoteAddress): bool
{
foreach ($trustedProxies as $tp) {
if ($this->matchesTrustedProxy($tp, $remoteAddress)) {
return true;
}
}
return false;
}
/**
* Determines the remote address, if the connection came from a trusted proxy
* and `forwarded_for_headers` has been configured then the IP address
* specified in this header will be returned instead.
*
* @param IManageConfigValues $config
* @param array $server The $_SERVER array
*
* @return string
*/
protected function determineRemoteAddress(IManageConfigValues $config, array $server): string
{
$remoteAddress = $server['REMOTE_ADDR'] ?? '0.0.0.0';
$trustedProxies = preg_split('/(\s*,*\s*)*,+(\s*,*\s*)*/', $config->get('proxy', 'trusted_proxies', ''));
if (\is_array($trustedProxies) && $this->isTrustedProxy($trustedProxies, $remoteAddress)) {
$forwardedForHeaders = preg_split('/(\s*,*\s*)*,+(\s*,*\s*)*/', $config->get('proxy', 'forwarded_for_headers', static::DEFAULT_FORWARD_FOR_HEADER));
foreach ($forwardedForHeaders as $header) {
if (isset($server[$header])) {
foreach (explode(',', $server[$header]) as $IP) {
$IP = trim($IP);
// remove brackets from IPv6 addresses
if (strpos($IP, '[') === 0 && substr($IP, -1) === ']') {
$IP = substr($IP, 1, -1);
}
// skip trusted proxies in the list itself
if ($this->isTrustedProxy($trustedProxies, $IP)) {
continue;
}
if (filter_var($IP, FILTER_VALIDATE_IP) !== false) {
return $IP;
}
}
}
}
}
return $remoteAddress;
}
}

View File

@ -152,7 +152,7 @@ class Router
*
* @throws HTTPException\InternalServerErrorException In case of invalid configs
*/
public function loadRoutes(array $routes)
public function loadRoutes(array $routes): Router
{
$routeCollector = ($this->routeCollector ?? new RouteCollector(new Std(), new GroupCountBased()));
@ -166,6 +166,13 @@ class Router
return $this;
}
/**
* Adds multiple routes to a route collector
*
* @param RouteCollector $routeCollector Route collector instance
* @param array $routes Multiple routes to be added
* @throws HTTPException\InternalServerErrorException If route was wrong (somehow)
*/
private function addRoutes(RouteCollector $routeCollector, array $routes)
{
foreach ($routes as $route => $config) {
@ -221,7 +228,7 @@ class Router
*
* @return bool
*/
private function isRoute(array $config)
private function isRoute(array $config): bool
{
return
// The config array should at least have one entry
@ -253,7 +260,7 @@ class Router
* @throws HTTPException\MethodNotAllowedException If a rule matched but the method didn't
* @throws HTTPException\NotFoundException If no rule matched
*/
private function getModuleClass()
private function getModuleClass(): string
{
$cmd = $this->args->getCommand();
$cmd = '/' . ltrim($cmd, '/');

View File

@ -70,9 +70,11 @@ class BaseCollection extends \ArrayIterator
}
/**
* @return int
* Getter for total count
*
* @return int Total count
*/
public function getTotalCount()
public function getTotalCount(): int
{
return $this->totalCount;
}
@ -85,7 +87,7 @@ class BaseCollection extends \ArrayIterator
* @return array
* @see array_column()
*/
public function column($column, $index_key = null)
public function column(string $column, $index_key = null): array
{
return array_column($this->getArrayCopy(true), $column, $index_key);
}
@ -97,7 +99,7 @@ class BaseCollection extends \ArrayIterator
* @return BaseCollection
* @see array_map()
*/
public function map(callable $callback)
public function map(callable $callback): BaseCollection
{
return new static(array_map($callback, $this->getArrayCopy()), $this->getTotalCount());
}
@ -110,7 +112,7 @@ class BaseCollection extends \ArrayIterator
* @return BaseCollection
* @see array_filter()
*/
public function filter(callable $callback = null, int $flag = 0)
public function filter(callable $callback = null, int $flag = 0): BaseCollection
{
return new static(array_filter($this->getArrayCopy(), $callback, $flag));
}

View File

@ -55,14 +55,14 @@ abstract class BaseEntity extends BaseDataTransferObject
}
/**
* @param $name
* @param mixed $name
* @return bool
* @throws HTTPException\InternalServerErrorException
*/
public function __isset($name)
public function __isset($name): bool
{
if (!property_exists($this, $name)) {
throw new HTTPException\InternalServerErrorException('Unknown property ' . $name . ' in Entity ' . static::class);
throw new HTTPException\InternalServerErrorException('Unknown property ' . $name . ' of type ' . gettype($name) . ' in Entity ' . static::class);
}
return !empty($this->$name);

View File

@ -110,11 +110,11 @@ abstract class BaseModel extends BaseDataTransferObject
* - $model->field (outside of class)
* - $this->field (inside of class)
*
* @param $name
* @param string $name Name of data to fetch
* @return mixed
* @throws HTTPException\InternalServerErrorException
*/
public function __get($name)
public function __get(string $name)
{
$this->checkValid();

View File

@ -102,6 +102,7 @@ abstract class BaseModule implements ICanHandleRequests
* e.g. from protocol implementations.
*
* @param string[] $request The $_REQUEST content
* @return void
*/
protected function rawContent(array $request = [])
{
@ -117,6 +118,7 @@ abstract class BaseModule implements ICanHandleRequests
* XML feed or a JSON output.
*
* @param string[] $request The $_REQUEST content
* @return string
*/
protected function content(array $request = []): string
{
@ -130,6 +132,7 @@ abstract class BaseModule implements ICanHandleRequests
* Doesn't display any content
*
* @param string[] $request The $_REQUEST content
* @return void
*/
protected function delete(array $request = [])
{
@ -142,6 +145,7 @@ abstract class BaseModule implements ICanHandleRequests
* Doesn't display any content
*
* @param string[] $request The $_REQUEST content
* @return void
*/
protected function patch(array $request = [])
{
@ -154,7 +158,7 @@ abstract class BaseModule implements ICanHandleRequests
* Doesn't display any content
*
* @param string[] $request The $_REQUEST content
*
* @return void
*/
protected function post(array $request = [])
{
@ -168,6 +172,7 @@ abstract class BaseModule implements ICanHandleRequests
* Doesn't display any content
*
* @param string[] $request The $_REQUEST content
* @return void
*/
protected function put(array $request = [])
{
@ -279,12 +284,12 @@ abstract class BaseModule implements ICanHandleRequests
/**
* Fetch a request value and apply default values and check against minimal and maximal values
*
* @param array $input
* @param string $parameter
* @param mixed $default
* @param mixed $minimal_value
* @param mixed $maximum_value
* @return mixed
* @param array $input Input fields
* @param string $parameter Parameter
* @param mixed $default Default
* @param mixed $minimal_value Minimal value
* @param mixed $maximum_value Maximum value
* @return mixed null on error anything else on success (?)
*/
public function getRequestValue(array $input, string $parameter, $default = null, $minimal_value = null, $maximum_value = null)
{
@ -320,7 +325,7 @@ abstract class BaseModule implements ICanHandleRequests
return $value;
}
/*
/**
* Functions used to protect against Cross-Site Request Forgery
* The security token has to base on at least one value that an attacker can't know - here it's the session ID and the private key.
* In this implementation, a security token is reusable (if the user submits a form, goes back and resubmits the form, maybe with small changes;
@ -330,8 +335,11 @@ abstract class BaseModule implements ICanHandleRequests
* If the new page contains by any chance external elements, then the used security token is exposed by the referrer.
* Actually, important actions should not be triggered by Links / GET-Requests at all, but sometimes they still are,
* so this mechanism brings in some damage control (the attacker would be able to forge a request to a form of this type, but not to forms of other types).
*
* @param string $typename Type name
* @return string Security hash with timestamp
*/
public static function getFormSecurityToken($typename = '')
public static function getFormSecurityToken(string $typename = ''): string
{
$user = User::getById(DI::app()->getLoggedInUserId(), ['guid', 'prvkey']);
$timestamp = time();
@ -340,7 +348,14 @@ abstract class BaseModule implements ICanHandleRequests
return $timestamp . '.' . $sec_hash;
}
public static function checkFormSecurityToken($typename = '', $formname = 'form_security_token')
/**
* Checks if form's security (CSRF) token is valid.
*
* @param string $typename ???
* @param string $formname Name of form/field (???)
* @return bool Whether it is valid
*/
public static function checkFormSecurityToken(string $typename = '', string $formname = 'form_security_token'): bool
{
$hash = null;
@ -372,12 +387,12 @@ abstract class BaseModule implements ICanHandleRequests
return ($sec_hash == $x[1]);
}
public static function getFormSecurityStandardErrorMessage()
public static function getFormSecurityStandardErrorMessage(): string
{
return DI::l10n()->t("The form security token was not correct. This probably happened because the form has been opened for too long \x28>3 hours\x29 before submitting it.") . EOL;
}
public static function checkFormSecurityTokenRedirectOnError($err_redirect, $typename = '', $formname = 'form_security_token')
public static function checkFormSecurityTokenRedirectOnError(string $err_redirect, string $typename = '', string $formname = 'form_security_token')
{
if (!self::checkFormSecurityToken($typename, $formname)) {
Logger::notice('checkFormSecurityToken failed: user ' . DI::app()->getLoggedInUserNickname() . ' - form element ' . $typename);
@ -387,7 +402,7 @@ abstract class BaseModule implements ICanHandleRequests
}
}
public static function checkFormSecurityTokenForbiddenOnError($typename = '', $formname = 'form_security_token')
public static function checkFormSecurityTokenForbiddenOnError(string $typename = '', string $formname = 'form_security_token')
{
if (!self::checkFormSecurityToken($typename, $formname)) {
Logger::notice('checkFormSecurityToken failed: user ' . DI::app()->getLoggedInUserNickname() . ' - form element ' . $typename);
@ -397,7 +412,7 @@ abstract class BaseModule implements ICanHandleRequests
}
}
protected static function getContactFilterTabs(string $baseUrl, string $current, bool $displayCommonTab)
protected static function getContactFilterTabs(string $baseUrl, string $current, bool $displayCommonTab): array
{
$tabs = [
[

View File

@ -82,7 +82,7 @@ HELP;
AddonCore::loadAddons();
}
protected function doExecute()
protected function doExecute(): int
{
if ($this->getOption('v')) {
$this->out('Class: ' . __CLASS__);
@ -116,8 +116,7 @@ HELP;
/**
* Lists plugins
*
* @return int Return code of this command
*
* @return int|bool Return code of this command, false on error (?)
* @throws \Exception
*/
private function list()
@ -165,10 +164,9 @@ HELP;
* Enables an addon
*
* @return int Return code of this command
*
* @throws \Exception
*/
private function enable()
private function enable(): int
{
$addonname = $this->getArgument(1);
@ -190,10 +188,9 @@ HELP;
* Disables an addon
*
* @return int Return code of this command
*
* @throws \Exception
*/
private function disable()
private function disable(): int
{
$addonname = $this->getArgument(1);

View File

@ -80,7 +80,7 @@ HELP;
$this->l10n = $l10n;
}
protected function doExecute()
protected function doExecute(): int
{
if ($this->getOption('v')) {
$this->out('Class: ' . __CLASS__);

View File

@ -110,7 +110,7 @@ HELP;
$this->dba = $dba;
}
protected function doExecute()
protected function doExecute(): int
{
// Initialise the app
$this->out("Initializing setup...");
@ -225,7 +225,7 @@ HELP;
$installer->resetChecks();
if (!$installer->installDatabase($basePathConf)) {
if (!$installer->installDatabase()) {
$errorMessage = $this->extractErrors($installer->getChecks());
throw new RuntimeException($errorMessage);
}

View File

@ -90,7 +90,7 @@ HELP;
$this->cache = $cache;
}
protected function doExecute()
protected function doExecute(): int
{
if ($this->getOption('v')) {
$this->out('Executable: ' . $this->executable);

View File

@ -102,7 +102,7 @@ HELP;
$this->config = $config;
}
protected function doExecute()
protected function doExecute(): int
{
if ($this->getOption('v')) {
$this->out('Executable: ' . $this->executable);

View File

@ -76,7 +76,7 @@ HELP;
$this->appMode = $appMode;
}
protected function doExecute()
protected function doExecute(): int
{
if ($this->getOption('v')) {
$this->out('Class: ' . __CLASS__);

View File

@ -45,7 +45,7 @@ HELP;
return $help;
}
protected function doExecute()
protected function doExecute(): int
{
if ($this->getOption('v')) {
$this->out('Class: ' . __CLASS__);

View File

@ -25,6 +25,12 @@ use Friendica\Core\Config\ValueObject\Cache;
use Friendica\Core\Update;
use Friendica\Database\Database;
use Friendica\Database\DBStructure;
use Friendica\Database\Definition\DbaDefinition;
use Friendica\Database\Definition\ViewDefinition;
use Friendica\Util\BasePath;
use Friendica\Util\Writer\DbaDefinitionSqlWriter;
use Friendica\Util\Writer\DocWriter;
use Friendica\Util\Writer\ViewDefinitionSqlWriter;
use RuntimeException;
/**
@ -34,15 +40,21 @@ class DatabaseStructure extends \Asika\SimpleConsole\Console
{
protected $helpOptions = ['h', 'help', '?'];
/**
* @var Database
*/
/** @var Database */
private $dba;
/**
* @var Cache
*/
/** @var Cache */
private $configCache;
/** @var DbaDefinition */
private $dbaDefinition;
/** @var ViewDefinition */
private $viewDefinition;
/** @var string */
private $basePath;
protected function getHelp()
{
$help = <<<HELP
@ -71,15 +83,18 @@ HELP;
return $help;
}
public function __construct(Database $dba, Cache $configCache, $argv = null)
public function __construct(Database $dba, DbaDefinition $dbaDefinition, ViewDefinition $viewDefinition, BasePath $basePath, Cache $configCache, $argv = null)
{
parent::__construct($argv);
$this->dba = $dba;
$this->dbaDefinition = $dbaDefinition;
$this->viewDefinition = $viewDefinition;
$this->configCache = $configCache;
$this->basePath = $basePath->getPath();
}
protected function doExecute()
protected function doExecute(): int
{
if ($this->getOption('v')) {
$this->out('Class: ' . __CLASS__);
@ -120,10 +135,9 @@ HELP;
$output = ob_get_clean();
break;
case "dumpsql":
DBStructure::writeStructure();
ob_start();
DBStructure::printStructure($basePath);
$output = ob_get_clean();
DocWriter::writeDbDefinition($this->dbaDefinition, $this->basePath);
$output = DbaDefinitionSqlWriter::create($this->dbaDefinition);
$output .= ViewDefinitionSqlWriter::create($this->viewDefinition);
break;
case "toinnodb":
ob_start();

View File

@ -71,7 +71,7 @@ HELP;
return $help;
}
protected function doExecute()
protected function doExecute(): int
{
if ($this->getOption('v')) {
$this->out('Class: ' . __CLASS__);

View File

@ -49,7 +49,7 @@ HELP;
return $help;
}
protected function doExecute()
protected function doExecute(): int
{
if ($this->getOption('v')) {
$this->out('Class: ' . __CLASS__);

View File

@ -85,7 +85,7 @@ HELP;
$this->l10n = $l10n;
}
protected function doExecute()
protected function doExecute(): int
{
if ($this->getOption('v')) {
$this->out('Class: ' . __CLASS__);

View File

@ -70,7 +70,7 @@ HELP;
$this->l10n = $l10n;
}
protected function doExecute()
protected function doExecute(): int
{
if ($this->getOption('v')) {
$this->out('Class: ' . __CLASS__);

View File

@ -75,7 +75,7 @@ HELP;
$this->dba =$dba;
}
protected function doExecute()
protected function doExecute(): int
{
if ($this->getOption('v')) {
$this->out('Class: ' . __CLASS__);

View File

@ -84,7 +84,7 @@ HELP;
$this->lock = $lock;
}
protected function doExecute()
protected function doExecute(): int
{
if ($this->getOption('v')) {
$this->out('Executable: ' . $this->executable);

View File

@ -77,7 +77,7 @@ HELP;
$this->config = $config;
}
protected function doExecute()
protected function doExecute(): int
{
if ($this->getOption('v')) {
$this->out('Class: ' . __CLASS__);

View File

@ -67,7 +67,7 @@ HELP;
$this->l10n = $l10n;
}
protected function doExecute()
protected function doExecute(): int
{
$duplicates = $this->dba->p("SELECT COUNT(*) AS `total`, `uri-id`, MAX(`url`) AS `url` FROM `contact` WHERE `uid` = 0 GROUP BY `uri-id` HAVING total > 1");
while ($duplicate = $this->dba->fetch($duplicates)) {

View File

@ -85,7 +85,7 @@ HELP;
$this->config = $config;
}
protected function doExecute()
protected function doExecute(): int
{
if (!$this->config->get('system', 'avatar_cache')) {
$this->err($this->l10n->t('The avatar cache needs to be enabled to use this command.'));

View File

@ -63,7 +63,7 @@ HELP;
return $help;
}
protected function doExecute()
protected function doExecute(): int
{
if ($this->getOption('v')) {
$this->out('Class: ' . __CLASS__);

View File

@ -50,7 +50,7 @@ HELP;
return $help;
}
protected function doExecute()
protected function doExecute(): int
{
if ($this->getOption('v')) {
$this->out('Class: ' . __CLASS__);

View File

@ -69,7 +69,7 @@ HELP;
$this->l10n = $l10n;
}
protected function doExecute()
protected function doExecute(): int
{
$a = \Friendica\DI::app();

View File

@ -76,7 +76,7 @@ HELP;
$this->dba = $dba;
}
protected function doExecute()
protected function doExecute(): int
{
if ($this->getOption('v')) {
$this->out('Executable: ' . $this->executable);

View File

@ -74,7 +74,7 @@ HELP;
$this->config = $config;
}
protected function doExecute()
protected function doExecute(): int
{
if (count($this->args) == 0) {
$this->out($this->getHelp());

View File

@ -79,7 +79,7 @@ HELP;
$this->config = $config;
}
protected function doExecute()
protected function doExecute(): int
{
if (count($this->args) == 0) {
$this->printBlockedServers($this->config);

View File

@ -69,7 +69,7 @@ HELP;
return $help;
}
protected function doExecute()
protected function doExecute(): int
{
if ($this->getOption('v')) {
$this->out('Executable: ' . $this->executable);

View File

@ -42,7 +42,7 @@ HELP;
return $help;
}
protected function doExecute()
protected function doExecute(): int
{
if ($this->getOption('v')) {
$this->out('Class: ' . __CLASS__);

View File

@ -60,7 +60,7 @@ HELP;
$this->config = $config;
}
protected function doExecute()
protected function doExecute(): int
{
if ($this->getOption('v')) {
$this->out('Class: ' . __CLASS__);

View File

@ -97,7 +97,7 @@ HELP;
$this->pConfig = $pConfig;
}
protected function doExecute()
protected function doExecute(): int
{
if ($this->getOption('v')) {
$this->out('Class: ' . __CLASS__);

View File

@ -123,7 +123,7 @@ class Avatar
return $fields;
}
private static function getFilename(string $url)
private static function getFilename(string $url): string
{
$guid = Item::guidFromUri($url, parse_url($url, PHP_URL_HOST));

View File

@ -52,7 +52,7 @@ class LocalRelationship extends BaseFactory implements ICanCreateFromTableRow
$row['hub-verify'] ?? '',
$row['protocol'] ?? Protocol::PHANTOM,
$row['rating'] ?? null,
$row['priority'] ?? null
$row['priority'] ?? 0
);
}
}

View File

@ -49,7 +49,7 @@ class BoundariesPager extends Pager
* @param string $last_item_id The id† of the last item in the displayed item list
* @param integer $itemsPerPage An optional number of items per page to override the default value
*/
public function __construct(L10n $l10n, $queryString, $first_item_id = null, $last_item_id = null, $itemsPerPage = 50)
public function __construct(L10n $l10n, string $queryString, string $first_item_id = null, string $last_item_id = null, int $itemsPerPage = 50)
{
parent::__construct($l10n, $queryString, $itemsPerPage);
@ -73,12 +73,12 @@ class BoundariesPager extends Pager
}
}
public function getStart()
public function getStart(): int
{
throw new \BadMethodCallException();
}
public function getPage()
public function getPage(): int
{
throw new \BadMethodCallException();
}
@ -102,7 +102,7 @@ class BoundariesPager extends Pager
* @return string HTML string of the pager
* @throws \Exception
*/
public function renderMinimal(int $itemCount)
public function renderMinimal(int $itemCount): string
{
$displayedItemCount = max(0, intval($itemCount));
@ -130,7 +130,10 @@ class BoundariesPager extends Pager
return Renderer::replaceMacros($tpl, ['pager' => $data]);
}
public function renderFull($itemCount)
/**
* Unsupported method, must be type-compatible
*/
public function renderFull(int $itemCount): string
{
throw new \BadMethodCallException();
}

View File

@ -41,7 +41,7 @@ class ContactSelector
* @param boolean $disabled optional, default false
* @return string
*/
public static function pollInterval($current, $disabled = false)
public static function pollInterval(string $current, bool $disabled = false): string
{
$dis = (($disabled) ? ' disabled="disabled" ' : '');
$o = '';
@ -84,7 +84,7 @@ class ContactSelector
* @return string Server URL
* @throws \Exception
*/
private static function getServerURLForProfile($profile)
private static function getServerURLForProfile(string $profile): string
{
if (!empty(self::$server_url[$profile])) {
return self::$server_url[$profile];
@ -111,13 +111,16 @@ class ContactSelector
}
/**
* Determines network name
*
* @param string $network network of the contact
* @param string $profile optional, default empty
* @param string $protocol (Optional) Protocol that is used for the transmission
* @param int $gsid Server id
* @return string
* @throws \Friendica\Network\HTTPException\InternalServerErrorException
*/
public static function networkToName($network, $profile = '', $protocol = '', $gsid = 0)
public static function networkToName(string $network, string $profile = '', string $protocol = '', int $gsid = null): string
{
$nets = [
Protocol::DFRN => DI::l10n()->t('DFRN'),
@ -179,12 +182,15 @@ class ContactSelector
}
/**
* Determines network's icon name
*
* @param string $network network
* @param string $profile optional, default empty
* @return string
* @param int $gsid Server id
* @return string Name for network icon
* @throws \Exception
*/
public static function networkToIcon($network, $profile = "", $gsid = 0)
public static function networkToIcon(string $network, string $profile = "", int $gsid = null): string
{
$nets = [
Protocol::DFRN => 'friendica',

View File

@ -154,7 +154,7 @@ class Conversation
}
// Skip when the causer of the parent is the same as the author of the announce
if (($verb == Activity::ANNOUNCE) && !empty($thread_parent['causer-id'] && ($thread_parent['causer-id'] == $activity['author-id']))) {
if (($verb == Activity::ANNOUNCE) && !empty($thread_parent['causer-id']) && ($thread_parent['causer-id'] == $activity['author-id'])) {
continue;
}
@ -189,7 +189,7 @@ class Conversation
* @return string formatted text
* @throws \Friendica\Network\HTTPException\InternalServerErrorException
*/
public function formatActivity(array $links, $verb, $id)
public function formatActivity(array $links, string $verb, int $id): string
{
$this->profiler->startRecording('rendering');
$o = '';
@ -275,7 +275,7 @@ class Conversation
return $o;
}
public function statusEditor(array $x = [], $notes_cid = 0, $popup = false)
public function statusEditor(array $x = [], int $notes_cid = 0, bool $popup = false): string
{
$user = User::getById($this->app->getLoggedInUserId(), ['uid', 'nickname', 'allow_location', 'default-location']);
if (empty($user['uid'])) {
@ -414,8 +414,8 @@ class Conversation
* figures out how to determine page owner and other contextual items
* that are based on unique features of the calling module.
* @param array $items
* @param $mode
* @param $update
* @param string $mode
* @param $update @TODO Which type?
* @param bool $preview
* @param string $order
* @param int $uid
@ -423,7 +423,7 @@ class Conversation
* @throws ImagickException
* @throws \Friendica\Network\HTTPException\InternalServerErrorException
*/
public function create(array $items, $mode, $update, $preview = false, $order = 'commented', $uid = 0)
public function create(array $items, string $mode, $update, bool $preview = false, string $order = 'commented', int $uid = 0): string
{
$this->profiler->startRecording('rendering');
@ -582,7 +582,7 @@ class Conversation
$uriids[] = $item['uri-id'];
if (!$this->item->visibleActivity($item)) {
if (!$this->item->isVisibleActivity($item)) {
continue;
}
@ -745,7 +745,7 @@ class Conversation
continue;
}
if (!$this->item->visibleActivity($item)) {
if (!$this->item->isVisibleActivity($item)) {
continue;
}
@ -784,7 +784,7 @@ class Conversation
return $o;
}
private function getBlocklist()
private function getBlocklist(): array
{
if (!local_user()) {
return [];
@ -816,7 +816,7 @@ class Conversation
*
* @return array items with parents and comments
*/
private function addRowInformation(array $row, array $activity, array $thr_parent)
private function addRowInformation(array $row, array $activity, array $thr_parent): array
{
$this->profiler->startRecording('rendering');
@ -911,7 +911,7 @@ class Conversation
* @return array items with parents and comments
* @throws \Friendica\Network\HTTPException\InternalServerErrorException
*/
private function addChildren(array $parents, bool $block_authors, string $order, int $uid, string $mode)
private function addChildren(array $parents, bool $block_authors, string $order, int $uid, string $mode): array
{
$this->profiler->startRecording('rendering');
if (count($parents) > 1) {
@ -1005,7 +1005,7 @@ class Conversation
* @param bool $recursive
* @return array
*/
private function getItemChildren(array &$item_list, array $parent, $recursive = true)
private function getItemChildren(array &$item_list, array $parent, bool $recursive = true): array
{
$this->profiler->startRecording('rendering');
$children = [];
@ -1040,7 +1040,7 @@ class Conversation
* @param array $items
* @return array
*/
private function sortItemChildren(array $items)
private function sortItemChildren(array $items): array
{
$this->profiler->startRecording('rendering');
$result = $items;
@ -1086,7 +1086,7 @@ class Conversation
* @param array $parent A tree-like array of items
* @return array
*/
private function smartFlattenConversation(array $parent)
private function smartFlattenConversation(array $parent): array
{
$this->profiler->startRecording('rendering');
if (!isset($parent['children']) || count($parent['children']) == 0) {
@ -1142,7 +1142,7 @@ class Conversation
* @return array
* @throws \Friendica\Network\HTTPException\InternalServerErrorException
*/
private function convSort(array $item_list, $order)
private function convSort(array $item_list, string $order): array
{
$this->profiler->startRecording('rendering');
$parents = [];
@ -1222,7 +1222,7 @@ class Conversation
* @param array $b
* @return int
*/
private function sortThrFeaturedReceived(array $a, array $b)
private function sortThrFeaturedReceived(array $a, array $b): int
{
if ($b['featured'] && !$a['featured']) {
return 1;
@ -1240,7 +1240,7 @@ class Conversation
* @param array $b
* @return int
*/
private function sortThrFeaturedCommented(array $a, array $b)
private function sortThrFeaturedCommented(array $a, array $b): int
{
if ($b['featured'] && !$a['featured']) {
return 1;
@ -1258,7 +1258,7 @@ class Conversation
* @param array $b
* @return int
*/
private function sortThrReceived(array $a, array $b)
private function sortThrReceived(array $a, array $b): int
{
return strcmp($b['received'], $a['received']);
}
@ -1270,7 +1270,7 @@ class Conversation
* @param array $b
* @return int
*/
private function sortThrReceivedRev(array $a, array $b)
private function sortThrReceivedRev(array $a, array $b): int
{
return strcmp($a['received'], $b['received']);
}
@ -1282,7 +1282,7 @@ class Conversation
* @param array $b
* @return int
*/
private function sortThrCommented(array $a, array $b)
private function sortThrCommented(array $a, array $b): int
{
return strcmp($b['commented'], $a['commented']);
}
@ -1294,7 +1294,7 @@ class Conversation
* @param array $b
* @return int
*/
private function sortThrCreated(array $a, array $b)
private function sortThrCreated(array $a, array $b): int
{
return strcmp($b['created'], $a['created']);
}

View File

@ -85,7 +85,7 @@ class Item
* ]
* ]
*/
public function determineCategoriesTerms(array $item, int $uid = 0)
public function determineCategoriesTerms(array $item, int $uid = 0): array
{
$categories = [];
$folders = [];
@ -142,15 +142,15 @@ class Item
* the appropriate link.
*
* @param string $body the text to replace the tag in
* @param integer $profile_uid the user id to replace the tag for (0 = anyone)
* @param int $profile_uid the user id to replace the tag for (0 = anyone)
* @param string $tag the tag to replace
* @param string $network The network of the post
*
* @return array|bool ['replaced' => $replaced, 'contact' => $contact];
* @return array|bool ['replaced' => $replaced, 'contact' => $contact] or "false" on if already replaced
* @throws \Friendica\Network\HTTPException\InternalServerErrorException
* @throws \ImagickException
*/
public static function replaceTag(&$body, $profile_uid, $tag, $network = '')
public static function replaceTag(string &$body, int $profile_uid, string $tag, string $network = '')
{
$replaced = false;
@ -244,16 +244,17 @@ class Item
/**
* Render actions localized
*
* @param $item
* @param array $item
* @return void
* @throws ImagickException
* @throws \Friendica\Network\HTTPException\InternalServerErrorException
*/
public function localize(&$item)
public function localize(array &$item)
{
$this->profiler->startRecording('rendering');
/// @todo The following functionality needs to be cleaned up.
if (!empty($item['verb'])) {
$xmlhead = "<" . "?xml version='1.0' encoding='UTF-8' ?" . ">";
$xmlhead = '<?xml version="1.0" encoding="UTF-8" ?>';
if (stristr($item['verb'], Activity::POKE)) {
$verb = urldecode(substr($item['verb'], strpos($item['verb'],'#') + 1));
@ -261,7 +262,7 @@ class Item
$this->profiler->stopRecording();
return;
}
if ($item['object-type'] == "" || $item['object-type'] !== Activity\ObjectType::PERSON) {
if ($item['object-type'] == '' || $item['object-type'] !== Activity\ObjectType::PERSON) {
$this->profiler->stopRecording();
return;
}
@ -270,18 +271,22 @@ class Item
$Bname = $obj->title;
$Blink = $obj->id;
$Bphoto = "";
$Bphoto = '';
foreach ($obj->link as $l) {
$atts = $l->attributes();
switch ($atts['rel']) {
case "alternate": $Blink = $atts['href'];
case "photo": $Bphoto = $atts['href'];
case 'alternate': $Blink = $atts['href'];
case 'photo': $Bphoto = $atts['href'];
}
}
$author = ['uid' => 0, 'id' => $item['author-id'],
'network' => $item['author-network'], 'url' => $item['author-link']];
$author = [
'uid' => 0,
'id' => $item['author-id'],
'network' => $item['author-network'],
'url' => $item['author-link'],
];
$A = '[url=' . Contact::magicLinkByContact($author) . ']' . $item['author-name'] . '[/url]';
if (!empty($Blink)) {
@ -290,7 +295,7 @@ class Item
$B = '';
}
if ($Bphoto != "" && !empty($Blink)) {
if ($Bphoto != '' && !empty($Blink)) {
$Bphoto = '[url=' . Contact::magicLink($Blink) . '][img=80x80]' . $Bphoto . '[/img][/url]';
}
@ -305,9 +310,7 @@ class Item
$txt = str_replace($poked_t, $this->l10n->t($verb), $txt);
// then do the sprintf on the translation string
$item['body'] = sprintf($txt, $A, $B) . "\n\n\n" . $Bphoto;
}
if ($this->activity->match($item['verb'], Activity::TAG)) {
@ -319,12 +322,20 @@ class Item
return;
}
$author_arr = ['uid' => 0, 'id' => $item['author-id'],
'network' => $item['author-network'], 'url' => $item['author-link']];
$author_arr = [
'uid' => 0,
'id' => $item['author-id'],
'network' => $item['author-network'],
'url' => $item['author-link'],
];
$author = '[url=' . Contact::magicLinkByContact($author_arr) . ']' . $item['author-name'] . '[/url]';
$author_arr = ['uid' => 0, 'id' => $obj['author-id'],
'network' => $obj['author-network'], 'url' => $obj['author-link']];
$author_arr = [
'uid' => 0,
'id' => $obj['author-id'],
'network' => $obj['author-network'],
'url' => $obj['author-link'],
];
$objauthor = '[url=' . Contact::magicLinkByContact($author_arr) . ']' . $obj['author-name'] . '[/url]';
switch ($obj['verb']) {
@ -337,6 +348,7 @@ class Item
$post_type = $this->l10n->t('status');
}
break;
default:
if ($obj['resource-id']) {
$post_type = $this->l10n->t('photo');
@ -360,25 +372,29 @@ class Item
$this->profiler->stopRecording();
}
public function photoMenu($item, string $formSecurityToken)
/**
* Renders photo menu based on item
*
* @param array $item
* @param string $formSecurityToken
* @return string
*/
public function photoMenu(array $item, string $formSecurityToken): string
{
$this->profiler->startRecording('rendering');
$sub_link = '';
$poke_link = '';
$contact_url = '';
$pm_url = '';
$status_link = '';
$photos_link = '';
$posts_link = '';
$block_link = '';
$ignore_link = '';
$sub_link = $poke_link = $contact_url = $pm_url = $status_link = '';
$photos_link = $posts_link = $block_link = $ignore_link = '';
if (local_user() && local_user() == $item['uid'] && $item['gravity'] == GRAVITY_PARENT && !$item['self'] && !$item['mention']) {
$sub_link = 'javascript:doFollowThread(' . $item['id'] . '); return false;';
}
$author = ['uid' => 0, 'id' => $item['author-id'],
'network' => $item['author-network'], 'url' => $item['author-link']];
$author = [
'uid' => 0,
'id' => $item['author-id'],
'network' => $item['author-network'],
'url' => $item['author-link'],
];
$profile_link = Contact::magicLinkByContact($author, $item['author-link']);
$sparkle = (strpos($profile_link, 'redir/') === 0);
@ -435,7 +451,7 @@ class Item
}
if ($network == Protocol::DFRN) {
$menu[$this->l10n->t("Poke")] = $poke_link;
$menu[$this->l10n->t('Poke')] = $poke_link;
}
if ((($cid == 0) || ($rel == Contact::FOLLOWER)) &&
@ -465,24 +481,28 @@ class Item
return $o;
}
public function visibleActivity($item) {
/**
* Checks if the activity is visible to current user
*
* @param array $item Activity item
* @return bool Whether the item is visible to the user
*/
public function isVisibleActivity(array $item): bool
{
// Empty verb or hidden?
if (empty($item['verb']) || $this->activity->isHidden($item['verb'])) {
return false;
}
// @TODO below if() block can be rewritten to a single line: $isVisible = allConditionsHere;
if ($this->activity->match($item['verb'], Activity::FOLLOW) &&
// Check conditions
return (!($this->activity->match($item['verb'], Activity::FOLLOW) &&
$item['object-type'] === Activity\ObjectType::NOTE &&
empty($item['self']) &&
$item['uid'] == local_user()) {
return false;
$item['uid'] == local_user())
);
}
return true;
}
public function expandTags(array $item, bool $setPermissions = false)
public function expandTags(array $item, bool $setPermissions = false): array
{
// Look for any tags and linkify them
$item['inform'] = '';

View File

@ -62,7 +62,7 @@ class Nav
*
* @param string $item
*/
public static function setSelected($item)
public static function setSelected(string $item)
{
self::$selected[$item] = 'selected';
}
@ -74,7 +74,7 @@ class Nav
* @return string
* @throws \Friendica\Network\HTTPException\InternalServerErrorException
*/
public static function build(App $a)
public static function build(App $a): string
{
// Placeholder div for popup panel
$nav = '<div id="panel" style="display: none;"></div>';
@ -106,7 +106,7 @@ class Nav
*
* @return array
*/
public static function getAppMenu()
public static function getAppMenu(): array
{
if (is_null(self::$app_menu)) {
self::populateAppMenu();
@ -117,6 +117,8 @@ class Nav
/**
* Fills the apps static variable with apps that require a menu
*
* @return void
*/
private static function populateAppMenu()
{

View File

@ -49,7 +49,13 @@ use Friendica\Util\Strings;
*/
class OEmbed
{
public static function replaceCallback($matches)
/**
* Callback for fetching URL, checking allowance and returning formatted HTML
*
* @param array $matches
* @return string Formatted HTML
*/
public static function replaceCallback(array $matches): string
{
$embedurl = $matches[1];
$j = self::fetchURL($embedurl, !self::isAllowedURL($embedurl));
@ -68,7 +74,7 @@ class OEmbed
* @return \Friendica\Object\OEmbed
* @throws \Friendica\Network\HTTPException\InternalServerErrorException
*/
public static function fetchURL($embedurl, bool $no_rich_type = false, bool $use_parseurl = true)
public static function fetchURL(string $embedurl, bool $no_rich_type = false, bool $use_parseurl = true): \Friendica\Object\OEmbed
{
$embedurl = trim($embedurl, '\'"');
@ -209,12 +215,18 @@ class OEmbed
return $oembed;
}
private static function formatObject(\Friendica\Object\OEmbed $oembed)
/**
* Returns a formatted string from OEmbed object
*
* @param \Friendica\Object\OEmbed $oembed
* @return string
*/
private static function formatObject(\Friendica\Object\OEmbed $oembed): string
{
$ret = '<div class="oembed ' . $oembed->type . '">';
switch ($oembed->type) {
case "video":
case 'video':
if ($oembed->thumbnail_url) {
$tw = (isset($oembed->thumbnail_width) && intval($oembed->thumbnail_width)) ? $oembed->thumbnail_width : 200;
$th = (isset($oembed->thumbnail_height) && intval($oembed->thumbnail_height)) ? $oembed->thumbnail_height : 180;
@ -236,14 +248,14 @@ class OEmbed
}
break;
case "photo":
case 'photo':
$ret .= '<img width="' . $oembed->width . '" src="' . Proxy::proxifyUrl($oembed->url) . '">';
break;
case "link":
case 'link':
break;
case "rich":
case 'rich':
$ret .= Proxy::proxifyHtml($oembed->html);
break;
}
@ -292,9 +304,15 @@ class OEmbed
return str_replace("\n", "", $ret);
}
public static function BBCode2HTML($text)
/**
* Converts BBCode to HTML code
*
* @param string $text
* @return string
*/
public static function BBCode2HTML(string $text): string
{
$stopoembed = DI::config()->get("system", "no_oembed");
$stopoembed = DI::config()->get('system', 'no_oembed');
if ($stopoembed == true) {
return preg_replace("/\[embed\](.+?)\[\/embed\]/is", "<!-- oembed $1 --><i>" . DI::l10n()->t('Embedding disabled') . " : $1</i><!-- /oembed $1 -->", $text);
}
@ -305,14 +323,13 @@ class OEmbed
* Find <span class='oembed'>..<a href='url' rel='oembed'>..</a></span>
* and replace it with [embed]url[/embed]
*
* @param $text
* @param string $text
* @return string
*/
public static function HTML2BBCode($text)
public static function HTML2BBCode(string $text): string
{
// start parser only if 'oembed' is in text
if (strpos($text, "oembed")) {
if (strpos($text, 'oembed')) {
// convert non ascii chars to html entities
$html_text = mb_convert_encoding($text, 'HTML-ENTITIES', mb_detect_encoding($text));
@ -323,17 +340,17 @@ class OEmbed
}
$xpath = new DOMXPath($dom);
$xattr = self::buildXPath("class", "oembed");
$xattr = self::buildXPath('class', 'oembed');
$entries = $xpath->query("//div[$xattr]");
$xattr = "@rel='oembed'"; //oe_build_xpath("rel","oembed");
foreach ($entries as $e) {
$href = $xpath->evaluate("a[$xattr]/@href", $e)->item(0)->nodeValue;
if (!is_null($href)) {
$e->parentNode->replaceChild(new DOMText("[embed]" . $href . "[/embed]"), $e);
$e->parentNode->replaceChild(new DOMText('[embed]' . $href . '[/embed]'), $e);
}
}
return self::getInnerHTML($dom->getElementsByTagName("body")->item(0));
return self::getInnerHTML($dom->getElementsByTagName('body')->item(0));
} else {
return $text;
}
@ -346,7 +363,7 @@ class OEmbed
* @return boolean
* @throws \Friendica\Network\HTTPException\InternalServerErrorException
*/
public static function isAllowedURL($url)
public static function isAllowedURL(string $url): bool
{
if (!DI::config()->get('system', 'no_oembed_rich_content')) {
return true;
@ -367,7 +384,14 @@ class OEmbed
return Network::isDomainAllowed($domain, $allowed);
}
public static function getHTML($url, $title = null)
/**
* Returns a formmated HTML code from given URL and sets optional title
*
* @param string $url URL to fetch
* @param string $title Optional title (default: what comes from OEmbed object)
* @return string Formatted HTML
*/
public static function getHTML(string $url, string $title = '')
{
$o = self::fetchURL($url, !self::isAllowedURL($url));
@ -401,12 +425,12 @@ class OEmbed
* @param string $src Original remote URL to embed
* @param string $width
* @param string $height
* @return string formatted HTML
* @return string Formatted HTML
*
* @throws \Friendica\Network\HTTPException\InternalServerErrorException
* @see oembed_format_object()
*/
private static function iframe($src, $width, $height)
private static function iframe(string $src, string $width, string $height): string
{
if (!$height || strstr($height, '%')) {
$height = '200';
@ -427,7 +451,7 @@ class OEmbed
* @param string $value Value to search in a space-separated list
* @return string
*/
private static function buildXPath($attr, $value)
private static function buildXPath(string $attr, $value): string
{
// https://www.westhoffswelt.de/blog/2009/6/9/select-html-elements-with-more-than-one-css-class-using-xpath
return "contains(normalize-space(@$attr), ' $value ') or substring(normalize-space(@$attr), 1, string-length('$value') + 1) = '$value ' or substring(normalize-space(@$attr), string-length(@$attr) - string-length('$value')) = ' $value' or @$attr = '$value'";
@ -439,7 +463,7 @@ class OEmbed
* @param DOMNode $node
* @return string
*/
private static function getInnerHTML(DOMNode $node)
private static function getInnerHTML(DOMNode $node): string
{
$innerHTML = '';
$children = $node->childNodes;

View File

@ -64,7 +64,7 @@ class PageInfo
* @return string
* @throws HTTPException\InternalServerErrorException
*/
public static function appendDataToBody(string $body, array $data, bool $no_photos = false)
public static function appendDataToBody(string $body, array $data, bool $no_photos = false): string
{
// Only one [attachment] tag per body is allowed
$existingAttachmentPos = strpos($body, '[attachment');
@ -90,7 +90,7 @@ class PageInfo
* @return string
* @throws HTTPException\InternalServerErrorException
*/
public static function getFooterFromUrl(string $url, bool $no_photos = false, string $photo = '', bool $keywords = false, string $keyword_denylist = '')
public static function getFooterFromUrl(string $url, bool $no_photos = false, string $photo = '', bool $keywords = false, string $keyword_denylist = ''): string
{
$data = self::queryUrl($url, $photo, $keywords, $keyword_denylist);
@ -103,7 +103,7 @@ class PageInfo
* @return string
* @throws HTTPException\InternalServerErrorException
*/
public static function getFooterFromData(array $data, bool $no_photos = false)
public static function getFooterFromData(array $data, bool $no_photos = false): string
{
Hook::callAll('page_info_data', $data);
@ -220,7 +220,7 @@ class PageInfo
* @return array
* @throws HTTPException\InternalServerErrorException
*/
public static function getTagsFromUrl(string $url, string $photo = '', string $keyword_denylist = '')
public static function getTagsFromUrl(string $url, string $photo = '', string $keyword_denylist = ''): array
{
$data = self::queryUrl($url, $photo, true, $keyword_denylist);
@ -282,7 +282,7 @@ class PageInfo
* @param string $url
* @return string
*/
protected static function stripTrailingUrlFromBody(string $body, string $url)
protected static function stripTrailingUrlFromBody(string $body, string $url): string
{
$quotedUrl = preg_quote($url, '#');
$body = preg_replace_callback("#(?:

View File

@ -50,9 +50,9 @@ class Pager
*
* @param L10n $l10n
* @param string $queryString The query string of the current page
* @param integer $itemsPerPage An optional number of items per page to override the default value
* @param int $itemsPerPage An optional number of items per page to override the default value
*/
public function __construct(L10n $l10n, $queryString, $itemsPerPage = 50)
public function __construct(L10n $l10n, string $queryString, int $itemsPerPage = 50)
{
$this->l10n = $l10n;
@ -64,9 +64,9 @@ class Pager
/**
* Returns the start offset for a LIMIT clause. Starts at 0.
*
* @return integer
* @return int
*/
public function getStart()
public function getStart(): int
{
return max(0, ($this->page * $this->itemsPerPage) - $this->itemsPerPage);
}
@ -74,9 +74,9 @@ class Pager
/**
* Returns the number of items per page
*
* @return integer
* @return int
*/
public function getItemsPerPage()
public function getItemsPerPage(): int
{
return $this->itemsPerPage;
}
@ -86,7 +86,7 @@ class Pager
*
* @return int
*/
public function getPage()
public function getPage(): int
{
return $this->page;
}
@ -108,9 +108,9 @@ class Pager
/**
* Sets the number of items per page, 1 minimum.
*
* @param integer $itemsPerPage
* @param int $itemsPerPage
*/
public function setItemsPerPage($itemsPerPage)
public function setItemsPerPage(int $itemsPerPage)
{
$this->itemsPerPage = max(1, intval($itemsPerPage));
}
@ -118,11 +118,11 @@ class Pager
/**
* Sets the current page number. Starts at 1.
*
* @param integer $page
* @param int $page
*/
public function setPage($page)
public function setPage(int $page)
{
$this->page = max(1, intval($page));
$this->page = max(1, $page);
}
/**
@ -132,7 +132,7 @@ class Pager
*
* @param string $queryString
*/
public function setQueryString($queryString)
public function setQueryString(string $queryString)
{
$stripped = preg_replace('/([&?]page=[0-9]*)/', '', $queryString);
@ -160,7 +160,7 @@ class Pager
* @return string HTML string of the pager
* @throws \Exception
*/
public function renderMinimal(int $itemCount)
public function renderMinimal(int $itemCount): string
{
$displayedItemCount = max(0, intval($itemCount));
@ -199,13 +199,13 @@ class Pager
*
* $html = $pager->renderFull();
*
* @param integer $itemCount The total number of items including those note displayed on the page
* @param int $itemCount The total number of items including those note displayed on the page
* @return string HTML string of the pager
* @throws \Friendica\Network\HTTPException\InternalServerErrorException
*/
public function renderFull($itemCount)
public function renderFull(int $itemCount): string
{
$totalItemCount = max(0, intval($itemCount));
$totalItemCount = max(0, $itemCount);
$data = [];

View File

@ -39,10 +39,9 @@ class Smilies
* @param array $b Array of emoticons
* @param string $smiley The text smilie
* @param string $representation The replacement
*
* @return void
*/
public static function add(&$b, $smiley, $representation)
public static function add(array &$b, string $smiley, string $representation)
{
$found = array_search($smiley, $b['texts']);
@ -66,7 +65,7 @@ class Smilies
* @throws \Friendica\Network\HTTPException\InternalServerErrorException
* @hook smilie ('texts' => smilies texts array, 'icons' => smilies html array)
*/
public static function getList()
public static function getList(): array
{
$texts = [
'&lt;3',
@ -169,7 +168,7 @@ class Smilies
*
* @return string $subject with all substrings in the $search array replaced by the values in the $replace array
*/
private static function strOrigReplace($search, $replace, $subject)
private static function strOrigReplace(array $search, array $replace, string $subject): string
{
return strtr($subject, array_combine($search, $replace));
}
@ -191,7 +190,7 @@ class Smilies
* @return string HTML Output of the Smilie
* @throws \Friendica\Network\HTTPException\InternalServerErrorException
*/
public static function replace($s, $no_images = false)
public static function replace(string $s, bool $no_images = false): string
{
$smilies = self::getList();
@ -211,7 +210,7 @@ class Smilies
* @return string
* @throws \Friendica\Network\HTTPException\InternalServerErrorException
*/
public static function replaceFromArray($text, array $smilies, $no_images = false)
public static function replaceFromArray(string $text, array $smilies, bool $no_images = false): string
{
if (intval(DI::config()->get('system', 'no_smilies'))
|| (local_user() && intval(DI::pConfig()->get(local_user(), 'system', 'no_smilies')))
@ -234,7 +233,7 @@ class Smilies
$smilies = $cleaned;
}
$text = preg_replace_callback('/&lt;(3+)/', 'self::pregHeart', $text);
$text = preg_replace_callback('/&lt;(3+)/', 'self::heartReplaceCallback', $text);
$text = self::strOrigReplace($smilies['texts'], $smilies['icons'], $text);
$text = preg_replace_callback('/<(code)>(.*?)<\/code>/ism', 'self::decode', $text);
@ -244,22 +243,24 @@ class Smilies
}
/**
* @param string $m string
* Encodes smiley match array to BASE64 string
*
* @param array $m Match array
* @return string base64 encoded string
*/
private static function encode($m)
private static function encode(array $m): string
{
return '<' . $m[1] . '>' . Strings::base64UrlEncode($m[2]) . '</' . $m[1] . '>';
}
/**
* @param string $m string
* Decodes a previously BASE64-encoded match array to a string
*
* @param array $m Matches array
* @return string base64 decoded string
* @throws \Exception
*/
private static function decode($m)
private static function decode(array $m): string
{
return '<' . $m[1] . '>' . Strings::base64UrlDecode($m[2]) . '</' . $m[1] . '>';
}
@ -268,24 +269,20 @@ class Smilies
/**
* expand <3333 to the correct number of hearts
*
* @param string $x string
*
* @param array $matches
* @return string HTML Output
*
* @throws \Friendica\Network\HTTPException\InternalServerErrorException
*/
private static function pregHeart($x)
private static function heartReplaceCallback(array $matches): string
{
if (strlen($x[1]) == 1) {
return $x[0];
if (strlen($matches[1]) == 1) {
return $matches[0];
}
$t = '';
for ($cnt = 0; $cnt < strlen($x[1]); $cnt ++) {
for ($cnt = 0; $cnt < strlen($matches[1]); $cnt ++) {
$t .= '❤';
}
$r = str_replace($x[0], $t, $x[0]);
return $r;
return str_replace($matches[0], $t, $matches[0]);
}
}

View File

@ -81,7 +81,7 @@ class BBCode
* 'description' -> Description of the attachment
* @throws \Friendica\Network\HTTPException\InternalServerErrorException
*/
private static function getOldAttachmentData($body)
private static function getOldAttachmentData(string $body): array
{
$post = [];
@ -152,7 +152,7 @@ class BBCode
* 'description' -> Description of the attachment
* @throws \Friendica\Network\HTTPException\InternalServerErrorException
*/
public static function getAttachmentData($body)
public static function getAttachmentData(string $body): array
{
DI::profiler()->startRecording('rendering');
$data = [
@ -187,26 +187,31 @@ class BBCode
case 'publisher_name':
$data['provider_name'] = html_entity_decode($value, ENT_QUOTES, 'UTF-8');
break;
case 'publisher_url':
$data['provider_url'] = html_entity_decode($value, ENT_QUOTES, 'UTF-8');
break;
case 'author_name':
$data['author_name'] = html_entity_decode($value, ENT_QUOTES, 'UTF-8');
if ($data['provider_name'] == $data['author_name']) {
$data['author_name'] = '';
}
break;
case 'author_url':
$data['author_url'] = html_entity_decode($value, ENT_QUOTES, 'UTF-8');
if ($data['provider_url'] == $data['author_url']) {
$data['author_url'] = '';
}
break;
case 'title':
$value = self::convert(html_entity_decode($value, ENT_QUOTES, 'UTF-8'), false, true);
$value = html_entity_decode($value, ENT_QUOTES, 'UTF-8');
$value = str_replace(['[', ']'], ['&#91;', '&#93;'], $value);
$data['title'] = $value;
default:
$data[$field] = html_entity_decode($value, ENT_QUOTES, 'UTF-8');
break;
@ -241,7 +246,7 @@ class BBCode
return $data;
}
public static function getAttachedData($body, $item = [])
public static function getAttachedData(string $body, array $item = []): array
{
/*
- text:
@ -303,7 +308,7 @@ class BBCode
// Workaround:
// Sometimes photo posts to the own album are not detected at the start.
// So we seem to cannot use the cache for these cases. That's strange.
if (($data['type'] != 'photo') && strstr($pictures[0][1], "/photos/")) {
if (($data['type'] != 'photo') && strstr($pictures[0][1], '/photos/')) {
$data = ParseUrl::getSiteinfo($pictures[0][1]);
}
@ -320,7 +325,7 @@ class BBCode
$post['text'] = trim(str_replace($pictures[0][0], '', $body));
} else {
$imgdata = Images::getInfoFromURLCached($pictures[0][1]);
if ($imgdata && substr($imgdata['mime'], 0, 6) == 'image/') {
if (($imgdata) && substr($imgdata['mime'], 0, 6) == 'image/') {
$post['type'] = 'photo';
$post['image'] = $pictures[0][1];
$post['preview'] = $pictures[0][2];
@ -390,7 +395,7 @@ class BBCode
}
if (!isset($post['type'])) {
$post['type'] = "text";
$post['type'] = 'text';
$post['text'] = trim($body);
}
@ -419,10 +424,9 @@ class BBCode
*
* @param string $body
* @param boolean $no_link_desc No link description
*
* @return string with replaced body
*/
public static function removeAttachment($body, $no_link_desc = false)
public static function removeAttachment(string $body, bool $no_link_desc = false): string
{
return preg_replace_callback("/\s*\[attachment (.*?)\](.*?)\[\/attachment\]\s*/ism",
function ($match) use ($body, $no_link_desc) {
@ -442,12 +446,11 @@ class BBCode
/**
* Converts a BBCode text into plaintext
*
* @param $text
* @param string $text
* @param bool $keep_urls Whether to keep URLs in the resulting plaintext
*
* @return string
*/
public static function toPlaintext($text, $keep_urls = true)
public static function toPlaintext(string $text, bool $keep_urls = true): string
{
DI::profiler()->startRecording('rendering');
// Remove pictures in advance to avoid unneeded proxy calls
@ -463,7 +466,7 @@ class BBCode
return $naked_text;
}
private static function proxyUrl($image, $simplehtml = self::INTERNAL, $uriid = 0, $size = '')
private static function proxyUrl(string $image, int $simplehtml = self::INTERNAL, int $uriid = 0, string $size = ''): string
{
// Only send proxied pictures to API and for internal display
if (!in_array($simplehtml, [self::INTERNAL, self::API])) {
@ -483,7 +486,7 @@ class BBCode
* @param string $srctext The body with images
* @return string The body with possibly scaled images
*/
public static function scaleExternalImages(string $srctext)
public static function scaleExternalImages(string $srctext): string
{
DI::profiler()->startRecording('rendering');
$s = $srctext;
@ -551,7 +554,7 @@ class BBCode
* @return string
* @throws \Friendica\Network\HTTPException\InternalServerErrorException
*/
public static function limitBodySize($body)
public static function limitBodySize(string $body): string
{
DI::profiler()->startRecording('rendering');
$maxlen = DI::config()->get('config', 'max_import_size', 0);
@ -646,7 +649,7 @@ class BBCode
* @return string
* @throws \Friendica\Network\HTTPException\InternalServerErrorException
*/
public static function convertAttachment($text, $simplehtml = self::INTERNAL, $tryoembed = true, array $data = [], $uriid = 0)
public static function convertAttachment(string $text, int $simplehtml = self::INTERNAL, bool $tryoembed = true, array $data = [], int $uriid = 0): string
{
DI::profiler()->startRecording('rendering');
$data = $data ?: self::getAttachmentData($text);
@ -659,10 +662,10 @@ class BBCode
$data['title'] = strip_tags($data['title']);
$data['title'] = str_replace(['http://', 'https://'], '', $data['title']);
} else {
$data['title'] = null;
$data['title'] = '';
}
if (((strpos($data['text'], "[img=") !== false) || (strpos($data['text'], "[img]") !== false) || DI::config()->get('system', 'always_show_preview')) && !empty($data['image'])) {
if (((strpos($data['text'], '[img=') !== false) || (strpos($data['text'], '[img]') !== false) || DI::config()->get('system', 'always_show_preview')) && !empty($data['image'])) {
$data['preview'] = $data['image'];
$data['image'] = '';
}
@ -716,14 +719,14 @@ class BBCode
return trim(($data['text'] ?? '') . ' ' . $return . ' ' . ($data['after'] ?? ''));
}
public static function removeShareInformation($Text, $plaintext = false, $nolink = false)
public static function removeShareInformation(string $text, bool $plaintext = false, bool $nolink = false): string
{
DI::profiler()->startRecording('rendering');
$data = self::getAttachmentData($Text);
$data = self::getAttachmentData($text);
if (!$data) {
DI::profiler()->stopRecording();
return $Text;
return $text;
} elseif ($nolink) {
DI::profiler()->stopRecording();
return $data['text'] . ($data['after'] ?? '');
@ -767,7 +770,7 @@ class BBCode
* @param array $match Array with the matching values
* @return string reformatted link including HTML codes
*/
private static function convertUrlForActivityPubCallback($match)
private static function convertUrlForActivityPubCallback(array $match): string
{
$url = $match[1];
@ -789,10 +792,9 @@ class BBCode
* @param string $url URL that is about to be reformatted
* @return string reformatted link including HTML codes
*/
private static function convertUrlForActivityPub($url)
private static function convertUrlForActivityPub(string $url): string
{
$html = '<a href="%s" target="_blank" rel="noopener noreferrer">%s</a>';
return sprintf($html, $url, self::getStyledURL($url));
return sprintf('<a href="%s" target="_blank" rel="noopener noreferrer">%s</a>', $url, self::getStyledURL($url));
}
/**
@ -801,7 +803,7 @@ class BBCode
* @param string $url URL that is about to be reformatted
* @return string reformatted link
*/
private static function getStyledURL($url)
private static function getStyledURL(string $url): string
{
$parts = parse_url($url);
$scheme = $parts['scheme'] . '://';
@ -818,8 +820,11 @@ class BBCode
* [noparse][i]italic[/i][/noparse] turns into
* [noparse][ i ]italic[ /i ][/noparse],
* to hide them from parser.
*
* @param array $match
* @return string
*/
private static function escapeNoparseCallback($match)
private static function escapeNoparseCallback(array $match): string
{
$whole_match = $match[0];
$captured = $match[1];
@ -832,8 +837,11 @@ class BBCode
* The previously spacefied [noparse][ i ]italic[ /i ][/noparse],
* now turns back and the [noparse] tags are trimed
* returning [i]italic[/i]
*
* @param array $match
* @return string
*/
private static function unescapeNoparseCallback($match)
private static function unescapeNoparseCallback(array $match): string
{
$captured = $match[1];
$unspacefied = preg_replace("/\[ (.*?)\ ]/", "[$1]", $captured);
@ -849,7 +857,7 @@ class BBCode
* @param int $occurrences Number of first occurrences to skip
* @return boolean|array
*/
public static function getTagPosition($text, $name, $occurrences = 0)
public static function getTagPosition(string $text, string $name, int $occurrences = 0)
{
DI::profiler()->startRecording('rendering');
if ($occurrences < 0) {
@ -913,7 +921,7 @@ class BBCode
* @param string $text Text to search
* @return string
*/
public static function pregReplaceInTag($pattern, $replace, $name, $text)
public static function pregReplaceInTag(string $pattern, string $replace, string $name, string $text): string
{
DI::profiler()->startRecording('rendering');
$occurrences = 0;
@ -936,7 +944,7 @@ class BBCode
return $text;
}
private static function extractImagesFromItemBody($body)
private static function extractImagesFromItemBody(string $body): array
{
$saved_image = [];
$orig_body = $body;
@ -977,7 +985,7 @@ class BBCode
return ['body' => $new_body, 'images' => $saved_image];
}
private static function interpolateSavedImagesIntoItemBody($uriid, $body, array $images)
private static function interpolateSavedImagesIntoItemBody(int $uriid, string $body, array $images): string
{
$newbody = $body;
@ -995,29 +1003,51 @@ class BBCode
}
/**
*
* @param string $text A BBCode string
* @return array share attributes
* @return array Empty array if no share tag is present or the following array, missing attributes end up empty strings:
* - comment: Text before the opening share tag
* - shared : Text inside the share tags
* - author : (Optional) Display name of the shared author
* - profile: (Optional) Profile page URL of the shared author
* - avatar : (Optional) Profile picture URL of the shared author
* - link : (Optional) Canonical URL of the shared post
* - posted : (Optional) Date the shared post was initially posted ("Y-m-d H:i:s" in GMT)
* - guid : (Optional) Shared post GUID if any
*/
public static function fetchShareAttributes($text)
public static function fetchShareAttributes(string $text): array
{
DI::profiler()->startRecording('rendering');
// See Issue https://github.com/friendica/friendica/issues/10454
// Hashtags in usernames are expanded to links. This here is a quick fix.
$text = preg_replace('/([@!#])\[url\=.*?\](.*?)\[\/url\]/ism', '$1$2', $text);
$text = preg_replace('~([@!#])\[url=.*?](.*?)\[/url]~ism', '$1$2', $text);
if (!preg_match('~(.*?)\[share(.*?)](.*)\[/share]~ism', $text, $matches)) {
DI::profiler()->stopRecording();
return [];
}
$attributes = self::extractShareAttributes($matches[2]);
$attributes['comment'] = trim($matches[1]);
$attributes['shared'] = trim($matches[3]);
$attributes = [];
if (!preg_match("/(.*?)\[share(.*?)\](.*)\[\/share\]/ism", $text, $matches)) {
DI::profiler()->stopRecording();
return $attributes;
}
$attribute_string = $matches[2];
/**
* @see BBCode::fetchShareAttributes()
* @param string $shareString Internal opening share tag string matched by the regular expression
* @return array A fixed attribute array where missing attribute are represented by empty strings
*/
private static function extractShareAttributes(string $shareString): array
{
$attributes = [];
foreach (['author', 'profile', 'avatar', 'link', 'posted', 'guid'] as $field) {
preg_match("/$field=(['\"])(.+?)\\1/ism", $attribute_string, $matches);
preg_match("/$field=(['\"])(.+?)\\1/ism", $shareString, $matches);
$attributes[$field] = html_entity_decode($matches[2] ?? '', ENT_QUOTES, 'UTF-8');
}
DI::profiler()->stopRecording();
return $attributes;
}
@ -1040,18 +1070,13 @@ class BBCode
* @param callable $callback
* @return string The BBCode string with all [share] blocks replaced
*/
public static function convertShare($text, callable $callback, int $uriid = 0)
public static function convertShare(string $text, callable $callback, int $uriid = 0): string
{
DI::profiler()->startRecording('rendering');
$return = preg_replace_callback(
"/(.*?)\[share(.*?)\](.*)\[\/share\]/ism",
'~(.*?)\[share(.*?)](.*)\[/share]~ism',
function ($match) use ($callback, $uriid) {
$attribute_string = $match[2];
$attributes = [];
foreach (['author', 'profile', 'avatar', 'link', 'posted', 'guid'] as $field) {
preg_match("/$field=(['\"])(.+?)\\1/ism", $attribute_string, $matches);
$attributes[$field] = html_entity_decode($matches[2] ?? '', ENT_QUOTES, 'UTF-8');
}
$attributes = self::extractShareAttributes($match[2]);
$author_contact = Contact::getByURL($attributes['profile'], false, ['id', 'url', 'addr', 'name', 'micro']);
$author_contact['url'] = ($author_contact['url'] ?? $attributes['profile']);
@ -1129,7 +1154,7 @@ class BBCode
* @return string
* @throws \Friendica\Network\HTTPException\InternalServerErrorException
*/
private static function convertShareCallback(array $attributes, array $author_contact, $content, $is_quote_share, $simplehtml)
private static function convertShareCallback(array $attributes, array $author_contact, string $content, bool $is_quote_share, int $simplehtml): string
{
DI::profiler()->startRecording('rendering');
$mention = $attributes['author'] . ' (' . ($author_contact['addr'] ?? '') . ')';
@ -1198,7 +1223,7 @@ class BBCode
return $text;
}
private static function removePictureLinksCallback($match)
private static function removePictureLinksCallback(array $match): string
{
$cache_key = 'remove:' . $match[1];
$text = DI::cache()->get($cache_key);
@ -1212,9 +1237,9 @@ class BBCode
}
if (substr($mimetype, 0, 6) == 'image/') {
$text = "[url=" . $match[1] . ']' . $match[1] . "[/url]";
$text = '[url=' . $match[1] . ']' . $match[1] . '[/url]';
} else {
$text = "[url=" . $match[2] . ']' . $match[2] . "[/url]";
$text = '[url=' . $match[2] . ']' . $match[2] . '[/url]';
// if its not a picture then look if its a page that contains a picture link
$body = DI::httpClient()->fetch($match[1], HttpClientAccept::HTML, 0);
@ -1226,7 +1251,7 @@ class BBCode
$doc = new DOMDocument();
@$doc->loadHTML($body);
$xpath = new DOMXPath($doc);
$list = $xpath->query("//meta[@name]");
$list = $xpath->query('//meta[@name]');
foreach ($list as $node) {
$attr = [];
@ -1247,16 +1272,28 @@ class BBCode
return $text;
}
private static function expandLinksCallback($match)
/**
* Callback: Expands links from given $match array
*
* @param arrat $match Array with link match
* @return string BBCode
*/
private static function expandLinksCallback(array $match): string
{
if (($match[3] == '') || ($match[2] == $match[3]) || stristr($match[2], $match[3])) {
return ($match[1] . "[url]" . $match[2] . "[/url]");
return ($match[1] . '[url]' . $match[2] . '[/url]');
} else {
return ($match[1] . $match[3] . " [url]" . $match[2] . "[/url]");
return ($match[1] . $match[3] . ' [url]' . $match[2] . '[/url]');
}
}
private static function cleanPictureLinksCallback($match)
/**
* Callback: Cleans picture links
*
* @param arrat $match Array with link match
* @return string BBCode
*/
private static function cleanPictureLinksCallback(array $match): string
{
// When the picture link is the own photo path then we can avoid fetching the link
$own_photo_url = preg_quote(Strings::normaliseLink(DI::baseUrl()->get()) . '/photos/');
@ -1302,7 +1339,7 @@ class BBCode
$doc = new DOMDocument();
@$doc->loadHTML($body);
$xpath = new DOMXPath($doc);
$list = $xpath->query("//meta[@name]");
$list = $xpath->query('//meta[@name]');
foreach ($list as $node) {
$attr = [];
if ($node->attributes->length) {
@ -1325,7 +1362,13 @@ class BBCode
return $text;
}
public static function cleanPictureLinks($text)
/**
* Cleans picture links
*
* @param string $text HTML/BBCode string
* @return string Cleaned HTML/BBCode
*/
public static function cleanPictureLinks(string $text): string
{
DI::profiler()->startRecording('rendering');
$return = preg_replace_callback("&\[url=([^\[\]]*)\]\[img=(.*)\](.*)\[\/img\]\[\/url\]&Usi", 'self::cleanPictureLinksCallback', $text);
@ -1334,7 +1377,13 @@ class BBCode
return $return;
}
public static function removeLinks(string $bbcode)
/**
* Removes links
*
* @param string $text HTML/BBCode string
* @return string Cleaned HTML/BBCode
*/
public static function removeLinks(string $bbcode): string
{
DI::profiler()->startRecording('rendering');
$bbcode = preg_replace("/\[img\=(.*?)\](.*?)\[\/img\]/ism", ' $1 ', $bbcode);
@ -1350,7 +1399,7 @@ class BBCode
/**
* Replace names in mentions with nicknames
*
* @param string $body
* @param string $body HTML/BBCode
* @return string Body with replaced mentions
*/
public static function setMentionsToNicknames(string $body): string
@ -1366,10 +1415,10 @@ class BBCode
* Callback function to replace a Friendica style mention in a mention with the nickname
*
* @param array $match Matching values for the callback
* @return string Replaced mention
* @return string Replaced mention or empty string
* @throws \Friendica\Network\HTTPException\InternalServerErrorException
*/
private static function mentionCallback($match)
private static function mentionCallback(array $match): string
{
if (empty($match[2])) {
return '';
@ -1407,7 +1456,7 @@ class BBCode
* @return string
* @throws \Friendica\Network\HTTPException\InternalServerErrorException
*/
public static function convertForUriId(int $uriid = null, string $text = null, int $simple_html = self::INTERNAL)
public static function convertForUriId(int $uriid = null, string $text = null, int $simple_html = self::INTERNAL): string
{
$try_oembed = ($simple_html == self::INTERNAL);
@ -1437,10 +1486,10 @@ class BBCode
* @param int $simple_html
* @param bool $for_plaintext
* @param int $uriid
* @return string
* @return string Converted code or empty string
* @throws \Friendica\Network\HTTPException\InternalServerErrorException
*/
public static function convert(string $text = null, $try_oembed = true, $simple_html = self::INTERNAL, $for_plaintext = false, $uriid = 0)
public static function convert(string $text = null, bool $try_oembed = true, int $simple_html = self::INTERNAL, bool $for_plaintext = false, int $uriid = 0): string
{
// Accounting for null default column values
if (is_null($text) || $text === '') {
@ -1462,10 +1511,10 @@ class BBCode
* $match[1] = $url
* $match[2] = $title or absent
*/
$try_oembed_callback = function ($match)
$try_oembed_callback = function (array $match)
{
$url = $match[1];
$title = $match[2] ?? null;
$title = $match[2] ?? '';
try {
$return = OEmbed::getHTML($url, $title);
@ -1788,7 +1837,7 @@ class BBCode
$text = preg_replace("/\[crypt\](.*?)\[\/crypt\]/ism", '<br><img src="' .DI::baseUrl() . '/images/lock_icon.gif" alt="' . DI::l10n()->t('Encrypted content') . '" title="' . DI::l10n()->t('Encrypted content') . '" /><br>', $text);
$text = preg_replace("/\[crypt(.*?)\](.*?)\[\/crypt\]/ism", '<br><img src="' .DI::baseUrl() . '/images/lock_icon.gif" alt="' . DI::l10n()->t('Encrypted content') . '" title="' . '$1' . ' ' . DI::l10n()->t('Encrypted content') . '" /><br>', $text);
//$Text = preg_replace("/\[crypt=(.*?)\](.*?)\[\/crypt\]/ism", '<br><img src="' .DI::baseUrl() . '/images/lock_icon.gif" alt="' . DI::l10n()->t('Encrypted content') . '" title="' . '$1' . ' ' . DI::l10n()->t('Encrypted content') . '" /><br>', $Text);
//$text = preg_replace("/\[crypt=(.*?)\](.*?)\[\/crypt\]/ism", '<br><img src="' .DI::baseUrl() . '/images/lock_icon.gif" alt="' . DI::l10n()->t('Encrypted content') . '" title="' . '$1' . ' ' . DI::l10n()->t('Encrypted content') . '" /><br>', $text);
// Simplify "video" element
$text = preg_replace('(\[video[^\]]*?\ssrc\s?=\s?([^\s\]]+)[^\]]*?\].*?\[/video\])ism', '[video]$1[/video]', $text);
@ -1916,7 +1965,7 @@ class BBCode
if (in_array($simple_html, [self::OSTATUS, self::TWITTER])) {
$text = preg_replace_callback("/([^#@!])\[url\=([^\]]*)\](.*?)\[\/url\]/ism", "self::expandLinksCallback", $text);
//$Text = preg_replace("/[^#@!]\[url\=([^\]]*)\](.*?)\[\/url\]/ism", ' $2 [url]$1[/url]', $Text);
//$text = preg_replace("/[^#@!]\[url\=([^\]]*)\](.*?)\[\/url\]/ism", ' $2 [url]$1[/url]', $text);
$text = preg_replace("/\[bookmark\=([^\]]*)\](.*?)\[\/bookmark\]/ism", ' $2 [url]$1[/url]', $text);
}
@ -2142,7 +2191,7 @@ class BBCode
* @throws \Friendica\Network\HTTPException\InternalServerErrorException
* @throws \ImagickException
*/
private static function bbCodeMention2DiasporaCallback($match)
private static function bbCodeMention2DiasporaCallback(array $match): string
{
$contact = Contact::getByURL($match[3], false, ['addr']);
if (empty($contact['addr'])) {
@ -2164,7 +2213,7 @@ class BBCode
* @return string
* @throws \Friendica\Network\HTTPException\InternalServerErrorException
*/
public static function toMarkdown($text, $for_diaspora = true)
public static function toMarkdown(string $text, bool $for_diaspora = true): string
{
DI::profiler()->startRecording('rendering');
$original_text = $text;
@ -2201,7 +2250,7 @@ class BBCode
$tagline .= '#' . $tag . ' ';
}
}
$text = $text . " " . $tagline;
$text = $text . ' ' . $tagline;
}
} else {
$text = self::convert($text, false, self::CONNECTORS);
@ -2246,10 +2295,9 @@ class BBCode
* Returns array of tags found, or empty array.
*
* @param string $string Post content
*
* @return array List of tag and person names
*/
public static function getTags($string)
public static function getTags(string $string): array
{
DI::profiler()->startRecording('rendering');
$ret = [];
@ -2309,13 +2357,13 @@ class BBCode
/**
* Expand tags to URLs, checks the tag is at the start of a line or preceded by a non-word character
*
* @param string $body
* @param string $body HTML/BBCode
* @return string body with expanded tags
*/
public static function expandTags(string $body)
public static function expandTags(string $body): string
{
return preg_replace_callback("/(?<=\W|^)([!#@])([^\^ \x0D\x0A,;:?'\"]*[^\^ \x0D\x0A,;:?!'\".])/",
function ($match) {
function (array $match) {
switch ($match[1]) {
case '!':
case '@':
@ -2326,6 +2374,7 @@ class BBCode
return $match[1] . $match[2];
}
break;
case '#':
default:
return $match[1] . '[url=' . DI::baseUrl() . '/search?tag=' . $match[2] . ']' . $match[2] . '[/url]';
@ -2336,7 +2385,7 @@ class BBCode
/**
* Perform a custom function on a text after having escaped blocks enclosed in the provided tag list.
*
* @param string $text
* @param string $text HTML/BBCode
* @param array $tagList A list of tag names, e.g ['noparse', 'nobb', 'pre']
* @param callable $callback
* @return string
@ -2352,14 +2401,14 @@ class BBCode
/**
* Replaces mentions in the provided message body in BBCode links for the provided user and network if any
*
* @param $body
* @param $profile_uid
* @param $network
* @return string
* @param string $body HTML/BBCode
* @param int $profile_uid Profile user id
* @param string $network Network name
* @return string HTML/BBCode with inserted images
* @throws \Friendica\Network\HTTPException\InternalServerErrorException
* @throws \ImagickException
*/
public static function setMentions($body, $profile_uid = 0, $network = '')
public static function setMentions(string $body, $profile_uid = 0, $network = '')
{
DI::profiler()->startRecording('rendering');
$body = self::performWithEscapedTags($body, ['noparse', 'pre', 'code', 'img'], function ($body) use ($profile_uid, $network) {
@ -2406,7 +2455,7 @@ class BBCode
* @return string
* @TODO Rewrite to handle over whole record array
*/
public static function getShareOpeningTag(string $author, string $profile, string $avatar, string $link, string $posted, string $guid = null)
public static function getShareOpeningTag(string $author, string $profile, string $avatar, string $link, string $posted, string $guid = null): string
{
DI::profiler()->startRecording('rendering');
$header = "[share author='" . str_replace(["'", "[", "]"], ["&#x27;", "&#x5B;", "&#x5D;"], $author) .
@ -2439,7 +2488,6 @@ class BBCode
* @return string
* @throws \Friendica\Network\HTTPException\InternalServerErrorException
* @see ParseUrl::getSiteinfoCached
*
*/
public static function embedURL(string $url, bool $tryAttachment = true, string $title = null, string $description = null, string $tags = null): string
{

View File

@ -61,7 +61,7 @@ class HTML
* inner value from an attribute value and disregard the tag children.
* @return bool Whether a replacement was done
*/
private static function tagToBBCodeSub(DOMDocument $doc, string $tag, array $attributes, string $startbb, string $endbb, bool $ignoreChildren = false)
private static function tagToBBCodeSub(DOMDocument $doc, string $tag, array $attributes, string $startbb, string $endbb, bool $ignoreChildren = false): bool
{
$savestart = str_replace('$', '\x01', $startbb);
$replace = false;
@ -141,8 +141,16 @@ class HTML
* @return string
* @throws \Friendica\Network\HTTPException\InternalServerErrorException
*/
public static function toBBCode($message, $basepath = '')
public static function toBBCode(string $message, string $basepath = ''): string
{
/*
* Check if message is empty to prevent a lot code below being executed
* for just an empty message.
*/
if (empty($message)) {
return '';
}
DI::profiler()->startRecording('rendering');
$message = str_replace("\r", "", $message);
@ -409,7 +417,7 @@ class HTML
*
* @return string The expanded URL
*/
private static function qualifyURLsSub($matches, $basepath)
private static function qualifyURLsSub(array $matches, string $basepath): string
{
$base = parse_url($basepath);
unset($base['query']);
@ -436,7 +444,7 @@ class HTML
*
* @return string Body with expanded URLs
*/
private static function qualifyURLs($body, $basepath)
private static function qualifyURLs(string $body, string $basepath): string
{
$URLSearchString = "^\[\]";
@ -462,7 +470,7 @@ class HTML
return $body;
}
private static function breakLines($line, $level, $wraplength = 75)
private static function breakLines(string $line, int $level, int $wraplength = 75): string
{
if ($wraplength == 0) {
$wraplength = 2000000;
@ -503,7 +511,7 @@ class HTML
return implode("\n", $newlines);
}
private static function quoteLevel($message, $wraplength = 75)
private static function quoteLevel(string $message, int $wraplength = 75): string
{
$lines = explode("\n", $message);
@ -539,7 +547,7 @@ class HTML
return implode("\n", $newlines);
}
private static function collectURLs($message)
private static function collectURLs(string $message): array
{
$pattern = '/<a.*?href="(.*?)".*?>(.*?)<\/a>/is';
preg_match_all($pattern, $message, $result, PREG_SET_ORDER);
@ -585,7 +593,7 @@ class HTML
* @param bool $compact True: Completely strips image tags; False: Keeps image URLs
* @return string
*/
public static function toPlaintext(string $html, $wraplength = 75, $compact = false)
public static function toPlaintext(string $html, int $wraplength = 75, bool $compact = false): string
{
DI::profiler()->startRecording('rendering');
$message = str_replace("\r", "", $html);
@ -705,7 +713,7 @@ class HTML
* @param string $html
* @return string
*/
public static function toMarkdown($html)
public static function toMarkdown(string $html): string
{
DI::profiler()->startRecording('rendering');
$converter = new HtmlConverter(['hard_break' => true]);
@ -721,7 +729,7 @@ class HTML
* @param string $s
* @return string
*/
public static function toBBCodeVideo($s)
public static function toBBCodeVideo(string $s): string
{
$s = preg_replace(
'#<object[^>]+>(.*?)https?://www.youtube.com/((?:v|cp)/[A-Za-z0-9\-_=]+)(.*?)</object>#ism',
@ -751,7 +759,7 @@ class HTML
* @param string $base base url
* @return string
*/
public static function relToAbs($text, $base)
public static function relToAbs(string $text, string $base): string
{
if (empty($base)) {
return $text;
@ -790,7 +798,7 @@ class HTML
* @return string html for loader
* @throws \Friendica\Network\HTTPException\InternalServerErrorException
*/
public static function scrollLoader()
public static function scrollLoader(): string
{
$tpl = Renderer::getMarkupTemplate("scroll_loader.tpl");
return Renderer::replaceMacros($tpl, [
@ -819,7 +827,7 @@ class HTML
* @throws \Friendica\Network\HTTPException\InternalServerErrorException
* @throws \ImagickException
*/
public static function micropro($contact, $redirect = false, $class = '', $textmode = false)
public static function micropro(array $contact, bool $redirect = false, string $class = '', bool $textmode = false): string
{
// Use the contact URL if no address is available
if (empty($contact['addr'])) {
@ -859,13 +867,12 @@ class HTML
*
* @param string $s Search query.
* @param string $id HTML id
* @param string $url Search url.
* @param bool $aside Display the search widgit aside.
*
* @return string Formatted HTML.
* @throws \Exception
*/
public static function search($s, $id = 'search-box', $aside = true)
public static function search(string $s, string $id = 'search-box', bool $aside = true): string
{
$mode = 'text';
@ -906,7 +913,7 @@ class HTML
* @param string $s
* @return string
*/
public static function toLink($s)
public static function toLink(string $s): string
{
$s = preg_replace("/(https?\:\/\/[a-zA-Z0-9\:\/\-\?\&\;\.\=\_\~\#\'\%\$\!\+]*)/", ' <a href="$1" target="_blank" rel="noopener noreferrer">$1</a>', $s);
$s = preg_replace("/\<(.*?)(src|href)=(.*?)\&amp\;(.*?)\>/ism", '<$1$2=$3&$4>', $s);
@ -923,7 +930,7 @@ class HTML
* @return string
* @throws \Friendica\Network\HTTPException\InternalServerErrorException
*/
public static function applyContentFilter($html, array $reasons)
public static function applyContentFilter(string $html, array $reasons): string
{
if (count($reasons)) {
$tpl = Renderer::getMarkupTemplate('wall/content_filter.tpl');
@ -943,7 +950,7 @@ class HTML
* @param string $s
* @return string
*/
public static function unamp($s)
public static function unamp(string $s): string
{
return str_replace('&amp;', '&', $s);
}

View File

@ -45,7 +45,7 @@ class Widget
* @return string
* @throws \Friendica\Network\HTTPException\InternalServerErrorException
*/
public static function follow($value = "")
public static function follow(string $value = ''): string
{
return Renderer::replaceMacros(Renderer::getMarkupTemplate('widget/follow.tpl'), array(
'$connect' => DI::l10n()->t('Add New Contact'),
@ -58,8 +58,10 @@ class Widget
/**
* Return Find People widget
*
* @return string HTML code respresenting "People Widget"
*/
public static function findPeople()
public static function findPeople(): string
{
$global_dir = Search::getGlobalDirectory();
@ -97,7 +99,7 @@ class Widget
*
* @return array Unsupported networks
*/
public static function unavailableNetworks()
public static function unavailableNetworks(): array
{
// Always hide content from these networks
$networks = [Protocol::PHANTOM, Protocol::FACEBOOK, Protocol::APPNET, Protocol::ZOT];
@ -154,7 +156,7 @@ class Widget
* @return string
* @throws \Exception
*/
private static function filter($type, $title, $desc, $all, $baseUrl, array $options, $selected = null)
private static function filter(string $type, string $title, string $desc, string $all, string $baseUrl, array $options, string $selected = null): string
{
$queryString = parse_url($baseUrl, PHP_URL_QUERY);
$queryArray = [];
@ -191,7 +193,7 @@ class Widget
* @return string
* @throws \Exception
*/
public static function groups($baseurl, $selected = '')
public static function groups(string $baseurl, string $selected = ''): string
{
if (!local_user()) {
return '';
@ -223,7 +225,7 @@ class Widget
* @return string
* @throws \Exception
*/
public static function contactRels($baseurl, $selected = '')
public static function contactRels(string $baseurl, string $selected = ''): string
{
if (!local_user()) {
return '';
@ -254,7 +256,7 @@ class Widget
* @return string
* @throws \Friendica\Network\HTTPException\InternalServerErrorException
*/
public static function networks($baseurl, $selected = '')
public static function networks(string $baseurl, string $selected = ''): string
{
if (!local_user()) {
return '';
@ -292,10 +294,10 @@ class Widget
*
* @param string $baseurl baseurl
* @param string $selected optional, default empty
* @return string|void
* @return string
* @throws \Exception
*/
public static function fileAs($baseurl, $selected = '')
public static function fileAs(string $baseurl, string $selected = ''): string
{
if (!local_user()) {
return '';
@ -323,10 +325,10 @@ class Widget
* @param int $uid Id of the user owning the categories
* @param string $baseurl Base page URL
* @param string $selected Selected category
* @return string|void
* @return string
* @throws \Friendica\Network\HTTPException\InternalServerErrorException
*/
public static function categories(int $uid, string $baseurl, string $selected = '')
public static function categories(int $uid, string $baseurl, string $selected = ''): string
{
if (!Feature::isEnabled($uid, 'categories')) {
return '';
@ -353,11 +355,11 @@ class Widget
*
* @param int $uid Viewed profile user ID
* @param string $nickname Viewed profile user nickname
* @return string|void
* @return string
* @throws \Friendica\Network\HTTPException\InternalServerErrorException
* @throws \ImagickException
*/
public static function commonFriendsVisitor(int $uid, string $nickname)
public static function commonFriendsVisitor(int $uid, string $nickname): string
{
if (local_user() == $uid) {
return '';
@ -414,7 +416,7 @@ class Widget
* @throws \Friendica\Network\HTTPException\InternalServerErrorException
* @throws \ImagickException
*/
public static function tagCloud(int $uid, int $limit = 50)
public static function tagCloud(int $uid, int $limit = 50): string
{
if (empty($uid)) {
return '';
@ -439,7 +441,7 @@ class Widget
* @return string
* @throws \Friendica\Network\HTTPException\InternalServerErrorException
*/
public static function postedByYear(string $url, int $uid, bool $wall)
public static function postedByYear(string $url, int $uid, bool $wall): string
{
$o = '';
@ -510,10 +512,10 @@ class Widget
* The account type value is added as a parameter to the url
*
* @param string $base Basepath
* @param int $accounttype Acount type
* @param string $accounttype Account type
* @return string
*/
public static function accounttypes(string $base, $accounttype)
public static function accountTypes(string $base, string $accounttype): string
{
$accounts = [
['ref' => 'person', 'name' => DI::l10n()->t('Persons')],

View File

@ -124,7 +124,7 @@ class Addon
* @return void
* @throws \Exception
*/
public static function uninstall($addon)
public static function uninstall(string $addon)
{
$addon = Strings::sanitizeFilePathItem($addon);
@ -149,7 +149,7 @@ class Addon
* @return bool
* @throws \Exception
*/
public static function install($addon)
public static function install(string $addon): bool
{
$addon = Strings::sanitizeFilePathItem($addon);
@ -185,6 +185,8 @@ class Addon
/**
* reload all updated addons
*
* @return void
*/
public static function reload()
{
@ -222,7 +224,7 @@ class Addon
* @return array with the addon information
* @throws \Exception
*/
public static function getInfo($addon)
public static function getInfo(string $addon): array
{
$addon = Strings::sanitizeFilePathItem($addon);
@ -287,7 +289,7 @@ class Addon
* @param string $addon
* @return boolean
*/
public static function isEnabled($addon)
public static function isEnabled(string $addon): bool
{
return in_array($addon, self::$addons);
}
@ -297,7 +299,7 @@ class Addon
*
* @return array
*/
public static function getEnabledList()
public static function getEnabledList(): array
{
return self::$addons;
}
@ -308,7 +310,7 @@ class Addon
* @return array
* @throws \Exception
*/
public static function getVisibleList()
public static function getVisibleList(): array
{
$visible_addons = [];
$stmt = DBA::select('addon', ['name'], ['hidden' => false, 'installed' => true]);

View File

@ -68,6 +68,17 @@ class MemcacheCache extends AbstractCache implements ICanCacheInMemory
}
}
/**
* Memcache doesn't allow spaces in keys
*
* @param string $key
* @return string
*/
protected function getCacheKey(string $key): string
{
return str_replace(' ', '_', parent::getCacheKey($key));
}
/**
* (@inheritdoc)
*/

View File

@ -93,6 +93,17 @@ class MemcachedCache extends AbstractCache implements ICanCacheInMemory
}
}
/**
* Memcached doesn't allow spaces in keys
*
* @param string $key
* @return string
*/
protected function getCacheKey(string $key): string
{
return str_replace(' ', '_', parent::getCacheKey($key));
}
/**
* (@inheritdoc)
*/

View File

@ -121,7 +121,7 @@ HELP;
$this->dice = $dice;
}
protected function doExecute()
protected function doExecute(): int
{
if ($this->getOption('v')) {
$this->out('Executable: ' . $this->executable);

View File

@ -49,6 +49,8 @@ class Hook
/**
* Load hooks
*
* @return void
*/
public static function loadHooks()
{
@ -69,8 +71,9 @@ class Hook
* @param string $hook
* @param string $file
* @param string $function
* @return void
*/
public static function add($hook, $file, $function)
public static function add(string $hook, string $file, string $function)
{
if (!array_key_exists($hook, self::$hooks)) {
self::$hooks[$hook] = [];
@ -90,7 +93,7 @@ class Hook
* @return mixed|bool
* @throws \Friendica\Network\HTTPException\InternalServerErrorException
*/
public static function register($hook, $file, $function, $priority = 0)
public static function register(string $hook, string $file, string $function, int $priority = 0)
{
$file = str_replace(DI::app()->getBasePath() . DIRECTORY_SEPARATOR, '', $file);
@ -111,7 +114,7 @@ class Hook
* @return boolean
* @throws \Friendica\Network\HTTPException\InternalServerErrorException
*/
public static function unregister($hook, $file, $function)
public static function unregister(string $hook, string $file, string $function): bool
{
$relative_file = str_replace(DI::app()->getBasePath() . DIRECTORY_SEPARATOR, '', $file);
@ -120,8 +123,8 @@ class Hook
self::delete($condition);
$condition = ['hook' => $hook, 'file' => $relative_file, 'function' => $function];
$result = self::delete($condition);
return $result;
return self::delete($condition);
}
/**
@ -130,7 +133,7 @@ class Hook
* @param string $name Name of the hook
* @return array
*/
public static function getByName($name)
public static function getByName(string $name): array
{
$return = [];
@ -149,9 +152,10 @@ class Hook
* @param integer $priority of the hook
* @param string $name of the hook to call
* @param mixed $data to transmit to the callback handler
* @return void
* @throws \Friendica\Network\HTTPException\InternalServerErrorException
*/
public static function fork($priority, $name, $data = null)
public static function fork(int $priority, string $name, $data = null)
{
if (array_key_exists($name, self::$hooks)) {
foreach (self::$hooks[$name] as $hook) {
@ -184,9 +188,10 @@ class Hook
*
* @param string $name of the hook to call
* @param string|array &$data to transmit to the callback handler
* @return void
* @throws \Friendica\Network\HTTPException\InternalServerErrorException
*/
public static function callAll($name, &$data = null)
public static function callAll(string $name, &$data = null)
{
if (array_key_exists($name, self::$hooks)) {
foreach (self::$hooks[$name] as $hook) {
@ -202,9 +207,10 @@ class Hook
* @param string $name of the hook to call
* @param array $hook Hook data
* @param string|array &$data to transmit to the callback handler
* @return void
* @throws \Friendica\Network\HTTPException\InternalServerErrorException
*/
public static function callSingle(App $a, $name, $hook, &$data = null)
public static function callSingle(App $a, string $name, array $hook, &$data = null)
{
// Don't run a theme's hook if the user isn't using the theme
if (strpos($hook[0], 'view/theme/') !== false && strpos($hook[0], 'view/theme/' . $a->getCurrentTheme()) === false) {
@ -229,7 +235,7 @@ class Hook
* @param string $name Name of the addon
* @return boolean
*/
public static function isAddonApp($name)
public static function isAddonApp(string $name): bool
{
$name = Strings::sanitizeFilePathItem($name);
@ -253,7 +259,7 @@ class Hook
* @return bool
* @throws \Exception
*/
public static function delete(array $condition)
public static function delete(array $condition): bool
{
$result = DBA::delete('hook', $condition);
@ -273,7 +279,7 @@ class Hook
* @return bool
* @throws \Exception
*/
private static function insert(array $condition)
private static function insert(array $condition): bool
{
$result = DBA::insert('hook', $condition);

View File

@ -189,14 +189,12 @@ class Installer
/***
* Installs the DB-Scheme for Friendica
*
* @param string $basePath The base path of this application
*
* @return bool true if the installation was successful, otherwise false
* @throws Exception
*/
public function installDatabase($basePath)
public function installDatabase(): bool
{
$result = DBStructure::install($basePath);
$result = DBStructure::install();
if ($result) {
$txt = DI::l10n()->t('You may need to import the file "database.sql" manually using phpmyadmin or mysql.') . EOL;
@ -656,7 +654,7 @@ class Installer
* @return bool true if the check was successful, otherwise false
* @throws Exception
*/
public function checkDB(Database $dba)
public function checkDB(Database $dba): bool
{
$dba->reconnect();

View File

@ -128,7 +128,7 @@ class L10n
private function setLangFromSession(IHandleSessions $session)
{
if ($session->get('language') !== $this->lang) {
$this->loadTranslationTable($session->get('language'));
$this->loadTranslationTable($session->get('language') ?? $this->lang);
}
}
@ -140,10 +140,10 @@ class L10n
* Uses an App object shim since all the strings files refer to $a->strings
*
* @param string $lang language code to load
*
* @return void
* @throws \Exception
*/
private function loadTranslationTable($lang)
private function loadTranslationTable(string $lang)
{
$lang = Strings::sanitizeFilePathItem($lang);
@ -183,7 +183,7 @@ class L10n
*
* @return string The two-letter language code
*/
public static function detectLanguage(array $server, array $get, string $sysLang = self::DEFAULT)
public static function detectLanguage(array $server, array $get, string $sysLang = self::DEFAULT): string
{
$lang_variable = $server['HTTP_ACCEPT_LANGUAGE'] ?? null;
@ -269,7 +269,7 @@ class L10n
*
* @return string
*/
public function t($s, ...$vars)
public function t(string $s, ...$vars): string
{
if (empty($s)) {
return '';
@ -307,7 +307,7 @@ class L10n
* @return string
* @throws \Exception
*/
public function tt(string $singular, string $plural, int $count)
public function tt(string $singular, string $plural, int $count): string
{
$s = null;
@ -352,7 +352,7 @@ class L10n
*
* @return bool
*/
private function stringPluralSelectDefault($n)
private function stringPluralSelectDefault(int $n): bool
{
return $n != 1;
}
@ -369,7 +369,7 @@ class L10n
*
* @return array
*/
public static function getAvailableLanguages()
public static function getAvailableLanguages(): array
{
$langs = [];
$strings_file_paths = glob('view/lang/*/strings.php');
@ -391,10 +391,9 @@ class L10n
* Translate days and months names.
*
* @param string $s String with day or month name.
*
* @return string Translated string.
*/
public function getDay($s)
public function getDay(string $s): string
{
$ret = str_replace(['Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday'],
[$this->t('Monday'), $this->t('Tuesday'), $this->t('Wednesday'), $this->t('Thursday'), $this->t('Friday'), $this->t('Saturday'), $this->t('Sunday')],
@ -411,10 +410,9 @@ class L10n
* Translate short days and months names.
*
* @param string $s String with short day or month name.
*
* @return string Translated string.
*/
public function getDayShort($s)
public function getDayShort(string $s): string
{
$ret = str_replace(['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'],
[$this->t('Mon'), $this->t('Tue'), $this->t('Wed'), $this->t('Thu'), $this->t('Fri'), $this->t('Sat'), $this->t('Sun')],
@ -435,7 +433,7 @@ class L10n
* @throws \Friendica\Network\HTTPException\InternalServerErrorException
* @hook poke_verbs pokes array
*/
public function getPokeVerbs()
public function getPokeVerbs(): array
{
// index is present tense verb
// value is array containing past tense verb, translation of present, translation of past
@ -461,7 +459,7 @@ class L10n
* @return static A new L10n instance
* @throws \Exception
*/
public function withLang(string $lang)
public function withLang(string $lang): L10n
{
// Don't create a new instance for same language
if ($lang === $this->lang) {

View File

@ -47,7 +47,7 @@ class Logger
/**
* @return LoggerInterface
*/
private static function getWorker()
private static function getInstance()
{
if (self::$type === self::TYPE_LOGGER) {
return DI::logger();
@ -66,7 +66,7 @@ class Logger
public static function enableWorker(string $functionName)
{
self::$type = self::TYPE_WORKER;
self::getWorker()->setFunctionName($functionName);
self::getInstance()->setFunctionName($functionName);
}
/**
@ -82,15 +82,14 @@ class Logger
*
* @see LoggerInterface::emergency()
*
* @param string $message
* @param array $context
*
* @param string $message Message to log
* @param array $context Optional variables
* @return void
* @throws \Exception
*/
public static function emergency($message, $context = [])
public static function emergency(string $message, array $context = [])
{
self::getWorker()->emergency($message, $context);
self::getInstance()->emergency($message, $context);
}
/**
@ -100,15 +99,14 @@ class Logger
* Example: Entire website down, database unavailable, etc. This should
* trigger the SMS alerts and wake you up.
*
* @param string $message
* @param array $context
*
* @param string $message Message to log
* @param array $context Optional variables
* @return void
* @throws \Exception
*/
public static function alert($message, $context = [])
public static function alert(string $message, array $context = [])
{
self::getWorker()->alert($message, $context);
self::getInstance()->alert($message, $context);
}
/**
@ -117,15 +115,14 @@ class Logger
*
* Example: Application component unavailable, unexpected exception.
*
* @param string $message
* @param array $context
*
* @param string $message Message to log
* @param array $context Optional variables
* @return void
* @throws \Exception
*/
public static function critical($message, $context = [])
public static function critical(string $message, array $context = [])
{
self::getWorker()->critical($message, $context);
self::getInstance()->critical($message, $context);
}
/**
@ -133,15 +130,14 @@ class Logger
* be logged and monitored.
* @see LoggerInterface::error()
*
* @param string $message
* @param array $context
*
* @param string $message Message to log
* @param array $context Optional variables
* @return void
* @throws \Exception
*/
public static function error($message, $context = [])
public static function error(string $message, array $context = [])
{
self::getWorker()->error($message, $context);
self::getInstance()->error($message, $context);
}
/**
@ -151,30 +147,28 @@ class Logger
* Example: Use of deprecated APIs, poor use of an API, undesirable things
* that are not necessarily wrong.
*
* @param string $message
* @param array $context
*
* @param string $message Message to log
* @param array $context Optional variables
* @return void
* @throws \Exception
*/
public static function warning($message, $context = [])
public static function warning(string $message, array $context = [])
{
self::getWorker()->warning($message, $context);
self::getInstance()->warning($message, $context);
}
/**
* Normal but significant events.
* @see LoggerInterface::notice()
*
* @param string $message
* @param array $context
*
* @param string $message Message to log
* @param array $context Optional variables
* @return void
* @throws \Exception
*/
public static function notice($message, $context = [])
public static function notice(string $message, array $context = [])
{
self::getWorker()->notice($message, $context);
self::getInstance()->notice($message, $context);
}
/**
@ -189,24 +183,23 @@ class Logger
* @return void
* @throws \Exception
*/
public static function info($message, $context = [])
public static function info(string $message, array $context = [])
{
self::getWorker()->info($message, $context);
self::getInstance()->info($message, $context);
}
/**
* Detailed debug information.
* @see LoggerInterface::debug()
*
* @param string $message
* @param array $context
*
* @param string $message Message to log
* @param array $context Optional variables
* @return void
* @throws \Exception
*/
public static function debug($message, $context = [])
public static function debug(string $message, array $context = [])
{
self::getWorker()->debug($message, $context);
self::getInstance()->debug($message, $context);
}
/**
@ -216,12 +209,13 @@ class Logger
* to isolate particular elements they are targetting
* personally without background noise
*
* @param string $msg
* @param string $level
* @param string $message Message to log
* @param string $level Logging level
* @return void
* @throws \Exception
*/
public static function devLog($msg, $level = LogLevel::DEBUG)
public static function devLog(string $message, string $level = LogLevel::DEBUG)
{
DI::devLogger()->log($level, $msg);
DI::devLogger()->log($level, $message);
}
}

View File

@ -21,6 +21,7 @@
namespace Friendica\Core\Logger\Type\Monolog;
use Friendica\App\Request;
use Monolog\Handler;
use Monolog\Logger;
@ -38,15 +39,22 @@ class DevelopHandler extends Handler\AbstractHandler
private $developerIp;
/**
* @var string The IP of the current request
*/
private $remoteAddress;
/**
* @param Request $request The current http request
* @param string $developerIp The IP of the developer who wants to debug
* @param int $level The minimum logging level at which this handler will be triggered
* @param bool $bubble Whether the messages that are handled can bubble up the stack or not
*/
public function __construct($developerIp, $level = Logger::DEBUG, bool $bubble = true)
public function __construct(Request $request, $developerIp, int $level = Logger::DEBUG, bool $bubble = true)
{
parent::__construct($level, $bubble);
$this->developerIp = $developerIp;
$this->remoteAddress = $request->getRemoteAddress();
}
/**
@ -59,7 +67,7 @@ class DevelopHandler extends Handler\AbstractHandler
}
/// Just in case the remote IP is the same as the developer IP log the output
if (!is_null($this->developerIp) && $_SERVER['REMOTE_ADDR'] != $this->developerIp) {
if (!is_null($this->developerIp) && $this->remoteAddress != $this->developerIp) {
return false;
}

View File

@ -71,7 +71,7 @@ class Renderer
* @return string
* @throws ServiceUnavailableException
*/
public static function replaceMacros(string $template, array $vars = [])
public static function replaceMacros(string $template, array $vars = []): string
{
DI::profiler()->startRecording('rendering');

View File

@ -441,6 +441,12 @@ class System
*
* @param string $url The new Location to redirect
* @param int $code The redirection code, which is used (Default is 302)
*
* @throws FoundException
* @throws MovedPermanentlyException
* @throws TemporaryRedirectException
*
* @throws \Friendica\Network\HTTPException\InternalServerErrorException
*/
public static function externalRedirect($url, $code = 302)
{

View File

@ -32,7 +32,7 @@ require_once 'boot.php';
*/
class Theme
{
public static function getAllowedList()
public static function getAllowedList(): array
{
$allowed_themes_str = DI::config()->get('system', 'allowed_themes');
$allowed_themes_raw = explode(',', str_replace(' ', '', $allowed_themes_str));
@ -69,7 +69,7 @@ class Theme
* @param string $theme the name of the theme
* @return array
*/
public static function getInfo($theme)
public static function getInfo(string $theme): array
{
$theme = Strings::sanitizeFilePathItem($theme);
@ -133,7 +133,7 @@ class Theme
* @return string
* @throws \Friendica\Network\HTTPException\InternalServerErrorException
*/
public static function getScreenshot($theme)
public static function getScreenshot(string $theme): string
{
$theme = Strings::sanitizeFilePathItem($theme);
@ -146,7 +146,13 @@ class Theme
return DI::baseUrl() . '/images/blank.png';
}
public static function uninstall($theme)
/**
* Uninstalls given theme name
*
* @param string $theme Name of theme
* @return bool true on success
*/
public static function uninstall(string $theme)
{
$theme = Strings::sanitizeFilePathItem($theme);
@ -167,10 +173,18 @@ class Theme
if ($key !== false) {
unset($allowed_themes[$key]);
Theme::setAllowedList($allowed_themes);
return true;
}
return false;
}
public static function install($theme)
/**
* Installs given theme name
*
* @param string $theme Name of theme
* @return bool true on success
*/
public static function install(string $theme): bool
{
$theme = Strings::sanitizeFilePathItem($theme);
@ -208,7 +222,7 @@ class Theme
* @return string Path to the file or empty string if the file isn't found
* @throws \Exception
*/
public static function getPathForFile($file)
public static function getPathForFile(string $file): string
{
$a = DI::app();
@ -237,10 +251,9 @@ class Theme
* Provide a sane default if nothing is chosen or the specified theme does not exist.
*
* @param string $theme Theme name
*
* @return string
*/
public static function getStylesheetPath($theme)
public static function getStylesheetPath(string $theme): string
{
$theme = Strings::sanitizeFilePathItem($theme);
@ -263,10 +276,10 @@ class Theme
/**
* Returns the path of the provided theme
*
* @param $theme
* @param string $theme Theme name
* @return string|null
*/
public static function getConfigFile($theme)
public static function getConfigFile(string $theme)
{
$theme = Strings::sanitizeFilePathItem($theme);
@ -285,11 +298,11 @@ class Theme
/**
* Returns the background color of the provided theme if available.
*
* @param string $theme
* @param string $theme Theme name
* @param int|null $uid Current logged-in user id
* @return string|null
*/
public static function getBackgroundColor(string $theme, $uid = null)
public static function getBackgroundColor(string $theme, int $uid = null)
{
$theme = Strings::sanitizeFilePathItem($theme);

View File

@ -41,7 +41,7 @@ class Update
* @param string $basePath The base path of this application
* @param boolean $via_worker Is the check run via the worker?
* @param App\Mode $mode The current app mode
*
* @return void
* @throws \Friendica\Network\HTTPException\InternalServerErrorException
*/
public static function check(string $basePath, bool $via_worker, App\Mode $mode)
@ -73,7 +73,7 @@ class Update
}
// The postupdate has to completed version 1288 for the new post views to take over
$postupdate = DI::config()->get("system", "post_update_version", NEW_TABLE_STRUCTURE_VERSION);
$postupdate = DI::config()->get('system', 'post_update_version', NEW_TABLE_STRUCTURE_VERSION);
if ($postupdate < NEW_TABLE_STRUCTURE_VERSION) {
$error = DI::l10n()->t('Updates from postupdate version %s are not supported. Please update at least to version 2021.01 and wait until the postupdate finished version 1383.', $postupdate);
if (DI::mode()->getExecutor() == Mode::INDEX) {
@ -85,9 +85,11 @@ class Update
if ($build < DB_UPDATE_VERSION) {
if ($via_worker) {
// Calling the database update directly via the worker enables us to perform database changes to the workerqueue table itself.
// This is a fallback, since normally the database update will be performed by a worker job.
// This worker job doesn't work for changes to the "workerqueue" table itself.
/*
* Calling the database update directly via the worker enables us to perform database changes to the workerqueue table itself.
* This is a fallback, since normally the database update will be performed by a worker job.
* This worker job doesn't work for changes to the "workerqueue" table itself.
*/
self::run($basePath);
} else {
Worker::add(PRIORITY_CRITICAL, 'DBUpdate');
@ -103,11 +105,10 @@ class Update
* @param bool $override Overrides any running/stuck updates
* @param bool $verbose Run the Update-Check verbose
* @param bool $sendMail Sends a Mail to the administrator in case of success/failure
*
* @return string Empty string if the update is successful, error messages otherwise
* @throws \Friendica\Network\HTTPException\InternalServerErrorException
*/
public static function run(string $basePath, bool $force = false, bool $override = false, bool $verbose = false, bool $sendMail = true)
public static function run(string $basePath, bool $force = false, bool $override = false, bool $verbose = false, bool $sendMail = true): string
{
// In force mode, we release the dbupdate lock first
// Necessary in case of an stuck update
@ -228,11 +229,10 @@ class Update
* @param int $version the DB version number of the function
* @param string $prefix the prefix of the function (update, pre_update)
* @param bool $sendMail whether to send emails on success/failure
* @return bool true, if the update function worked
* @throws \Friendica\Network\HTTPException\InternalServerErrorException
*/
public static function runUpdateFunction(int $version, string $prefix, bool $sendMail = true)
public static function runUpdateFunction(int $version, string $prefix, bool $sendMail = true): bool
{
$funcname = $prefix . '_' . $version;
@ -284,6 +284,7 @@ class Update
*
* @param int $update_id number of failed update
* @param string $error_message error message
* @return void
* @throws \Friendica\Network\HTTPException\InternalServerErrorException
*/
private static function updateFailed(int $update_id, string $error_message) {

View File

@ -86,7 +86,7 @@ class UserImport
* @return array|bool
* @throws \Exception
*/
private static function dbImportAssoc($table, $arr)
private static function dbImportAssoc(string $table, array $arr)
{
if (isset($arr['id'])) {
unset($arr['id']);
@ -105,10 +105,11 @@ class UserImport
* Import account file exported from mod/uexport
*
* @param array $file array from $_FILES
* @return void
* @throws \Friendica\Network\HTTPException\InternalServerErrorException
* @throws \ImagickException
*/
public static function importAccount($file)
public static function importAccount(array $file)
{
Logger::notice("Start user import from " . $file['tmp_name']);
/*

View File

@ -60,7 +60,7 @@ class Worker
* @return void
* @throws \Friendica\Network\HTTPException\InternalServerErrorException
*/
public static function processQueue($run_cron, Process $process)
public static function processQueue(bool $run_cron, Process $process)
{
self::$up_start = microtime(true);
@ -169,7 +169,7 @@ class Worker
*
* @return boolean
*/
public static function isReady()
public static function isReady(): bool
{
// Count active workers and compare them with a maximum value that depends on the load
if (self::tooMuchWorkers()) {
@ -204,7 +204,7 @@ class Worker
* @return boolean Returns "true" if tasks are existing
* @throws \Exception
*/
public static function entriesExists()
public static function entriesExists(): bool
{
$stamp = (float)microtime(true);
$exists = DBA::exists('workerqueue', ["NOT `done` AND `pid` = 0 AND `next_try` < ?", DateTimeFormat::utcNow()]);
@ -218,7 +218,7 @@ class Worker
* @return integer Number of deferred entries in the worker queue
* @throws \Exception
*/
private static function deferredEntries()
private static function deferredEntries(): int
{
$stamp = (float)microtime(true);
$count = DBA::count('workerqueue', ["NOT `done` AND `pid` = 0 AND `retrial` > ?", 0]);
@ -233,7 +233,7 @@ class Worker
* @return integer Number of non executed entries in the worker queue
* @throws \Exception
*/
private static function totalEntries()
private static function totalEntries(): int
{
$stamp = (float)microtime(true);
$count = DBA::count('workerqueue', ['done' => false, 'pid' => 0]);
@ -248,7 +248,7 @@ class Worker
* @return integer Number of active worker processes
* @throws \Exception
*/
private static function highestPriority()
private static function highestPriority(): int
{
$stamp = (float)microtime(true);
$condition = ["`pid` = 0 AND NOT `done` AND `next_try` < ?", DateTimeFormat::utcNow()];
@ -269,7 +269,7 @@ class Worker
* @return integer Is there a process running with that priority?
* @throws \Exception
*/
private static function processWithPriorityActive($priority)
private static function processWithPriorityActive(int $priority): int
{
$condition = ["`priority` <= ? AND `pid` != 0 AND NOT `done`", $priority];
return DBA::exists('workerqueue', $condition);
@ -281,7 +281,7 @@ class Worker
* @param mixed $file
* @return bool
*/
private static function validateInclude(&$file)
private static function validateInclude(&$file): bool
{
$orig_file = $file;
@ -321,7 +321,7 @@ class Worker
* @return boolean "true" if further processing should be stopped
* @throws \Friendica\Network\HTTPException\InternalServerErrorException
*/
public static function execute($queue)
public static function execute(array $queue): bool
{
$mypid = getmypid();
@ -454,7 +454,7 @@ class Worker
* @return void
* @throws \Friendica\Network\HTTPException\InternalServerErrorException
*/
private static function execFunction($queue, $funcname, $argv, $method_call)
private static function execFunction(array $queue, string $funcname, array $argv, bool $method_call)
{
$a = DI::app();
@ -543,7 +543,7 @@ class Worker
* @return bool Are more than 3/4 of the maximum connections used?
* @throws \Friendica\Network\HTTPException\InternalServerErrorException
*/
private static function maxConnectionsReached()
private static function maxConnectionsReached(): bool
{
// Fetch the max value from the config. This is needed when the system cannot detect the correct value by itself.
$max = DI::config()->get("system", "max_connections");
@ -627,7 +627,7 @@ class Worker
* @return bool Are there too much workers running?
* @throws \Friendica\Network\HTTPException\InternalServerErrorException
*/
private static function tooMuchWorkers()
private static function tooMuchWorkers(): bool
{
$queues = DI::config()->get("system", "worker_queues", 10);
@ -751,7 +751,7 @@ class Worker
* @return integer Number of active worker processes
* @throws \Exception
*/
private static function activeWorkers()
private static function activeWorkers(): int
{
$stamp = (float)microtime(true);
$count = DI::process()->countCommand('Worker.php');
@ -766,7 +766,7 @@ class Worker
* @return array List of worker process ids
* @throws \Exception
*/
private static function getWorkerPIDList()
private static function getWorkerPIDList(): array
{
$ids = [];
$stamp = (float)microtime(true);
@ -787,7 +787,7 @@ class Worker
/**
* Returns waiting jobs for the current process id
*
* @return array waiting workerqueue jobs
* @return array|bool waiting workerqueue jobs or FALSE on failture
* @throws \Exception
*/
private static function getWaitingJobForPID()
@ -809,7 +809,7 @@ class Worker
* @return array array with next jobs
* @throws \Exception
*/
private static function nextProcess(int $limit)
private static function nextProcess(int $limit): array
{
$priority = self::nextPriority();
if (empty($priority)) {
@ -844,7 +844,7 @@ class Worker
/**
* Returns the priority of the next workerqueue job
*
* @return string priority
* @return string|bool priority or FALSE on failure
* @throws \Exception
*/
private static function nextPriority()
@ -915,7 +915,7 @@ class Worker
/**
* Find and claim the next worker process for us
*
* @return boolean Have we found something?
* @return void
* @throws \Friendica\Network\HTTPException\InternalServerErrorException
*/
private static function findWorkerProcesses()
@ -993,7 +993,7 @@ class Worker
* @return array worker processes
* @throws \Friendica\Network\HTTPException\InternalServerErrorException
*/
public static function workerProcess()
public static function workerProcess(): array
{
// There can already be jobs for us in the queue.
$waiting = self::getWaitingJobForPID();
@ -1003,7 +1003,7 @@ class Worker
$stamp = (float)microtime(true);
if (!DI::lock()->acquire(self::LOCK_PROCESS)) {
return false;
return [];
}
self::$lock_duration += (microtime(true) - $stamp);
@ -1011,7 +1011,9 @@ class Worker
DI::lock()->release(self::LOCK_PROCESS);
return self::getWaitingJobForPID();
// Prevents "Return value of Friendica\Core\Worker::workerProcess() must be of the type array, bool returned"
$process = self::getWaitingJobForPID();
return (is_array($process) ? $process : []);
}
/**
@ -1097,7 +1099,7 @@ class Worker
* @return void
* @throws \Friendica\Network\HTTPException\InternalServerErrorException
*/
public static function spawnWorker($do_cron = false)
public static function spawnWorker(bool $do_cron = false)
{
if (Worker\Daemon::isMode() && DI::config()->get('system', 'worker_fork')) {
self::forkProcess($do_cron);
@ -1231,7 +1233,7 @@ class Worker
return $added;
}
public static function countWorkersByCommand(string $command)
public static function countWorkersByCommand(string $command): int
{
return DBA::count('workerqueue', ['done' => false, 'pid' => 0, 'command' => $command]);
}
@ -1244,7 +1246,7 @@ class Worker
* @param integer $max_level maximum retrial level
* @return integer the next retrial level value
*/
private static function getNextRetrial($queue, $max_level)
private static function getNextRetrial(array $queue, int $max_level): int
{
$created = strtotime($queue['created']);
$retrial_time = time() - $created;
@ -1314,9 +1316,10 @@ class Worker
/**
* Check if the system is inside the defined maintenance window
*
* @param bool $check_last_execution Whether check last execution
* @return boolean
*/
public static function isInMaintenanceWindow(bool $check_last_execution = false)
public static function isInMaintenanceWindow(bool $check_last_execution = false): bool
{
// Calculate the seconds of the start end end of the maintenance window
$start = strtotime(DI::config()->get('system', 'maintenance_start')) % 86400;

View File

@ -65,11 +65,27 @@ abstract class DI
/**
* @return Database\Database
*/
public static function dba()
public static function dba(): Database\Database
{
return self::$dice->create(Database\Database::class);
}
/**
* @return \Friendica\Database\Definition\DbaDefinition
*/
public static function dbaDefinition(): Database\Definition\DbaDefinition
{
return self::$dice->create(Database\Definition\DbaDefinition::class);
}
/**
* @return \Friendica\Database\Definition\ViewDefinition
*/
public static function viewDefinition(): Database\Definition\ViewDefinition
{
return self::$dice->create(Database\Definition\ViewDefinition::class);
}
//
// "App" namespace instances
//

View File

@ -42,7 +42,7 @@ class DBA
*/
const NULL_DATETIME = '0001-01-01 00:00:00';
public static function connect()
public static function connect(): bool
{
return DI::dba()->connect();
}
@ -58,7 +58,7 @@ class DBA
/**
* Perform a reconnect of an existing database connection
*/
public static function reconnect()
public static function reconnect(): bool
{
return DI::dba()->reconnect();
}
@ -77,7 +77,7 @@ class DBA
*
* @return string with either "pdo" or "mysqli"
*/
public static function getDriver()
public static function getDriver(): string
{
return DI::dba()->getDriver();
}
@ -90,7 +90,7 @@ class DBA
*
* @return string
*/
public static function serverInfo()
public static function serverInfo(): string
{
return DI::dba()->serverInfo();
}
@ -101,7 +101,7 @@ class DBA
* @return string
* @throws \Exception
*/
public static function databaseName()
public static function databaseName(): string
{
return DI::dba()->databaseName();
}
@ -112,7 +112,7 @@ class DBA
* @param string $str
* @return string escaped string
*/
public static function escape($str)
public static function escape(string $str): string
{
return DI::dba()->escape($str);
}
@ -122,7 +122,7 @@ class DBA
*
* @return boolean is the database connected?
*/
public static function connected()
public static function connected(): bool
{
return DI::dba()->connected();
}
@ -138,7 +138,7 @@ class DBA
* @param string $sql An SQL string without the values
* @return string The input SQL string modified if necessary.
*/
public static function anyValueFallback($sql)
public static function anyValueFallback(string $sql): string
{
return DI::dba()->anyValueFallback($sql);
}
@ -152,7 +152,7 @@ class DBA
* @param string $sql An SQL string without the values
* @return string The input SQL string modified if necessary.
*/
public static function cleanQuery($sql)
public static function cleanQuery(string $sql): string
{
$search = ["\t", "\n", "\r", " "];
$replace = [' ', ' ', ' ', ' '];
@ -169,7 +169,7 @@ class DBA
* @param array $args Parameter array
* @return array universalized parameter array
*/
public static function getParam($args)
public static function getParam(array $args): array
{
unset($args[0]);
@ -192,7 +192,7 @@ class DBA
* @return bool|object statement object or result object
* @throws \Exception
*/
public static function p($sql)
public static function p(string $sql)
{
$params = self::getParam(func_get_args());
@ -208,8 +208,8 @@ class DBA
* @return boolean Was the query successfull? False is returned only if an error occurred
* @throws \Exception
*/
public static function e($sql) {
public static function e(string $sql): bool
{
$params = self::getParam(func_get_args());
return DI::dba()->e($sql, $params);
@ -218,13 +218,12 @@ class DBA
/**
* Check if data exists
*
* @param string|array $table Table name or array [schema => table]
* @param array $condition array of fields for condition
*
* @param string $table Table name in format schema.table (while scheme is optiona)
* @param array $condition Array of fields for condition
* @return boolean Are there rows for that condition?
* @throws \Exception
*/
public static function exists($table, $condition)
public static function exists(string $table, array $condition): bool
{
return DI::dba()->exists($table, $condition);
}
@ -238,7 +237,7 @@ class DBA
* @return array first row of query
* @throws \Exception
*/
public static function fetchFirst($sql)
public static function fetchFirst(string $sql)
{
$params = self::getParam(func_get_args());
@ -250,7 +249,7 @@ class DBA
*
* @return int Number of rows
*/
public static function affectedRows()
public static function affectedRows(): int
{
return DI::dba()->affectedRows();
}
@ -261,7 +260,7 @@ class DBA
* @param object Statement object
* @return int Number of columns
*/
public static function columnCount($stmt)
public static function columnCount($stmt): int
{
return DI::dba()->columnCount($stmt);
}
@ -271,7 +270,7 @@ class DBA
* @param PDOStatement|mysqli_result|mysqli_stmt Statement object
* @return int Number of rows
*/
public static function numRows($stmt)
public static function numRows($stmt): int
{
return DI::dba()->numRows($stmt);
}
@ -290,14 +289,13 @@ class DBA
/**
* Insert a row into a table
*
* @param string|array $table Table name or array [schema => table]
* @param string $table Table name in format schema.table (while scheme is optiona)
* @param array $param parameter array
* @param int $duplicate_mode What to do on a duplicated entry
*
* @return boolean was the insert successful?
* @throws \Exception
*/
public static function insert($table, array $param, int $duplicate_mode = Database::INSERT_DEFAULT)
public static function insert(string $table, array $param, int $duplicate_mode = Database::INSERT_DEFAULT): bool
{
return DI::dba()->insert($table, $param, $duplicate_mode);
}
@ -306,13 +304,12 @@ class DBA
* Inserts a row with the provided data in the provided table.
* If the data corresponds to an existing row through a UNIQUE or PRIMARY index constraints, it updates the row instead.
*
* @param string|array $table Table name or array [schema => table]
* @param string $table Table name in format schema.table (while scheme is optiona)
* @param array $param parameter array
*
* @return boolean was the insert successful?
* @throws \Exception
*/
public static function replace($table, $param)
public static function replace(string $table, array $param): bool
{
return DI::dba()->replace($table, $param);
}
@ -322,7 +319,7 @@ class DBA
*
* @return integer Last inserted id
*/
public static function lastInsertId()
public static function lastInsertId(): int
{
return DI::dba()->lastInsertId();
}
@ -332,12 +329,11 @@ class DBA
*
* This function can be extended in the future to accept a table array as well.
*
* @param string|array $table Table name or array [schema => table]
*
* @param string $table Table name in format schema.table (while scheme is optiona)
* @return boolean was the lock successful?
* @throws \Exception
*/
public static function lock($table)
public static function lock(string $table): bool
{
return DI::dba()->lock($table);
}
@ -348,7 +344,7 @@ class DBA
* @return boolean was the unlock successful?
* @throws \Exception
*/
public static function unlock()
public static function unlock(): bool
{
return DI::dba()->unlock();
}
@ -358,7 +354,7 @@ class DBA
*
* @return boolean Was the command executed successfully?
*/
public static function transaction()
public static function transaction(): bool
{
return DI::dba()->transaction();
}
@ -368,7 +364,7 @@ class DBA
*
* @return boolean Was the command executed successfully?
*/
public static function commit()
public static function commit(): bool
{
return DI::dba()->commit();
}
@ -378,7 +374,7 @@ class DBA
*
* @return boolean Was the command executed successfully?
*/
public static function rollback()
public static function rollback(): bool
{
return DI::dba()->rollback();
}
@ -386,13 +382,13 @@ class DBA
/**
* Delete a row from a table
*
* @param string|array $table Table name
* @param string $table Table name
* @param array $conditions Field condition(s)
*
* @return boolean was the delete successful?
* @throws \Exception
*/
public static function delete($table, array $conditions, array $options = [])
public static function delete(string $table, array $conditions, array $options = []): bool
{
return DI::dba()->delete($table, $conditions, $options);
}
@ -418,7 +414,7 @@ class DBA
* Only set $old_fields to a boolean value when you are sure that you will update a single row.
* When you set $old_fields to "true" then $fields must contain all relevant fields!
*
* @param string|array $table Table name or array [schema => table]
* @param string $table Table name in format schema.table (while scheme is optiona)
* @param array $fields contains the fields that are updated
* @param array $condition condition array with the key values
* @param array|boolean $old_fields array with the old field values that are about to be replaced (true = update on duplicate, false = don't update identical fields)
@ -427,7 +423,7 @@ class DBA
* @return boolean was the update successfull?
* @throws \Exception
*/
public static function update($table, $fields, $condition, $old_fields = [], $params = [])
public static function update(string $table, array $fields, array $condition, $old_fields = [], array $params = []): bool
{
return DI::dba()->update($table, $fields, $condition, $old_fields, $params);
}
@ -435,7 +431,7 @@ class DBA
/**
* Retrieve a single record from a table and returns it in an associative array
*
* @param string|array $table Table name or array [schema => table]
* @param string|array $table Table name in format schema.table (while scheme is optiona)
* @param array $fields
* @param array $condition
* @param array $params
@ -443,7 +439,7 @@ class DBA
* @throws \Exception
* @see self::select
*/
public static function selectFirst($table, array $fields = [], array $condition = [], $params = [])
public static function selectFirst($table, array $fields = [], array $condition = [], array $params = [])
{
return DI::dba()->selectFirst($table, $fields, $condition, $params);
}
@ -451,7 +447,7 @@ class DBA
/**
* Select rows from a table and fills an array with the data
*
* @param string|array $table Table name or array [schema => table]
* @param string $table Table name in format schema.table (while scheme is optiona)
* @param array $fields Array of selected fields, empty for all
* @param array $condition Array of fields for condition
* @param array $params Array of several parameters
@ -460,7 +456,7 @@ class DBA
* @throws \Exception
* @see self::select
*/
public static function selectToArray($table, array $fields = [], array $condition = [], array $params = [])
public static function selectToArray(string $table, array $fields = [], array $condition = [], array $params = [])
{
return DI::dba()->selectToArray($table, $fields, $condition, $params);
}
@ -468,7 +464,7 @@ class DBA
/**
* Select rows from a table
*
* @param string|array $table Table name or array [schema => table]
* @param string $table Table name in format schema.table (while scheme is optiona)
* @param array $fields Array of selected fields, empty for all
* @param array $condition Array of fields for condition
* @param array $params Array of several parameters
@ -488,7 +484,7 @@ class DBA
* $data = DBA::select($table, $fields, $condition, $params);
* @throws \Exception
*/
public static function select($table, array $fields = [], array $condition = [], array $params = [])
public static function select(string $table, array $fields = [], array $condition = [], array $params = [])
{
return DI::dba()->select($table, $fields, $condition, $params);
}
@ -496,7 +492,7 @@ class DBA
/**
* Counts the rows from a table satisfying the provided condition
*
* @param string|array $table Table name or array [schema => table]
* @param string $table Table name in format schema.table (while scheme is optiona)
* @param array $condition array of fields for condition
* @param array $params Array of several parameters
*
@ -512,7 +508,7 @@ class DBA
* $count = DBA::count($table, $condition);
* @throws \Exception
*/
public static function count($table, array $condition = [], array $params = [])
public static function count(string $table, array $condition = [], array $params = []): int
{
return DI::dba()->count($table, $condition, $params);
}
@ -525,37 +521,30 @@ class DBA
* - [table1, table2, ...]
* - [schema1 => table1, schema2 => table2, table3, ...]
*
* @param string|array $tables
* @param array $tables Table names
* @return string
*/
public static function buildTableString($tables)
public static function buildTableString(array $tables): string
{
if (is_string($tables)) {
$tables = [$tables];
}
$quotedTables = [];
foreach ($tables as $schema => $table) {
if (is_numeric($schema)) {
$quotedTables[] = self::quoteIdentifier($table);
} else {
$quotedTables[] = self::quoteIdentifier($schema) . '.' . self::quoteIdentifier($table);
}
}
return implode(', ', $quotedTables);
// Quote each entry
return implode(',', array_map(['self', 'quoteIdentifier'], $tables));
}
/**
* Escape an identifier (table or field name)
* Escape an identifier (table or field name) optional with a schema like (schema.)table
*
* @param $identifier
* @return string
* @param $identifier Table, field name
* @return string Quotes table or field name
*/
public static function quoteIdentifier($identifier)
public static function quoteIdentifier(string $identifier): string
{
return '`' . str_replace('`', '``', $identifier) . '`';
return implode(
'.',
array_map(
function (string $identifier) { return '`' . str_replace('`', '``', $identifier) . '`'; },
explode('.', $identifier)
)
);
}
/**
@ -576,7 +565,7 @@ class DBA
* @param array $condition
* @return string
*/
public static function buildCondition(array &$condition = [])
public static function buildCondition(array &$condition = []): string
{
$condition = self::collapseCondition($condition);
@ -600,7 +589,7 @@ class DBA
* @param array $condition
* @return array
*/
public static function collapseCondition(array $condition)
public static function collapseCondition(array $condition): array
{
// Ensures an always true condition is returned
if (count($condition) < 1) {
@ -675,7 +664,7 @@ class DBA
* @return array A collapsed condition
* @see DBA::collapseCondition() for the condition array formats
*/
public static function mergeConditions(array ...$conditions)
public static function mergeConditions(array ...$conditions): array
{
if (count($conditions) == 1) {
return current($conditions);
@ -724,7 +713,7 @@ class DBA
* @param array $params
* @return string
*/
public static function buildParameter(array $params = [])
public static function buildParameter(array $params = []): string
{
$groupby_string = '';
if (!empty($params['group_by'])) {
@ -771,7 +760,7 @@ class DBA
*
* @return array Data array
*/
public static function toArray($stmt, $do_close = true, int $count = 0)
public static function toArray($stmt, bool $do_close = true, int $count = 0): array
{
return DI::dba()->toArray($stmt, $do_close, $count);
}
@ -783,7 +772,7 @@ class DBA
* @param array $fields
* @return array casted fields
*/
public static function castFields(string $table, array $fields)
public static function castFields(string $table, array $fields): array
{
return DI::dba()->castFields($table, $fields);
}
@ -793,7 +782,7 @@ class DBA
*
* @return string Error number (0 if no error)
*/
public static function errorNo()
public static function errorNo(): int
{
return DI::dba()->errorNo();
}
@ -803,7 +792,7 @@ class DBA
*
* @return string Error message ('' if no error)
*/
public static function errorMessage()
public static function errorMessage(): string
{
return DI::dba()->errorMessage();
}
@ -814,7 +803,7 @@ class DBA
* @param object $stmt statement object
* @return boolean was the close successful?
*/
public static function close($stmt)
public static function close($stmt): bool
{
return DI::dba()->close($stmt);
}
@ -827,7 +816,7 @@ class DBA
* 'amount' => Number of concurrent database processes
* @throws \Exception
*/
public static function processlist()
public static function processlist(): array
{
return DI::dba()->processlist();
}
@ -847,10 +836,9 @@ class DBA
* Checks if $array is a filled array with at least one entry.
*
* @param mixed $array A filled array with at least one entry
*
* @return boolean Whether $array is a filled array or an object with rows
*/
public static function isResult($array)
public static function isResult($array): bool
{
return DI::dba()->isResult($array);
}
@ -862,7 +850,7 @@ class DBA
* @param boolean $add_quotation add quotation marks for string values
* @return void
*/
public static function escapeArray(&$arr, $add_quotation = false)
public static function escapeArray(&$arr, bool $add_quotation = false)
{
DI::dba()->escapeArray($arr, $add_quotation);
}

View File

@ -22,13 +22,12 @@
namespace Friendica\Database;
use Exception;
use Friendica\Core\Hook;
use Friendica\Core\Logger;
use Friendica\Core\Renderer;
use Friendica\DI;
use Friendica\Model\Item;
use Friendica\Model\User;
use Friendica\Util\DateTimeFormat;
use Friendica\Util\Writer\DbaDefinitionSqlWriter;
/**
* This class contains functions that doesn't need to know if pdo, mysqli or whatever is used.
@ -42,13 +41,6 @@ class DBStructure
const RENAME_COLUMN = 0;
const RENAME_PRIMARY_KEY = 1;
/**
* Database structure definition loaded from config/dbstructure.config.php
*
* @var array
*/
private static $definition = [];
/**
* Set a database version to trigger update functions
*
@ -73,7 +65,7 @@ class DBStructure
*/
public static function dropTables(bool $execute)
{
$postupdate = DI::config()->get("system", "post_update_version", PostUpdate::VERSION);
$postupdate = DI::config()->get('system', 'post_update_version', PostUpdate::VERSION);
if ($postupdate < PostUpdate::VERSION) {
echo DI::l10n()->t('The post update is at version %d, it has to be at %d to safely drop the tables.', $postupdate, PostUpdate::VERSION);
return;
@ -84,7 +76,7 @@ class DBStructure
'deliverq', 'dsprphotoq', 'ffinder', 'sign', 'spam', 'term', 'user-item', 'thread', 'item', 'challenge',
'auth_codes', 'tokens', 'clients', 'profile_check', 'host'];
$tables = DBA::selectToArray(['INFORMATION_SCHEMA' => 'TABLES'], ['TABLE_NAME'],
$tables = DBA::selectToArray('INFORMATION_SCHEMA.TABLES', ['TABLE_NAME'],
['TABLE_SCHEMA' => DBA::databaseName(), 'TABLE_TYPE' => 'BASE TABLE']);
if (empty($tables)) {
@ -119,13 +111,13 @@ class DBStructure
public static function convertToInnoDB()
{
$tables = DBA::selectToArray(
['information_schema' => 'tables'],
'information_schema.tables',
['table_name'],
['engine' => 'MyISAM', 'table_schema' => DBA::databaseName()]
);
$tables = array_merge($tables, DBA::selectToArray(
['information_schema' => 'tables'],
'information_schema.tables',
['table_name'],
['engine' => 'InnoDB', 'ROW_FORMAT' => ['COMPACT', 'REDUNDANT'], 'table_schema' => DBA::databaseName()]
));
@ -153,7 +145,7 @@ class DBStructure
*
* @return string Error message
*/
private static function printUpdateError($message)
private static function printUpdateError(string $message): string
{
echo DI::l10n()->t("\nError %d occurred during database update:\n%s\n",
DBA::errorNo(), DBA::errorMessage());
@ -161,334 +153,15 @@ class DBStructure
return DI::l10n()->t('Errors encountered performing database changes: ') . $message . EOL;
}
public static function writeStructure()
{
$tables = [];
foreach (self::definition(null) as $name => $definition) {
$indexes = [[
'name' => 'Name',
'fields' => 'Fields',
],
[
'name' => '-',
'fields' => '-',
]];
$lengths = ['name' => 4, 'fields' => 6];
foreach ($definition['indexes'] as $key => $value) {
$fieldlist = implode(', ', $value);
$indexes[] = ['name' => $key, 'fields' => $fieldlist];
$lengths['name'] = max($lengths['name'], strlen($key));
$lengths['fields'] = max($lengths['fields'], strlen($fieldlist));
}
array_walk_recursive($indexes, function(&$value, $key) use ($lengths)
{
$value = str_pad($value, $lengths[$key], $value === '-' ? '-' : ' ');
});
$foreign = [];
$fields = [[
'name' => 'Field',
'comment' => 'Description',
'type' => 'Type',
'null' => 'Null',
'primary' => 'Key',
'default' => 'Default',
'extra' => 'Extra',
],
[
'name' => '-',
'comment' => '-',
'type' => '-',
'null' => '-',
'primary' => '-',
'default' => '-',
'extra' => '-',
]];
$lengths = [
'name' => 5,
'comment' => 11,
'type' => 4,
'null' => 4,
'primary' => 3,
'default' => 7,
'extra' => 5,
];
foreach ($definition['fields'] as $key => $value) {
$field = [];
$field['name'] = $key;
$field['comment'] = $value['comment'] ?? '';
$field['type'] = $value['type'];
$field['null'] = ($value['not null'] ?? false) ? 'NO' : 'YES';
$field['primary'] = ($value['primary'] ?? false) ? 'PRI' : '';
$field['default'] = $value['default'] ?? 'NULL';
$field['extra'] = $value['extra'] ?? '';
foreach ($field as $fieldname => $fieldvalue) {
$lengths[$fieldname] = max($lengths[$fieldname] ?? 0, strlen($fieldvalue));
}
$fields[] = $field;
if (!empty($value['foreign'])) {
$foreign[] = [
'field' => $key,
'targettable' => array_keys($value['foreign'])[0],
'targetfield' => array_values($value['foreign'])[0]
];
}
}
array_walk_recursive($fields, function(&$value, $key) use ($lengths)
{
$value = str_pad($value, $lengths[$key], $value === '-' ? '-' : ' ');
});
$tables[] = ['name' => $name, 'comment' => $definition['comment']];
$content = Renderer::replaceMacros(Renderer::getMarkupTemplate('structure.tpl'), [
'$name' => $name,
'$comment' => $definition['comment'],
'$fields' => $fields,
'$indexes' => $indexes,
'$foreign' => $foreign,
]);
$filename = DI::basePath() . '/doc/database/db_' . $name . '.md';
file_put_contents($filename, $content);
}
asort($tables);
$content = Renderer::replaceMacros(Renderer::getMarkupTemplate('tables.tpl'), [
'$tables' => $tables,
]);
$filename = DI::basePath() . '/doc/database.md';
file_put_contents($filename, $content);
}
public static function printStructure($basePath)
{
$database = self::definition($basePath, false);
echo "-- ------------------------------------------\n";
echo "-- " . FRIENDICA_PLATFORM . " " . FRIENDICA_VERSION . " (" . FRIENDICA_CODENAME, ")\n";
echo "-- DB_UPDATE_VERSION " . DB_UPDATE_VERSION . "\n";
echo "-- ------------------------------------------\n\n\n";
foreach ($database as $name => $structure) {
echo "--\n";
echo "-- TABLE $name\n";
echo "--\n";
self::createTable($name, $structure, true, false);
echo "\n";
}
View::printStructure($basePath);
}
/**
* Loads the database structure definition from the static/dbstructure.config.php file.
* On first pass, defines DB_UPDATE_VERSION constant.
*
* @see static/dbstructure.config.php
* @param boolean $with_addons_structure Whether to tack on addons additional tables
* @param string $basePath The base path of this application
* @return array
* @throws Exception
*/
public static function definition($basePath, $with_addons_structure = true)
{
if (!self::$definition) {
if (empty($basePath)) {
$basePath = DI::app()->getBasePath();
}
$filename = $basePath . '/static/dbstructure.config.php';
if (!is_readable($filename)) {
throw new Exception('Missing database structure config file static/dbstructure.config.php');
}
$definition = require $filename;
if (!$definition) {
throw new Exception('Corrupted database structure config file static/dbstructure.config.php');
}
self::$definition = $definition;
} else {
$definition = self::$definition;
}
if ($with_addons_structure) {
Hook::callAll('dbstructure_definition', $definition);
}
return $definition;
}
/**
* Get field data for the given table
*
* @param string $table
* @param array $data data fields
* @return array fields for the given
*/
public static function getFieldsForTable(string $table, array $data = [])
{
$definition = DBStructure::definition('', false);
if (empty($definition[$table])) {
return [];
}
$fieldnames = array_keys($definition[$table]['fields']);
$fields = [];
// Assign all field that are present in the table
foreach ($fieldnames as $field) {
if (isset($data[$field])) {
// Limit the length of varchar, varbinary, char and binrary fields
if (is_string($data[$field]) && preg_match("/char\((\d*)\)/", $definition[$table]['fields'][$field]['type'], $result)) {
$data[$field] = mb_substr($data[$field], 0, $result[1]);
} elseif (is_string($data[$field]) && preg_match("/binary\((\d*)\)/", $definition[$table]['fields'][$field]['type'], $result)) {
$data[$field] = substr($data[$field], 0, $result[1]);
}
$fields[$field] = $data[$field];
}
}
return $fields;
}
private static function createTable($name, $structure, $verbose, $action)
{
$r = true;
$engine = "";
$comment = "";
$sql_rows = [];
$primary_keys = [];
$foreign_keys = [];
foreach ($structure["fields"] as $fieldname => $field) {
$sql_rows[] = "`" . DBA::escape($fieldname) . "` " . self::FieldCommand($field);
if (!empty($field['primary'])) {
$primary_keys[] = $fieldname;
}
if (!empty($field['foreign'])) {
$foreign_keys[$fieldname] = $field;
}
}
if (!empty($structure["indexes"])) {
foreach ($structure["indexes"] as $indexname => $fieldnames) {
$sql_index = self::createIndex($indexname, $fieldnames, "");
if (!is_null($sql_index)) {
$sql_rows[] = $sql_index;
}
}
}
foreach ($foreign_keys as $fieldname => $parameters) {
$sql_rows[] = self::foreignCommand($name, $fieldname, $parameters);
}
if (isset($structure["engine"])) {
$engine = " ENGINE=" . $structure["engine"];
}
if (isset($structure["comment"])) {
$comment = " COMMENT='" . DBA::escape($structure["comment"]) . "'";
}
$sql = implode(",\n\t", $sql_rows);
$sql = sprintf("CREATE TABLE IF NOT EXISTS `%s` (\n\t", DBA::escape($name)) . $sql .
"\n)" . $engine . " DEFAULT COLLATE utf8mb4_general_ci" . $comment;
if ($verbose) {
echo $sql . ";\n";
}
if ($action) {
$r = DBA::e($sql);
}
return $r;
}
private static function FieldCommand($parameters, $create = true)
{
$fieldstruct = $parameters["type"];
if (isset($parameters["Collation"])) {
$fieldstruct .= " COLLATE " . $parameters["Collation"];
}
if (isset($parameters["not null"])) {
$fieldstruct .= " NOT NULL";
}
if (isset($parameters["default"])) {
if (strpos(strtolower($parameters["type"]), "int") !== false) {
$fieldstruct .= " DEFAULT " . $parameters["default"];
} else {
$fieldstruct .= " DEFAULT '" . $parameters["default"] . "'";
}
}
if (isset($parameters["extra"])) {
$fieldstruct .= " " . $parameters["extra"];
}
if (isset($parameters["comment"])) {
$fieldstruct .= " COMMENT '" . DBA::escape($parameters["comment"]) . "'";
}
/*if (($parameters["primary"] != "") && $create)
$fieldstruct .= " PRIMARY KEY";*/
return ($fieldstruct);
}
private static function createIndex($indexname, $fieldnames, $method = "ADD")
{
$method = strtoupper(trim($method));
if ($method != "" && $method != "ADD") {
throw new Exception("Invalid parameter 'method' in self::createIndex(): '$method'");
}
if (in_array($fieldnames[0], ["UNIQUE", "FULLTEXT"])) {
$index_type = array_shift($fieldnames);
$method .= " " . $index_type;
}
$names = "";
foreach ($fieldnames as $fieldname) {
if ($names != "") {
$names .= ",";
}
if (preg_match('|(.+)\((\d+)\)|', $fieldname, $matches)) {
$names .= "`" . DBA::escape($matches[1]) . "`(" . intval($matches[2]) . ")";
} else {
$names .= "`" . DBA::escape($fieldname) . "`";
}
}
if ($indexname == "PRIMARY") {
return sprintf("%s PRIMARY KEY(%s)", $method, $names);
}
$sql = sprintf("%s INDEX `%s` (%s)", $method, DBA::escape($indexname), $names);
return ($sql);
}
/**
* Perform a database structure dryrun (means: just simulating)
*
* @return string Empty string if the update is successful, error messages otherwise
* @throws Exception
*/
public static function dryRun()
public static function dryRun(): string
{
self::update(DI::app()->getBasePath(), true, false);
return self::update(true, false);
}
/**
@ -500,13 +173,13 @@ class DBStructure
* @return string Empty string if the update is successful, error messages otherwise
* @throws Exception
*/
public static function performUpdate(bool $enable_maintenance_mode = true, bool $verbose = false)
public static function performUpdate(bool $enable_maintenance_mode = true, bool $verbose = false): string
{
if ($enable_maintenance_mode) {
DI::config()->set('system', 'maintenance', 1);
}
$status = self::update(DI::app()->getBasePath(), $verbose, true);
$status = self::update($verbose, true);
if ($enable_maintenance_mode) {
DI::config()->set('system', 'maintenance', 0);
@ -519,20 +192,17 @@ class DBStructure
/**
* Updates DB structure from the installation and returns eventual errors messages
*
* @param string $basePath The base path of this application
*
* @return string Empty string if the update is successful, error messages otherwise
* @throws Exception
*/
public static function install(string $basePath)
public static function install(): string
{
return self::update($basePath, false, true, true);
return self::update(false, true, true);
}
/**
* Updates DB structure and returns eventual errors messages
*
* @param string $basePath The base path of this application
* @param bool $verbose
* @param bool $action Whether to actually apply the update
* @param bool $install Is this the initial update during the installation?
@ -541,7 +211,7 @@ class DBStructure
* @return string Empty string if the update is successful, error messages otherwise
* @throws Exception
*/
private static function update($basePath, $verbose, $action, $install = false, array $tables = null, array $definition = null)
private static function update(bool $verbose, bool $action, bool $install = false, array $tables = null, array $definition = null): string
{
$in_maintenance_mode = DI::config()->get('system', 'maintenance');
@ -579,7 +249,7 @@ class DBStructure
// Get the definition
if (is_null($definition)) {
$definition = self::definition($basePath);
$definition = DI::dbaDefinition()->getAll();
}
// MySQL >= 5.7.4 doesn't support the IGNORE keyword in ALTER TABLE statements
@ -595,10 +265,16 @@ class DBStructure
$is_new_table = false;
$sql3 = "";
if (!isset($database[$name])) {
$r = self::createTable($name, $structure, $verbose, $action);
$sql = DbaDefinitionSqlWriter::createTable($name, $structure, $verbose, $action);
if ($verbose) {
echo $sql;
}
if ($action) {
$r = DBA::e($sql);
if (!DBA::isResult($r)) {
$errors .= self::printUpdateError($name);
}
}
$is_new_table = true;
} else {
/*
@ -606,15 +282,15 @@ class DBStructure
* or the definition differ from current status
* and index name doesn't start with "local_"
*/
foreach ($database[$name]["indexes"] as $indexname => $fieldnames) {
$current_index_definition = implode(",", $fieldnames);
if (isset($structure["indexes"][$indexname])) {
$new_index_definition = implode(",", $structure["indexes"][$indexname]);
foreach ($database[$name]["indexes"] as $indexName => $fieldNames) {
$current_index_definition = implode(",", $fieldNames);
if (isset($structure["indexes"][$indexName])) {
$new_index_definition = implode(",", $structure["indexes"][$indexName]);
} else {
$new_index_definition = "__NOT_SET__";
}
if ($current_index_definition != $new_index_definition && substr($indexname, 0, 6) != 'local_') {
$sql2 = self::dropIndex($indexname);
if ($current_index_definition != $new_index_definition && substr($indexName, 0, 6) != 'local_') {
$sql2 = DbaDefinitionSqlWriter::dropIndex($indexName);
if ($sql3 == "") {
$sql3 = "ALTER" . $ignore . " TABLE `" . $name . "` " . $sql2;
} else {
@ -623,9 +299,9 @@ class DBStructure
}
}
// Compare the field structure field by field
foreach ($structure["fields"] as $fieldname => $parameters) {
if (!isset($database[$name]["fields"][$fieldname])) {
$sql2 = self::addTableField($fieldname, $parameters);
foreach ($structure["fields"] as $fieldName => $parameters) {
if (!isset($database[$name]["fields"][$fieldName])) {
$sql2 = DbaDefinitionSqlWriter::addTableField($fieldName, $parameters);
if ($sql3 == "") {
$sql3 = "ALTER" . $ignore . " TABLE `" . $name . "` " . $sql2;
} else {
@ -633,7 +309,7 @@ class DBStructure
}
} else {
// Compare the field definition
$field_definition = $database[$name]["fields"][$fieldname];
$field_definition = $database[$name]["fields"][$fieldName];
// Remove the relation data that is used for the referential integrity
unset($parameters['relation']);
@ -653,7 +329,7 @@ class DBStructure
$current_field_definition = DBA::cleanQuery(implode(",", $field_definition));
$new_field_definition = DBA::cleanQuery(implode(",", $parameters));
if ($current_field_definition != $new_field_definition) {
$sql2 = self::modifyTableField($fieldname, $parameters);
$sql2 = DbaDefinitionSqlWriter::modifyTableField($fieldName, $parameters);
if ($sql3 == "") {
$sql3 = "ALTER" . $ignore . " TABLE `" . $name . "` " . $sql2;
} else {
@ -670,15 +346,15 @@ class DBStructure
* Don't create keys if table is new
*/
if (!$is_new_table) {
foreach ($structure["indexes"] as $indexname => $fieldnames) {
if (isset($database[$name]["indexes"][$indexname])) {
$current_index_definition = implode(",", $database[$name]["indexes"][$indexname]);
foreach ($structure["indexes"] as $indexName => $fieldNames) {
if (isset($database[$name]["indexes"][$indexName])) {
$current_index_definition = implode(",", $database[$name]["indexes"][$indexName]);
} else {
$current_index_definition = "__NOT_SET__";
}
$new_index_definition = implode(",", $fieldnames);
$new_index_definition = implode(",", $fieldNames);
if ($current_index_definition != $new_index_definition) {
$sql2 = self::createIndex($indexname, $fieldnames);
$sql2 = DbaDefinitionSqlWriter::createIndex($indexName, $fieldNames);
if ($sql2 != "") {
if ($sql3 == "") {
@ -694,17 +370,17 @@ class DBStructure
// Foreign keys
// Compare the field structure field by field
foreach ($structure["fields"] as $fieldname => $parameters) {
foreach ($structure["fields"] as $fieldName => $parameters) {
if (empty($parameters['foreign'])) {
continue;
}
$constraint = self::getConstraintName($name, $fieldname, $parameters);
$constraint = self::getConstraintName($name, $fieldName, $parameters);
unset($existing_foreign_keys[$constraint]);
if (empty($database[$name]['foreign_keys'][$constraint])) {
$sql2 = self::addForeignKey($name, $fieldname, $parameters);
$sql2 = DbaDefinitionSqlWriter::addForeignKey($fieldName, $parameters);
if ($sql3 == "") {
$sql3 = "ALTER" . $ignore . " TABLE `" . $name . "` " . $sql2;
@ -715,7 +391,7 @@ class DBStructure
}
foreach ($existing_foreign_keys as $param) {
$sql2 = self::dropForeignKey($param['CONSTRAINT_NAME']);
$sql2 = DbaDefinitionSqlWriter::dropForeignKey($param['CONSTRAINT_NAME']);
if ($sql3 == "") {
$sql3 = "ALTER" . $ignore . " TABLE `" . $name . "` " . $sql2;
@ -767,9 +443,9 @@ class DBStructure
// Now have a look at the field collations
// Compare the field structure field by field
foreach ($structure["fields"] as $fieldname => $parameters) {
foreach ($structure["fields"] as $fieldName => $parameters) {
// Compare the field definition
$field_definition = ($database[$name]["fields"][$fieldname] ?? '') ?: ['Collation' => ''];
$field_definition = ($database[$name]["fields"][$fieldName] ?? '') ?: ['Collation' => ''];
// Define the default collation if not given
if (!isset($parameters['Collation']) && !empty($field_definition['Collation'])) {
@ -779,7 +455,7 @@ class DBStructure
}
if ($field_definition['Collation'] != $parameters['Collation']) {
$sql2 = self::modifyTableField($fieldname, $parameters);
$sql2 = DbaDefinitionSqlWriter::modifyTableField($fieldName, $parameters);
if (($sql3 == "") || (substr($sql3, -2, 2) == "; ")) {
$sql3 .= "ALTER" . $ignore . " TABLE `" . $name . "` " . $sql2;
} else {
@ -826,23 +502,29 @@ class DBStructure
return $errors;
}
private static function tableStructure($table)
/**
* Returns an array with table structure information
*
* @param string $table Name of table
* @return array Table structure information
*/
private static function tableStructure(string $table): array
{
// This query doesn't seem to be executable as a prepared statement
$indexes = DBA::toArray(DBA::p("SHOW INDEX FROM " . DBA::quoteIdentifier($table)));
$fields = DBA::selectToArray(['INFORMATION_SCHEMA' => 'COLUMNS'],
$fields = DBA::selectToArray('INFORMATION_SCHEMA.COLUMNS',
['COLUMN_NAME', 'COLUMN_TYPE', 'IS_NULLABLE', 'COLUMN_DEFAULT', 'EXTRA',
'COLUMN_KEY', 'COLLATION_NAME', 'COLUMN_COMMENT'],
["`TABLE_SCHEMA` = ? AND `TABLE_NAME` = ?",
DBA::databaseName(), $table]);
$foreign_keys = DBA::selectToArray(['INFORMATION_SCHEMA' => 'KEY_COLUMN_USAGE'],
$foreign_keys = DBA::selectToArray('INFORMATION_SCHEMA.KEY_COLUMN_USAGE',
['COLUMN_NAME', 'CONSTRAINT_NAME', 'REFERENCED_TABLE_NAME', 'REFERENCED_COLUMN_NAME'],
["`TABLE_SCHEMA` = ? AND `TABLE_NAME` = ? AND `REFERENCED_TABLE_SCHEMA` IS NOT NULL",
DBA::databaseName(), $table]);
$table_status = DBA::selectFirst(['INFORMATION_SCHEMA' => 'TABLES'],
$table_status = DBA::selectFirst('INFORMATION_SCHEMA.TABLES',
['ENGINE', 'TABLE_COLLATION', 'TABLE_COMMENT'],
["`TABLE_SCHEMA` = ? AND `TABLE_NAME` = ?",
DBA::databaseName(), $table]);
@ -909,65 +591,20 @@ class DBStructure
}
}
return ["fields" => $fielddata, "indexes" => $indexdata,
"foreign_keys" => $foreigndata, "table_status" => $table_status];
return [
'fields' => $fielddata,
'indexes' => $indexdata,
'foreign_keys' => $foreigndata,
'table_status' => $table_status
];
}
private static function dropIndex($indexname)
{
$sql = sprintf("DROP INDEX `%s`", DBA::escape($indexname));
return ($sql);
}
private static function addTableField($fieldname, $parameters)
{
$sql = sprintf("ADD `%s` %s", DBA::escape($fieldname), self::FieldCommand($parameters));
return ($sql);
}
private static function modifyTableField($fieldname, $parameters)
{
$sql = sprintf("MODIFY `%s` %s", DBA::escape($fieldname), self::FieldCommand($parameters, false));
return ($sql);
}
private static function getConstraintName(string $tablename, string $fieldname, array $parameters)
private static function getConstraintName(string $tableName, string $fieldName, array $parameters): string
{
$foreign_table = array_keys($parameters['foreign'])[0];
$foreign_field = array_values($parameters['foreign'])[0];
return $tablename . "-" . $fieldname. "-" . $foreign_table. "-" . $foreign_field;
}
private static function foreignCommand(string $tablename, string $fieldname, array $parameters) {
$foreign_table = array_keys($parameters['foreign'])[0];
$foreign_field = array_values($parameters['foreign'])[0];
$sql = "FOREIGN KEY (`" . $fieldname . "`) REFERENCES `" . $foreign_table . "` (`" . $foreign_field . "`)";
if (!empty($parameters['foreign']['on update'])) {
$sql .= " ON UPDATE " . strtoupper($parameters['foreign']['on update']);
} else {
$sql .= " ON UPDATE RESTRICT";
}
if (!empty($parameters['foreign']['on delete'])) {
$sql .= " ON DELETE " . strtoupper($parameters['foreign']['on delete']);
} else {
$sql .= " ON DELETE CASCADE";
}
return $sql;
}
private static function addForeignKey(string $tablename, string $fieldname, array $parameters)
{
return sprintf("ADD %s", self::foreignCommand($tablename, $fieldname, $parameters));
}
private static function dropForeignKey(string $constraint)
{
return sprintf("DROP FOREIGN KEY `%s`", $constraint);
return $tableName . '-' . $fieldName. '-' . $foreign_table. '-' . $foreign_field;
}
/**
@ -983,7 +620,7 @@ class DBStructure
* @return boolean Was the renaming successful?
* @throws Exception
*/
public static function rename($table, $columns, $type = self::RENAME_COLUMN)
public static function rename(string $table, array $columns, int $type = self::RENAME_COLUMN): bool
{
if (empty($table) || empty($columns)) {
return false;
@ -1019,7 +656,7 @@ class DBStructure
return false;
}
$sql .= ";";
$sql .= ';';
$stmt = DBA::p($sql);
@ -1043,7 +680,7 @@ class DBStructure
* @return boolean Does the table exist?
* @throws Exception
*/
public static function existsColumn($table, $columns = [])
public static function existsColumn(string $table, array $columns = []): bool
{
if (empty($table)) {
return false;
@ -1079,39 +716,33 @@ class DBStructure
/**
* Check if a foreign key exists for the given table field
*
* @param string $table
* @param string $field
* @return boolean
* @param string $table Table name
* @param string $field Field name
* @return boolean Wether a foreign key exists
*/
public static function existsForeignKeyForField(string $table, string $field)
public static function existsForeignKeyForField(string $table, string $field): bool
{
return DBA::exists(['INFORMATION_SCHEMA' => 'KEY_COLUMN_USAGE'],
return DBA::exists('INFORMATION_SCHEMA.KEY_COLUMN_USAGE',
["`TABLE_SCHEMA` = ? AND `TABLE_NAME` = ? AND `COLUMN_NAME` = ? AND `REFERENCED_TABLE_SCHEMA` IS NOT NULL",
DBA::databaseName(), $table, $field]);
}
/**
* Check if a table exists
*
* @param string|array $table Table name
*
* @param string $table Single table name (please loop yourself)
* @return boolean Does the table exist?
* @throws Exception
*/
public static function existsTable($table)
public static function existsTable(string $table): bool
{
if (empty($table)) {
return false;
}
if (is_array($table)) {
$condition = ['table_schema' => key($table), 'table_name' => current($table)];
} else {
$condition = ['table_schema' => DBA::databaseName(), 'table_name' => $table];
}
$result = DBA::exists(['information_schema' => 'tables'], $condition);
return $result;
return DBA::exists('information_schema.tables', $condition);
}
/**
@ -1122,7 +753,7 @@ class DBStructure
* @return array An array of the table columns
* @throws Exception
*/
public static function getColumns($table)
public static function getColumns(string $table): array
{
$stmtColumns = DBA::p("SHOW COLUMNS FROM `" . $table . "`");
return DBA::toArray($stmtColumns);
@ -1130,6 +761,9 @@ class DBStructure
/**
* Check if initial database values do exist - or create them
*
* @param bool $verbose Whether to output messages
* @return void
*/
public static function checkInitialValues(bool $verbose = false)
{
@ -1163,9 +797,9 @@ class DBStructure
if (self::existsTable('user') && !DBA::exists('user', ['uid' => 0])) {
$user = [
"verified" => true,
"page-flags" => User::PAGE_FLAGS_SOAPBOX,
"account-type" => User::ACCOUNT_TYPE_RELAY,
'verified' => true,
'page-flags' => User::PAGE_FLAGS_SOAPBOX,
'account-type' => User::ACCOUNT_TYPE_RELAY,
];
DBA::insert('user', $user);
$lastid = DBA::lastInsertId();
@ -1265,12 +899,14 @@ class DBStructure
*
* @return boolean
*/
private static function isUpdating()
private static function isUpdating(): bool
{
$isUpdate = false;
$processes = DBA::select(['information_schema' => 'processlist'], ['info'],
['db' => DBA::databaseName(), 'command' => ['Query', 'Execute']]);
$processes = DBA::select('information_schema.processlist', ['info'], [
'db' => DBA::databaseName(),
'command' => ['Query', 'Execute']
]);
while ($process = DBA::fetch($processes)) {
$parts = explode(' ', $process['info']);

View File

@ -23,9 +23,12 @@ namespace Friendica\Database;
use Friendica\Core\Config\ValueObject\Cache;
use Friendica\Core\System;
use Friendica\Database\Definition\DbaDefinition;
use Friendica\Database\Definition\ViewDefinition;
use Friendica\Network\HTTPException\ServiceUnavailableException;
use Friendica\Util\DateTimeFormat;
use Friendica\Util\Profiler;
use InvalidArgumentException;
use mysqli;
use mysqli_result;
use mysqli_stmt;
@ -63,7 +66,7 @@ class Database
protected $server_info = '';
/** @var PDO|mysqli */
protected $connection;
protected $driver;
protected $driver = '';
protected $pdo_emulate_prepares = false;
private $error = false;
private $errorno = 0;
@ -72,23 +75,29 @@ class Database
protected $in_retrial = false;
protected $testmode = false;
private $relation = [];
/** @var DbaDefinition */
protected $dbaDefinition;
/** @var ViewDefinition */
protected $viewDefinition;
public function __construct(Cache $configCache, Profiler $profiler, LoggerInterface $logger)
public function __construct(Cache $configCache, Profiler $profiler, DbaDefinition $dbaDefinition, ViewDefinition $viewDefinition, LoggerInterface $logger)
{
// We are storing these values for being able to perform a reconnect
$this->configCache = $configCache;
$this->profiler = $profiler;
$this->logger = $logger;
$this->dbaDefinition = $dbaDefinition;
$this->viewDefinition = $viewDefinition;
$this->connect();
if ($this->isConnected()) {
// Loads DB_UPDATE_VERSION constant
DBStructure::definition($configCache->get('system', 'basepath'), false);
}
}
public function connect()
/**
* Tries to connect to database
*
* @return bool Success
*/
public function connect(): bool
{
if (!is_null($this->connection) && $this->connected()) {
return $this->connected;
@ -175,7 +184,7 @@ class Database
// No suitable SQL driver was found.
if (!$this->connected) {
$this->driver = null;
$this->driver = '';
$this->connection = null;
}
@ -227,7 +236,7 @@ class Database
}
}
$this->driver = null;
$this->driver = '';
$this->connected = false;
}
@ -255,7 +264,7 @@ class Database
*
* @return string with either "pdo" or "mysqli"
*/
public function getDriver()
public function getDriver(): string
{
return $this->driver;
}
@ -266,9 +275,9 @@ class Database
* This function discriminate between the deprecated mysql API and the current
* object-oriented mysqli API. Example of returned string: 5.5.46-0+deb8u1
*
* @return string
* @return string Database server information
*/
public function serverInfo()
public function serverInfo(): string
{
if ($this->server_info == '') {
switch ($this->driver) {
@ -286,10 +295,10 @@ class Database
/**
* Returns the selected database name
*
* @return string
* @return string Database name
* @throws \Exception
*/
public function databaseName()
public function databaseName(): string
{
$ret = $this->p("SELECT DATABASE() AS `db`");
$data = $this->toArray($ret);
@ -300,10 +309,10 @@ class Database
* Analyze a database query and log this if some conditions are met.
*
* @param string $query The database query that will be analyzed
*
* @return void
* @throws \Exception
*/
private function logIndex($query)
private function logIndex(string $query)
{
if (!$this->configCache->get('system', 'db_log_index')) {
@ -359,11 +368,10 @@ class Database
* Removes every not allowlisted character from the identifier string
*
* @param string $identifier
*
* @return string sanitized identifier
* @throws \Exception
*/
private function sanitizeIdentifier($identifier)
private function sanitizeIdentifier(string $identifier): string
{
return preg_replace('/[^A-Za-z0-9_\-]+/', '', $identifier);
}
@ -383,11 +391,21 @@ class Database
}
}
public function isConnected()
/**
* Returns connected flag
*
* @return bool Whether connection to database was success
*/
public function isConnected(): bool
{
return $this->connected;
}
/**
* Checks connection status
*
* @return bool Whether connection to database was success
*/
public function connected()
{
$connected = false;
@ -424,7 +442,7 @@ class Database
*
* @return string The input SQL string modified if necessary.
*/
public function anyValueFallback($sql)
public function anyValueFallback(string $sql): string
{
$server_info = $this->serverInfo();
if (version_compare($server_info, '5.7.5', '<') ||
@ -442,7 +460,7 @@ class Database
*
* @return string The replaced SQL query
*/
private function replaceParameters($sql, $args)
private function replaceParameters(string $sql, array $args): string
{
$offset = 0;
foreach ($args as $param => $value) {
@ -476,7 +494,7 @@ class Database
* @return bool|object statement object or result object
* @throws \Exception
*/
public function p($sql)
public function p(string $sql)
{
$this->profiler->startRecording('database');
@ -541,7 +559,7 @@ class Database
if (!$retval = $this->connection->query($this->replaceParameters($sql, $args))) {
$errorInfo = $this->connection->errorInfo();
$this->error = $errorInfo[2];
$this->errorno = $errorInfo[1];
$this->errorno = (int) $errorInfo[1];
$retval = false;
$is_error = true;
break;
@ -554,7 +572,7 @@ class Database
if (!$stmt = $this->connection->prepare($sql)) {
$errorInfo = $this->connection->errorInfo();
$this->error = $errorInfo[2];
$this->errorno = $errorInfo[1];
$this->errorno = (int) $errorInfo[1];
$retval = false;
$is_error = true;
break;
@ -574,7 +592,7 @@ class Database
if (!$stmt->execute()) {
$errorInfo = $stmt->errorInfo();
$this->error = $errorInfo[2];
$this->errorno = $errorInfo[1];
$this->errorno = (int) $errorInfo[1];
$retval = false;
$is_error = true;
} else {
@ -709,7 +727,7 @@ class Database
}
$this->error = $error;
$this->errorno = $errorno;
$this->errorno = (int) $errorno;
}
$this->profiler->stopRecording();
@ -741,8 +759,9 @@ class Database
* @return boolean Was the query successfull? False is returned only if an error occurred
* @throws \Exception
*/
public function e($sql)
public function e(string $sql): bool
{
$retval = false;
$this->profiler->startRecording('database_write');
@ -804,13 +823,14 @@ class Database
/**
* Check if data exists
*
* @param string|array $table Table name or array [schema => table]
* @param array $condition array of fields for condition
* @param string $table Table name in format schema.table (while scheme is optiona)
* @param array $condition Array of fields for condition
*
* @return boolean Are there rows for that condition?
* @throws \Exception
* @todo Please unwrap the DBStructure::existsTable() call so this method has one behavior only: checking existence on records
*/
public function exists($table, $condition)
public function exists(string $table, array $condition): bool
{
if (empty($table)) {
return false;
@ -850,10 +870,10 @@ class Database
*
* @param string $sql SQL statement
*
* @return array first row of query
* @return array|bool first row of query or false on failure
* @throws \Exception
*/
public function fetchFirst($sql)
public function fetchFirst(string $sql)
{
$params = DBA::getParam(func_get_args());
@ -875,7 +895,7 @@ class Database
*
* @return int Number of rows
*/
public function affectedRows()
public function affectedRows(): int
{
return $this->affected_rows;
}
@ -887,7 +907,7 @@ class Database
*
* @return int Number of columns
*/
public function columnCount($stmt)
public function columnCount($stmt): int
{
if (!is_object($stmt)) {
return 0;
@ -908,7 +928,7 @@ class Database
*
* @return int Number of rows
*/
public function numRows($stmt)
public function numRows($stmt): int
{
if (!is_object($stmt)) {
return 0;
@ -927,7 +947,7 @@ class Database
*
* @param bool|PDOStatement|mysqli_stmt $stmt statement object
*
* @return array|false current row
* @return array|bool Current row or false on failure
*/
public function fetch($stmt)
{
@ -987,14 +1007,14 @@ class Database
/**
* Insert a row into a table. Field value objects will be cast as string.
*
* @param string|array $table Table name or array [schema => table]
* @param string $table Table name in format schema.table (while scheme is optiona)
* @param array $param parameter array
* @param int $duplicate_mode What to do on a duplicated entry
*
* @return boolean was the insert successful?
* @throws \Exception
*/
public function insert($table, array $param, int $duplicate_mode = self::INSERT_DEFAULT)
public function insert(string $table, array $param, int $duplicate_mode = self::INSERT_DEFAULT): bool
{
if (empty($table) || empty($param)) {
$this->logger->info('Table and fields have to be set');
@ -1003,7 +1023,7 @@ class Database
$param = $this->castFields($table, $param);
$table_string = DBA::buildTableString($table);
$table_string = DBA::buildTableString([$table]);
$fields_string = implode(', ', array_map([DBA::class, 'quoteIdentifier'], array_keys($param)));
@ -1038,13 +1058,12 @@ class Database
* Inserts a row with the provided data in the provided table.
* If the data corresponds to an existing row through a UNIQUE or PRIMARY index constraints, it updates the row instead.
*
* @param string|array $table Table name or array [schema => table]
* @param string $table Table name in format schema.table (while scheme is optiona)
* @param array $param parameter array
*
* @return boolean was the insert successful?
* @throws \Exception
*/
public function replace($table, array $param)
public function replace(string $table, array $param): bool
{
if (empty($table) || empty($param)) {
$this->logger->info('Table and fields have to be set');
@ -1053,7 +1072,7 @@ class Database
$param = $this->castFields($table, $param);
$table_string = DBA::buildTableString($table);
$table_string = DBA::buildTableString([$table]);
$fields_string = implode(', ', array_map([DBA::class, 'quoteIdentifier'], array_keys($param)));
@ -1069,7 +1088,7 @@ class Database
*
* @return integer Last inserted id
*/
public function lastInsertId()
public function lastInsertId(): int
{
switch ($this->driver) {
case self::PDO:
@ -1087,12 +1106,11 @@ class Database
*
* This function can be extended in the future to accept a table array as well.
*
* @param string|array $table Table name or array [schema => table]
*
* @param string $table Table name in format schema.table (while scheme is optiona)
* @return boolean was the lock successful?
* @throws \Exception
*/
public function lock($table)
public function lock(string $table): bool
{
// See here: https://dev.mysql.com/doc/refman/5.7/en/lock-tables-and-transactions.html
if ($this->driver == self::PDO) {
@ -1102,7 +1120,7 @@ class Database
$this->connection->autocommit(false);
}
$success = $this->e("LOCK TABLES " . DBA::buildTableString($table) . " WRITE");
$success = $this->e("LOCK TABLES " . DBA::buildTableString([$table]) . " WRITE");
if ($this->driver == self::PDO) {
$this->connection->setAttribute(PDO::ATTR_EMULATE_PREPARES, $this->pdo_emulate_prepares);
@ -1126,7 +1144,7 @@ class Database
* @return boolean was the unlock successful?
* @throws \Exception
*/
public function unlock()
public function unlock(): bool
{
// See here: https://dev.mysql.com/doc/refman/5.7/en/lock-tables-and-transactions.html
$this->performCommit();
@ -1177,7 +1195,12 @@ class Database
return true;
}
protected function performCommit()
/**
* Performs the commit
*
* @return boolean Was the command executed successfully?
*/
protected function performCommit(): bool
{
switch ($this->driver) {
case self::PDO:
@ -1199,7 +1222,7 @@ class Database
*
* @return boolean Was the command executed successfully?
*/
public function commit()
public function commit(): bool
{
if (!$this->performCommit()) {
return false;
@ -1213,7 +1236,7 @@ class Database
*
* @return boolean Was the command executed successfully?
*/
public function rollback()
public function rollback(): bool
{
$ret = false;
@ -1230,6 +1253,7 @@ class Database
$ret = $this->connection->rollback();
break;
}
$this->in_transaction = false;
return $ret;
}
@ -1243,14 +1267,14 @@ class Database
* @return boolean was the delete successful?
* @throws \Exception
*/
public function delete($table, array $conditions)
public function delete(string $table, array $conditions): bool
{
if (empty($table) || empty($conditions)) {
$this->logger->info('Table and conditions have to be set');
return false;
}
$table_string = DBA::buildTableString($table);
$table_string = DBA::buildTableString([$table]);
$condition_string = DBA::buildCondition($conditions);
@ -1280,7 +1304,7 @@ class Database
* Only set $old_fields to a boolean value when you are sure that you will update a single row.
* When you set $old_fields to "true" then $fields must contain all relevant fields!
*
* @param string|array $table Table name or array [schema => table]
* @param string $table Table name in format schema.table (while scheme is optiona)
* @param array $fields contains the fields that are updated
* @param array $condition condition array with the key values
* @param array|boolean $old_fields array with the old field values that are about to be replaced (true = update on duplicate, false = don't update identical fields)
@ -1288,8 +1312,9 @@ class Database
*
* @return boolean was the update successfull?
* @throws \Exception
* @todo Implement "bool $update_on_duplicate" to avoid mixed type for $old_fields
*/
public function update($table, $fields, $condition, $old_fields = [], $params = [])
public function update(string $table, array $fields, array $condition, $old_fields = [], array $params = [])
{
if (empty($table) || empty($fields) || empty($condition)) {
$this->logger->info('Table, fields and condition have to be set');
@ -1322,7 +1347,7 @@ class Database
$fields = $this->castFields($table, $fields);
$table_string = DBA::buildTableString($table);
$table_string = DBA::buildTableString([$table]);
$condition_string = DBA::buildCondition($condition);
@ -1345,16 +1370,16 @@ class Database
/**
* Retrieve a single record from a table and returns it in an associative array
*
* @param string|array $table
* @param array $fields
* @param array $condition
* @param array $params
* @param string $table Table name in format schema.table (while scheme is optiona)
* @param array $fields Array of selected fields, empty for all
* @param array $condition Array of fields for condition
* @param array $params Array of several parameters
*
* @return bool|array
* @throws \Exception
* @see $this->select
*/
public function selectFirst($table, array $fields = [], array $condition = [], $params = [])
public function selectFirst(string $table, array $fields = [], array $condition = [], array $params = [])
{
$params['limit'] = 1;
$result = $this->select($table, $fields, $condition, $params);
@ -1371,16 +1396,15 @@ class Database
/**
* Select rows from a table and fills an array with the data
*
* @param string|array $table Table name or array [schema => table]
* @param string $table Table name in format schema.table (while scheme is optiona)
* @param array $fields Array of selected fields, empty for all
* @param array $condition Array of fields for condition
* @param array $params Array of several parameters
*
* @return array Data array
* @throws \Exception
* @see self::select
*/
public function selectToArray($table, array $fields = [], array $condition = [], array $params = [])
public function selectToArray(string $table, array $fields = [], array $condition = [], array $params = [])
{
return $this->toArray($this->select($table, $fields, $condition, $params));
}
@ -1390,9 +1414,9 @@ class Database
*
* @param array $fields
* @param array $options
* @return array
* @return array Escaped fields
*/
private function escapeFields(array $fields, array $options)
private function escapeFields(array $fields, array $options): array
{
// In the case of a "GROUP BY" we have to add all the ORDER fields to the fieldlist.
// This needs to done to apply the "ANY_VALUE(...)" treatment from below to them.
@ -1446,14 +1470,14 @@ class Database
*
* $data = DBA::select($table, $fields, $condition, $params);
*
* @param string|array $table Table name or array [schema => table]
* @param string $table Table name in format schema.table (while scheme is optiona)
* @param array $fields Array of selected fields, empty for all
* @param array $condition Array of fields for condition
* @param array $params Array of several parameters
* @return boolean|object
* @throws \Exception
*/
public function select($table, array $fields = [], array $condition = [], array $params = [])
public function select(string $table, array $fields = [], array $condition = [], array $params = [])
{
if (empty($table)) {
return false;
@ -1466,7 +1490,7 @@ class Database
$select_string = '*';
}
$table_string = DBA::buildTableString($table);
$table_string = DBA::buildTableString([$table]);
$condition_string = DBA::buildCondition($condition);
@ -1486,11 +1510,11 @@ class Database
/**
* Counts the rows from a table satisfying the provided condition
*
* @param string|array $table Table name or array [schema => table]
* @param string $table Table name in format schema.table (while scheme is optiona)
* @param array $condition Array of fields for condition
* @param array $params Array of several parameters
*
* @return int
* @return int Count of rows
*
* Example:
* $table = "post";
@ -1502,13 +1526,13 @@ class Database
* $count = DBA::count($table, $condition);
* @throws \Exception
*/
public function count($table, array $condition = [], array $params = [])
public function count(string $table, array $condition = [], array $params = []): int
{
if (empty($table)) {
return false;
throw new InvalidArgumentException('Parameter "table" cannot be empty.');
}
$table_string = DBA::buildTableString($table);
$table_string = DBA::buildTableString([$table]);
$condition_string = DBA::buildCondition($condition);
@ -1541,7 +1565,7 @@ class Database
*
* @return array Data array
*/
public function toArray($stmt, $do_close = true, int $count = 0)
public function toArray($stmt, bool $do_close = true, int $count = 0): array
{
if (is_bool($stmt)) {
return [];
@ -1569,7 +1593,8 @@ class Database
* @param array $fields
* @return array casted fields
*/
public function castFields(string $table, array $fields) {
public function castFields(string $table, array $fields): array
{
// When there is no data, we don't need to do something
if (empty($fields)) {
return $fields;
@ -1587,10 +1612,10 @@ class Database
$types = [];
$tables = DBStructure::definition('', false);
$tables = $this->dbaDefinition->getAll();
if (empty($tables[$table])) {
// When a matching table wasn't found we check if it is a view
$views = View::definition('', false);
$views = $this->viewDefinition->getAll();
if (empty($views[$table])) {
return $fields;
}
@ -1632,7 +1657,7 @@ class Database
*
* @return string Error number (0 if no error)
*/
public function errorNo()
public function errorNo(): int
{
return $this->errorno;
}
@ -1642,7 +1667,7 @@ class Database
*
* @return string Error message ('' if no error)
*/
public function errorMessage()
public function errorMessage(): string
{
return $this->error;
}
@ -1654,7 +1679,7 @@ class Database
*
* @return boolean was the close successful?
*/
public function close($stmt)
public function close($stmt): bool
{
$this->profiler->startRecording('database');
@ -1696,38 +1721,39 @@ class Database
* 'amount' => Number of concurrent database processes
* @throws \Exception
*/
public function processlist()
public function processlist(): array
{
$ret = $this->p("SHOW PROCESSLIST");
$ret = $this->p('SHOW PROCESSLIST');
$data = $this->toArray($ret);
$processes = 0;
$states = [];
foreach ($data as $process) {
$state = trim($process["State"]);
$state = trim($process['State']);
// Filter out all non blocking processes
if (!in_array($state, ["", "init", "statistics", "updating"])) {
if (!in_array($state, ['', 'init', 'statistics', 'updating'])) {
++$states[$state];
++$processes;
}
}
$statelist = "";
$statelist = '';
foreach ($states as $state => $usage) {
if ($statelist != "") {
$statelist .= ", ";
if ($statelist != '') {
$statelist .= ', ';
}
$statelist .= $state . ": " . $usage;
$statelist .= $state . ': ' . $usage;
}
return (["list" => $statelist, "amount" => $processes]);
return (['list' => $statelist, 'amount' => $processes]);
}
/**
* Fetch a database variable
*
* @param string $name
* @return string content
* @return string|null content or null if inexistent
* @throws \Exception
*/
public function getVariable(string $name)
{
@ -1739,10 +1765,9 @@ class Database
* Checks if $array is a filled array with at least one entry.
*
* @param mixed $array A filled array with at least one entry
*
* @return boolean Whether $array is a filled array or an object with rows
*/
public function isResult($array)
public function isResult($array): bool
{
// It could be a return value from an update statement
if (is_bool($array)) {
@ -1762,10 +1787,9 @@ class Database
* @param mixed $value Array value
* @param string $key Array key
* @param boolean $add_quotation add quotation marks for string values
*
* @return void
*/
private function escapeArrayCallback(&$value, $key, $add_quotation)
private function escapeArrayCallback(&$value, string $key, bool $add_quotation)
{
if (!$add_quotation) {
if (is_bool($value)) {
@ -1790,10 +1814,9 @@ class Database
*
* @param mixed $arr Array with values to be escaped
* @param boolean $add_quotation add quotation marks for string values
*
* @return void
*/
public function escapeArray(&$arr, $add_quotation = false)
public function escapeArray(&$arr, bool $add_quotation = false)
{
array_walk($arr, [$this, 'escapeArrayCallback'], $add_quotation);
}
@ -1801,13 +1824,14 @@ class Database
/**
* Replaces a string in the provided fields of the provided table
*
* @param string $table_name
* @param string $table Table name
* @param array $fields List of field names in the provided table
* @param string $search
* @param string $replace
* @param string $search String to search for
* @param string $replace String to replace with
* @return void
* @throws \Exception
*/
public function replaceInTableFields(string $table_name, array $fields, string $search, string $replace)
public function replaceInTableFields(string $table, array $fields, string $search, string $replace)
{
$search = $this->escape($search);
$replace = $this->escape($replace);
@ -1820,9 +1844,10 @@ class Database
$upds = implode(', ', $upd);
$r = $this->e(sprintf("UPDATE %s SET %s;", $table_name, $upds));
$r = $this->e(sprintf("UPDATE %s SET %s;", DBA::quoteIdentifier($table), $upds));
if (!$this->isResult($r)) {
throw new \RuntimeException("Failed updating `$table_name`: " . $this->errorMessage());
throw new \RuntimeException("Failed updating `$table`: " . $this->errorMessage());
}
}
}

View File

@ -0,0 +1,126 @@
<?php
/**
* @copyright Copyright (C) 2010-2022, the Friendica project
*
* @license GNU AGPL version 3 or any later version
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* 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
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
*/
namespace Friendica\Database\Definition;
use Exception;
use Friendica\Core\Hook;
/**
* Stores the whole database definition
*/
class DbaDefinition
{
/** @var string The relative path of the db structure config file */
const DBSTRUCTURE_RELATIVE_PATH = '/static/dbstructure.config.php';
/** @var array The complete DB definition as an array */
protected $definition;
/** @var string */
protected $configFile;
/**
* @param string $basePath The basepath of the dbstructure file (loads relative path in case of null)
*
* @throws Exception in case the config file isn't available/readable
*/
public function __construct(string $basePath)
{
$this->configFile = $basePath . static::DBSTRUCTURE_RELATIVE_PATH;
if (!is_readable($this->configFile)) {
throw new Exception('Missing database structure config file static/dbstructure.config.php at basePath=' . $basePath);
}
}
/**
* @return array Returns the whole Definition as an array
*/
public function getAll(): array
{
return $this->definition;
}
/**
* Truncate field data for the given table
*
* @param string $table Name of the table to load field definitions for
* @param array $data data fields
*
* @return array fields for the given
*/
public function truncateFieldsForTable(string $table, array $data): array
{
$definition = $this->definition;
if (empty($definition[$table])) {
return [];
}
$fieldNames = array_keys($definition[$table]['fields']);
$fields = [];
// Assign all field that are present in the table
foreach ($fieldNames as $field) {
if (isset($data[$field])) {
// Limit the length of varchar, varbinary, char and binrary fields
if (is_string($data[$field]) && preg_match("/char\((\d*)\)/", $definition[$table]['fields'][$field]['type'], $result)) {
$data[$field] = mb_substr($data[$field], 0, $result[1]);
} elseif (is_string($data[$field]) && preg_match("/binary\((\d*)\)/", $definition[$table]['fields'][$field]['type'], $result)) {
$data[$field] = substr($data[$field], 0, $result[1]);
}
$fields[$field] = $data[$field];
}
}
return $fields;
}
/**
* Loads the database structure definition from the static/dbstructure.config.php file.
* On first pass, defines DB_UPDATE_VERSION constant.
*
* @param bool $withAddonStructure Whether to tack on addons additional tables
*
* @throws Exception in case the definition cannot be found
*
* @see static/dbstructure.config.php
*
* @return self The current instance
*/
public function load(bool $withAddonStructure = false): self
{
$definition = require $this->configFile;
if (!$definition) {
throw new Exception('Corrupted database structure config file static/dbstructure.config.php');
}
if ($withAddonStructure) {
Hook::callAll('dbstructure_definition', $definition);
}
$this->definition = $definition;
return $this;
}
}

View File

@ -0,0 +1,91 @@
<?php
/**
* @copyright Copyright (C) 2010-2022, the Friendica project
*
* @license GNU AGPL version 3 or any later version
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* 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
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
*/
namespace Friendica\Database\Definition;
use Exception;
use Friendica\Core\Hook;
/**
* Stores the whole View definitions
*/
class ViewDefinition
{
/** @var string the relative path to the database view config file */
const DBSTRUCTURE_RELATIVE_PATH = '/static/dbview.config.php';
/** @var array The complete view definition as an array */
protected $definition;
/** @var string */
protected $configFile;
/**
* @param string $basePath The basepath of the dbview file (loads relative path in case of null)
*
* @throws Exception in case the config file isn't available/readable
*/
public function __construct(string $basePath)
{
$this->configFile = $basePath . static::DBSTRUCTURE_RELATIVE_PATH;
if (!is_readable($this->configFile)) {
throw new Exception('Missing database structure config file static/dbview.config.php at basePath=' . $basePath);
}
}
/**
* @return array Returns the whole Definition as an array
*/
public function getAll(): array
{
return $this->definition;
}
/**
* Loads the database structure definition from the static/dbview.config.php file.
* On first pass, defines DB_UPDATE_VERSION constant.
*
* @param bool $withAddonStructure Whether to tack on addons additional tables
*
* @throws Exception in case the definition cannot be found
*
* @see static/dbview.config.php
*
* @return self The current instance
*/
public function load(bool $withAddonStructure = false): self
{
$definition = require $this->configFile;
if (!$definition) {
throw new Exception('Corrupted database structure config file static/dbstructure.config.php');
}
if ($withAddonStructure) {
Hook::callAll('dbview_definition', $definition);
}
$this->definition = $definition;
return $this;
}
}

View File

@ -133,7 +133,7 @@ class PostUpdate
}
$max_item_delivery_data = DBA::selectFirst('item-delivery-data', ['iid'], ['queue_count > 0 OR queue_done > 0'], ['order' => ['iid']]);
$max_iid = $max_item_delivery_data['iid'];
$max_iid = $max_item_delivery_data['iid'] ?? 0;
Logger::info('Start update1297 with max iid: ' . $max_iid);
@ -538,7 +538,7 @@ class PostUpdate
private static function update1347()
{
// Was the script completed?
if (DI::config()->get("system", "post_update_version") >= 1347) {
if (DI::config()->get('system', 'post_update_version') >= 1347) {
return true;
}
@ -547,7 +547,7 @@ class PostUpdate
return true;
}
$id = DI::config()->get("system", "post_update_version_1347_id", 0);
$id = DI::config()->get('system', 'post_update_version_1347_id', 0);
Logger::info('Start', ['item' => $id]);
@ -582,12 +582,12 @@ class PostUpdate
}
DBA::close($items);
DI::config()->set("system", "post_update_version_1347_id", $id);
DI::config()->set('system', 'post_update_version_1347_id', $id);
Logger::info('Processed', ['rows' => $rows, 'last' => $id]);
if ($start_id == $id) {
DI::config()->set("system", "post_update_version", 1347);
DI::config()->set('system', 'post_update_version', 1347);
Logger::info('Done');
return true;
}
@ -605,11 +605,11 @@ class PostUpdate
private static function update1348()
{
// Was the script completed?
if (DI::config()->get("system", "post_update_version") >= 1348) {
if (DI::config()->get('system', 'post_update_version') >= 1348) {
return true;
}
$id = DI::config()->get("system", "post_update_version_1348_id", 0);
$id = DI::config()->get('system', 'post_update_version_1348_id', 0);
Logger::info('Start', ['contact' => $id]);
@ -635,12 +635,12 @@ class PostUpdate
}
DBA::close($contacts);
DI::config()->set("system", "post_update_version_1348_id", $id);
DI::config()->set('system', 'post_update_version_1348_id', $id);
Logger::info('Processed', ['rows' => $rows, 'last' => $id]);
if ($start_id == $id) {
DI::config()->set("system", "post_update_version", 1348);
DI::config()->set('system', 'post_update_version', 1348);
Logger::info('Done');
return true;
}
@ -658,11 +658,11 @@ class PostUpdate
private static function update1349()
{
// Was the script completed?
if (DI::config()->get("system", "post_update_version") >= 1349) {
if (DI::config()->get('system', 'post_update_version') >= 1349) {
return true;
}
$id = DI::config()->get("system", "post_update_version_1349_id", '');
$id = DI::config()->get('system', 'post_update_version_1349_id', '');
Logger::info('Start', ['apcontact' => $id]);
@ -688,12 +688,12 @@ class PostUpdate
}
DBA::close($apcontacts);
DI::config()->set("system", "post_update_version_1349_id", $id);
DI::config()->set('system', 'post_update_version_1349_id', $id);
Logger::info('Processed', ['rows' => $rows, 'last' => $id]);
if ($start_id == $id) {
DI::config()->set("system", "post_update_version", 1349);
DI::config()->set('system', 'post_update_version', 1349);
Logger::info('Done');
return true;
}
@ -711,7 +711,7 @@ class PostUpdate
private static function update1383()
{
// Was the script completed?
if (DI::config()->get("system", "post_update_version") >= 1383) {
if (DI::config()->get('system', 'post_update_version') >= 1383) {
return true;
}
@ -737,7 +737,7 @@ class PostUpdate
}
DBA::close($photos);
DI::config()->set("system", "post_update_version", 1383);
DI::config()->set('system', 'post_update_version', 1383);
Logger::info('Done', ['deleted' => $deleted]);
return true;
}
@ -752,7 +752,7 @@ class PostUpdate
private static function update1384()
{
// Was the script completed?
if (DI::config()->get("system", "post_update_version") >= 1384) {
if (DI::config()->get('system', 'post_update_version') >= 1384) {
return true;
}
@ -782,7 +782,7 @@ class PostUpdate
Logger::info('Processed', ['rows' => $rows]);
if ($rows <= 100) {
DI::config()->set("system", "post_update_version", 1384);
DI::config()->set('system', 'post_update_version', 1384);
Logger::info('Done');
return true;
}
@ -800,12 +800,12 @@ class PostUpdate
private static function update1400()
{
// Was the script completed?
if (DI::config()->get("system", "post_update_version") >= 1400) {
if (DI::config()->get('system', 'post_update_version') >= 1400) {
return true;
}
if (!DBStructure::existsTable('item')) {
DI::config()->set("system", "post_update_version", 1400);
DI::config()->set('system', 'post_update_version', 1400);
return true;
}
@ -829,7 +829,7 @@ class PostUpdate
Logger::info('Processed', ['rows' => $rows]);
if ($rows <= 100) {
DI::config()->set("system", "post_update_version", 1400);
DI::config()->set('system', 'post_update_version', 1400);
Logger::info('Done');
return true;
}
@ -847,7 +847,7 @@ class PostUpdate
private static function update1424()
{
// Was the script completed?
if (DI::config()->get("system", "post_update_version") >= 1424) {
if (DI::config()->get('system', 'post_update_version') >= 1424) {
return true;
}
@ -871,7 +871,7 @@ class PostUpdate
Logger::info('Processed', ['rows' => $rows]);
if ($rows <= 100) {
DI::config()->set("system", "post_update_version", 1424);
DI::config()->set('system', 'post_update_version', 1424);
Logger::info('Done');
return true;
}
@ -889,7 +889,7 @@ class PostUpdate
private static function update1425()
{
// Was the script completed?
if (DI::config()->get("system", "post_update_version") >= 1425) {
if (DI::config()->get('system', 'post_update_version') >= 1425) {
return true;
}
@ -918,7 +918,7 @@ class PostUpdate
Logger::info('Processed', ['rows' => $rows]);
if ($rows <= 100) {
DI::config()->set("system", "post_update_version", 1425);
DI::config()->set('system', 'post_update_version', 1425);
Logger::info('Done');
return true;
}
@ -936,7 +936,7 @@ class PostUpdate
private static function update1426()
{
// Was the script completed?
if (DI::config()->get("system", "post_update_version") >= 1426) {
if (DI::config()->get('system', 'post_update_version') >= 1426) {
return true;
}
@ -965,7 +965,7 @@ class PostUpdate
Logger::info('Processed', ['rows' => $rows]);
if ($rows <= 100) {
DI::config()->set("system", "post_update_version", 1426);
DI::config()->set('system', 'post_update_version', 1426);
Logger::info('Done');
return true;
}
@ -983,7 +983,7 @@ class PostUpdate
private static function update1427()
{
// Was the script completed?
if (DI::config()->get("system", "post_update_version") >= 1427) {
if (DI::config()->get('system', 'post_update_version') >= 1427) {
return true;
}
@ -1012,7 +1012,7 @@ class PostUpdate
Logger::info('Processed', ['rows' => $rows]);
if ($rows <= 100) {
DI::config()->set("system", "post_update_version", 1427);
DI::config()->set('system', 'post_update_version', 1427);
Logger::info('Done');
return true;
}

View File

@ -21,60 +21,18 @@
namespace Friendica\Database;
use Exception;
use Friendica\Core\Hook;
use Friendica\DI;
use Friendica\Util\Writer\ViewDefinitionSqlWriter;
class View
{
/**
* view definition loaded from static/dbview.config.php
* Creates a view
*
* @var array
* @param bool $verbose Whether to show SQL statements
* @param bool $action Whether to execute SQL statements
* @return void
*/
private static $definition = [];
/**
* Loads the database structure definition from the static/dbview.config.php file.
* On first pass, defines DB_UPDATE_VERSION constant.
*
* @see static/dbview.config.php
* @param boolean $with_addons_structure Whether to tack on addons additional tables
* @param string $basePath The base path of this application
* @return array
* @throws Exception
*/
public static function definition($basePath = '', $with_addons_structure = true)
{
if (!self::$definition) {
if (empty($basePath)) {
$basePath = DI::app()->getBasePath();
}
$filename = $basePath . '/static/dbview.config.php';
if (!is_readable($filename)) {
throw new Exception('Missing database view config file static/dbview.config.php');
}
$definition = require $filename;
if (!$definition) {
throw new Exception('Corrupted database view config file static/dbview.config.php');
}
self::$definition = $definition;
} else {
$definition = self::$definition;
}
if ($with_addons_structure) {
Hook::callAll('dbview_definition', $definition);
}
return $definition;
}
public static function create(bool $verbose, bool $action)
{
// Delete previously used views that aren't used anymore
@ -91,66 +49,16 @@ class View
}
}
$definition = self::definition();
$definition = DI::viewDefinition()->getAll();
foreach ($definition as $name => $structure) {
self::createview($name, $structure, $verbose, $action);
}
}
public static function printStructure($basePath)
{
$database = self::definition($basePath, false);
foreach ($database as $name => $structure) {
echo "--\n";
echo "-- VIEW $name\n";
echo "--\n";
self::createView($name, $structure, true, false);
echo "\n";
}
}
private static function createview($name, $structure, $verbose, $action)
{
$r = true;
$sql_rows = [];
foreach ($structure["fields"] as $fieldname => $origin) {
if (is_string($origin)) {
$sql_rows[] = $origin . " AS `" . DBA::escape($fieldname) . "`";
} elseif (is_array($origin) && (sizeof($origin) == 2)) {
$sql_rows[] = "`" . DBA::escape($origin[0]) . "`.`" . DBA::escape($origin[1]) . "` AS `" . DBA::escape($fieldname) . "`";
}
}
if (self::isView($name)) {
$sql = sprintf("DROP VIEW IF EXISTS `%s`", DBA::escape($name));
DBA::e(sprintf("DROP VIEW IF EXISTS `%s`", DBA::escape($name)));
} elseif (self::isTable($name)) {
$sql = sprintf("DROP TABLE IF EXISTS `%s`", DBA::escape($name));
DBA::e(sprintf("DROP TABLE IF EXISTS `%s`", DBA::escape($name)));
}
if (!empty($sql) && $verbose) {
echo $sql . ";\n";
DBA::e(ViewDefinitionSqlWriter::createView($name, $structure));
}
if (!empty($sql) && $action) {
DBA::e($sql);
}
$sql = sprintf("CREATE VIEW `%s` AS SELECT \n\t", DBA::escape($name)) .
implode(",\n\t", $sql_rows) . "\n\t" . $structure['query'];
if ($verbose) {
echo $sql . ";\n";
}
if ($action) {
$r = DBA::e($sql);
}
return $r;
}
/**
@ -159,9 +67,9 @@ class View
* @param string $view
* @return boolean "true" if it's a view
*/
private static function isView(string $view)
private static function isView(string $view): bool
{
$status = DBA::selectFirst(['INFORMATION_SCHEMA' => 'TABLES'], ['TABLE_TYPE'],
$status = DBA::selectFirst('INFORMATION_SCHEMA.TABLES', ['TABLE_TYPE'],
['TABLE_SCHEMA' => DBA::databaseName(), 'TABLE_NAME' => $view]);
if (empty($status['TABLE_TYPE'])) {
@ -177,9 +85,9 @@ class View
* @param string $table
* @return boolean "true" if it's a table
*/
private static function isTable(string $table)
private static function isTable(string $table): bool
{
$status = DBA::selectFirst(['INFORMATION_SCHEMA' => 'TABLES'], ['TABLE_TYPE'],
$status = DBA::selectFirst('INFORMATION_SCHEMA.TABLES', ['TABLE_TYPE'],
['TABLE_SCHEMA' => DBA::databaseName(), 'TABLE_NAME' => $table]);
if (empty($status['TABLE_TYPE'])) {

View File

@ -57,12 +57,17 @@ class Account extends BaseFactory
* @throws HTTPException\InternalServerErrorException
* @throws ImagickException|HTTPException\NotFoundException
*/
public function createFromContactId(int $contactId, $uid = 0): \Friendica\Object\Api\Mastodon\Account
public function createFromContactId(int $contactId, int $uid = 0): \Friendica\Object\Api\Mastodon\Account
{
$contact = Contact::getById($contactId, ['uri-id']);
if (empty($contact)) {
throw new HTTPException\NotFoundException('Contact ' . $contactId . ' not found');
}
if (empty($contact['uri-id'])) {
throw new HTTPException\NotFoundException('Contact ' . $contactId . ' has no uri-id set');
}
return self::createFromUriId($contact['uri-id'], $uid);
}
@ -74,7 +79,7 @@ class Account extends BaseFactory
* @throws HTTPException\InternalServerErrorException
* @throws ImagickException|HTTPException\NotFoundException
*/
public function createFromUriId(int $contactUriId, $uid = 0): \Friendica\Object\Api\Mastodon\Account
public function createFromUriId(int $contactUriId, int $uid = 0): \Friendica\Object\Api\Mastodon\Account
{
$account = DBA::selectFirst('account-user-view', [], ['uri-id' => $contactUriId, 'uid' => [0, $uid]], ['order' => ['id' => true]]);
if (empty($account)) {

View File

@ -190,7 +190,7 @@ class Status extends BaseFactory
*/
public function createFromMailId(int $id): \Friendica\Object\Api\Mastodon\Status
{
$item = ActivityPub\Transmitter::ItemArrayFromMail($id, true);
$item = ActivityPub\Transmitter::getItemArrayFromMail($id, true);
if (empty($item)) {
$this->mstdnErrorFactory->RecordNotFound();
}

View File

@ -70,6 +70,7 @@ class Status extends BaseFactory
/**
* @param int $uriId Uri-ID of the item
* @param int $uid Item user
* @param bool $include_entities Whether to include entities
*
* @return \Friendica\Object\Api\Twitter\Status
* @throws HTTPException\InternalServerErrorException
@ -90,12 +91,13 @@ class Status extends BaseFactory
/**
* @param int $uriId Uri-ID of the item
* @param int $uid Item user
* @param bool $include_entities Whether to include entities
*
* @return \Friendica\Object\Api\Twitter\Status
* @throws HTTPException\InternalServerErrorException
* @throws ImagickException|HTTPException\NotFoundException
*/
public function createFromUriId(int $uriId, $uid = 0, $include_entities = false): \Friendica\Object\Api\Twitter\Status
public function createFromUriId(int $uriId, int $uid = 0, bool $include_entities = false): \Friendica\Object\Api\Twitter\Status
{
$fields = ['parent-uri-id', 'uri-id', 'uid', 'author-id', 'author-link', 'author-network', 'owner-id', 'causer-id',
'starred', 'app', 'title', 'body', 'raw-body', 'created', 'network','post-reason', 'language', 'gravity',
@ -110,6 +112,7 @@ class Status extends BaseFactory
/**
* @param array $item item array
* @param int $uid Item user
* @param bool $include_entities Whether to include entities
*
* @return \Friendica\Object\Api\Twitter\Status
* @throws HTTPException\InternalServerErrorException

View File

@ -51,7 +51,7 @@ class User extends BaseFactory
* @throws HTTPException\InternalServerErrorException
* @throws \ImagickException
*/
public function createFromContactId(int $contactId, $uid = 0, $skip_status = true, $include_user_entities = true)
public function createFromContactId(int $contactId, int $uid = 0, bool $skip_status = true, bool $include_user_entities = true)
{
$cdata = Contact::getPublicAndUserContactID($contactId, $uid);
if (!empty($cdata)) {
@ -78,7 +78,7 @@ class User extends BaseFactory
return new \Friendica\Object\Api\Twitter\User($publicContact, $apcontact, $userContact, $status, $include_user_entities);
}
public function createFromUserId(int $uid, $skip_status = true, $include_user_entities = true)
public function createFromUserId(int $uid, bool $skip_status = true, bool $include_user_entities = true)
{
return $this->createFromContactId(Contact::getPublicIdByUserId($uid), $uid, $skip_status, $include_user_entities);
}

View File

@ -57,7 +57,7 @@ class LegacyModule extends BaseModule
* @param string $file_path
* @throws \Exception
*/
private function setModuleFile($file_path)
private function setModuleFile(string $file_path)
{
if (!is_readable($file_path)) {
throw new \Exception(DI::l10n()->t('Legacy module file not found: %s', $file_path));
@ -87,7 +87,7 @@ class LegacyModule extends BaseModule
* @return string
* @throws \Exception
*/
private function runModuleFunction(string $function_suffix)
private function runModuleFunction(string $function_suffix): string
{
$function_name = $this->moduleName . '_' . $function_suffix;

View File

@ -48,7 +48,7 @@ class APContact
* @param string $addr Address
* @return array webfinger data
*/
private static function fetchWebfingerData(string $addr)
private static function fetchWebfingerData(string $addr): array
{
$addr_parts = explode('@', $addr);
if (count($addr_parts) != 2) {
@ -116,15 +116,16 @@ class APContact
* @return array profile array
* @throws \Friendica\Network\HTTPException\InternalServerErrorException
* @throws \ImagickException
* @todo Rewrite parameter $update to avoid true|false|null (boolean is binary, null adds a third case)
*/
public static function getByURL($url, $update = null)
public static function getByURL(string $url, $update = null): array
{
if (empty($url) || Network::isUrlBlocked($url)) {
Logger::info('Domain is blocked', ['url' => $url]);
return [];
}
$fetched_contact = false;
$fetched_contact = [];
if (empty($update)) {
if (is_null($update)) {
@ -222,14 +223,14 @@ class APContact
$apcontact['type'] = str_replace('as:', '', JsonLD::fetchElement($compacted, '@type'));
$apcontact['following'] = JsonLD::fetchElement($compacted, 'as:following', '@id');
$apcontact['followers'] = JsonLD::fetchElement($compacted, 'as:followers', '@id');
$apcontact['inbox'] = JsonLD::fetchElement($compacted, 'ldp:inbox', '@id');
$apcontact['inbox'] = (JsonLD::fetchElement($compacted, 'ldp:inbox', '@id') ?? '');
self::unarchiveInbox($apcontact['inbox'], false);
$apcontact['outbox'] = JsonLD::fetchElement($compacted, 'as:outbox', '@id');
$apcontact['sharedinbox'] = '';
if (!empty($compacted['as:endpoints'])) {
$apcontact['sharedinbox'] = JsonLD::fetchElement($compacted['as:endpoints'], 'as:sharedInbox', '@id');
$apcontact['sharedinbox'] = (JsonLD::fetchElement($compacted['as:endpoints'], 'as:sharedInbox', '@id') ?? '');
self::unarchiveInbox($apcontact['sharedinbox'], true);
}
@ -243,9 +244,10 @@ class APContact
$apcontact['name'] = $apcontact['nick'];
}
$apcontact['about'] = HTML::toBBCode(JsonLD::fetchElement($compacted, 'as:summary', '@value'));
$apcontact['about'] = HTML::toBBCode(JsonLD::fetchElement($compacted, 'as:summary', '@value') ?? '');
$ims = JsonLD::fetchElementArray($compacted, 'vcard:hasInstantMessage');
if (!empty($ims)) {
foreach ($ims as $link) {
if (substr($link, 0, 5) == 'xmpp:') {
@ -466,7 +468,7 @@ class APContact
}
// Limit the length on incoming fields
$apcontact = DBStructure::getFieldsForTable('apcontact', $apcontact);
$apcontact = DI::dbaDefinition()->truncateFieldsForTable('apcontact', $apcontact);
if (DBA::exists('apcontact', ['url' => $apcontact['url']])) {
DBA::update('apcontact', $apcontact, ['url' => $apcontact['url']]);
@ -527,8 +529,9 @@ class APContact
*
* @param string $url inbox url
* @param boolean $shared Shared Inbox
* @return void
*/
private static function unarchiveInbox($url, $shared)
private static function unarchiveInbox(string $url, bool $shared)
{
if (empty($url)) {
return;

Some files were not shown because too many files have changed in this diff Show More