Merge remote-tracking branch 'upstream/develop' into http-417

This commit is contained in:
Michael 2019-10-17 21:37:24 +00:00
commit 36ba7fa79c
316 changed files with 39229 additions and 36498 deletions

View file

@ -1,10 +1,14 @@
codecov:
branch: develop
ci:
- drone.friendi.ca
coverage:
precision: 2
round: down
range: "70...100"
status:
project:
default:
target: auto
threshold: null
base: auto
project: off
patch: off
comment: off

439
.drone.yml Normal file
View file

@ -0,0 +1,439 @@
kind: pipeline
name: mysql8.0-php7.1
steps:
- name: mysql8.0-php7.1
image: friendicaci/php7.1:php7.1.32
commands:
- NOCOVERAGE=true ./autotest.sh mysql
environment:
MYSQL_USERNAME: friendica
MYSQL_PASSWORD: friendica
MYSQL_DATABASE: friendica
MYSQL_HOST: mysql
services:
- name: mysql
image: mysql:8.0
command: [ "--default-authentication-plugin=mysql_native_password" ]
environment:
MYSQL_ROOT_PASSWORD: friendica
MYSQL_USER: friendica
MYSQL_PASSWORD: friendica
MYSQL_DATABASE: friendica
volumes:
- name: cache
path: /var/lib/mysql
volumes:
- name: cache
temp: {}
trigger:
branch:
- master
- develop
- "*-rc"
event:
- pull_request
- push
---
kind: pipeline
name: mysql8.0-php7.2
steps:
- name: mysql8.0-php7.2
image: friendicaci/php7.2:php7.2.22
commands:
- NOCOVERAGE=true ./autotest.sh mysql
environment:
MYSQL_USERNAME: friendica
MYSQL_PASSWORD: friendica
MYSQL_DATABASE: friendica
MYSQL_HOST: mysql
services:
- name: mysql
image: mysql:8.0
command: [ "--default-authentication-plugin=mysql_native_password" ]
environment:
MYSQL_ROOT_PASSWORD: friendica
MYSQL_USER: friendica
MYSQL_PASSWORD: friendica
MYSQL_DATABASE: friendica
volumes:
- name: cache
path: /var/lib/mysql
volumes:
- name: cache
temp: {}
trigger:
branch:
- master
- develop
- "*-rc"
event:
- pull_request
- push
---
kind: pipeline
name: mysql8.0-php7.3
steps:
- name: mysql8.0-php7.3
image: friendicaci/php7.3:php7.3.9
commands:
- NOCOVERAGE=true ./autotest.sh mysql
environment:
MYSQL_USERNAME: friendica
MYSQL_PASSWORD: friendica
MYSQL_DATABASE: friendica
MYSQL_HOST: mysql
services:
- name: mysql
image: mysql:8.0
command: [ "--default-authentication-plugin=mysql_native_password" ]
environment:
MYSQL_ROOT_PASSWORD: friendica
MYSQL_USER: friendica
MYSQL_PASSWORD: friendica
MYSQL_DATABASE: friendica
volumes:
- name: cache
path: /var/lib/mysql
volumes:
- name: cache
temp: {}
trigger:
branch:
- master
- develop
- "*-rc"
event:
- pull_request
- push
---
kind: pipeline
name: mariadb10.1-php7.1
steps:
- name: mariadb10.1-php7.1
image: friendicaci/php7.1:php7.1.32
commands:
- phpenmod xdebug
- sleep 20
- ./autotest.sh mariadb
- wget https://codecov.io/bash -O codecov.sh
- sh -c "if [ '$DRONE_BUILD_EVENT' = 'pull_request' ]; then bash codecov.sh -B $DRONE_BRANCH -C $DRONE_COMMIT -P $DRONE_PULL_REQUEST -t 5ce7d64e-07b4-4adf-8700-e2eae27e14ec -f tests/autotest-clover.xml; fi"
- sh -c "if [ '$DRONE_BUILD_EVENT' != 'pull_request' ]; then bash codecov.sh -B $DRONE_BRANCH -C $DRONE_COMMIT -t 5ce7d64e-07b4-4adf-8700-e2eae27e14ec -f tests/autotest-clover.xml; fi"
environment:
MYSQL_USER: friendica
MYSQL_PASSWORD: friendica
MYSQL_DATABASE: friendica
MYSQL_HOST: mariadb
services:
- name: mariadb
image: mariadb:10.1
environment:
MYSQL_ROOT_PASSWORD: friendica
MYSQL_USER: friendica
MYSQL_PASSWORD: friendica
MYSQL_DATABASE: friendica
volumes:
- name: cache
path: /var/lib/mysql
volumes:
- name: cache
temp: {}
trigger:
branch:
- master
- develop
- "*-rc"
event:
- pull_request
- push
---
kind: pipeline
name: mariadb10.1-php7.2
steps:
- name: mariadb10.1-php7.2
image: friendicaci/php7.2:php7.2.22
commands:
- NOCOVERAGE=true ./autotest.sh mariadb
environment:
MYSQL_USER: friendica
MYSQL_PASSWORD: friendica
MYSQL_DATABASE: friendica
MYSQL_HOST: mariadb
services:
- name: mariadb
image: mariadb:10.1
environment:
MYSQL_ROOT_PASSWORD: friendica
MYSQL_USER: friendica
MYSQL_PASSWORD: friendica
MYSQL_DATABASE: friendica
volumes:
- name: cache
path: /var/lib/mysql
volumes:
- name: cache
temp: {}
trigger:
branch:
- master
- develop
- "*-rc"
event:
- pull_request
- push
---
kind: pipeline
name: mariadb10.1-php7.3
steps:
- name: mariadb10.1-php7.3
image: friendicaci/php7.3:php7.3.9
commands:
- NOCOVERAGE=true ./autotest.sh mariadb
environment:
MYSQL_USER: friendica
MYSQL_PASSWORD: friendica
MYSQL_DATABASE: friendica
MYSQL_HOST: mariadb
services:
- name: mariadb
image: mariadb:10.1
environment:
MYSQL_ROOT_PASSWORD: friendica
MYSQL_USER: friendica
MYSQL_PASSWORD: friendica
MYSQL_DATABASE: friendica
volumes:
- name: cache
path: /var/lib/mysql
volumes:
- name: cache
temp: {}
---
kind: pipeline
name: redis-php7.1
steps:
- name: redis-php7.1
image: friendicaci/php7.1:php7.1.32
commands:
- phpenmod xdebug
- sleep 20
- NOINSTALL=true TEST_SELECTION=REDIS ./autotest.sh mysql
- wget https://codecov.io/bash -O codecov.sh
- sh -c "if [ '$DRONE_BUILD_EVENT' = 'pull_request' ]; then bash codecov.sh -B $DRONE_BRANCH -C $DRONE_COMMIT -P $DRONE_PULL_REQUEST -t 5ce7d64e-07b4-4adf-8700-e2eae27e14ec -f tests/autotest-clover.xml; fi"
- sh -c "if [ '$DRONE_BUILD_EVENT' != 'pull_request' ]; then bash codecov.sh -B $DRONE_BRANCH -C $DRONE_COMMIT -t 5ce7d64e-07b4-4adf-8700-e2eae27e14ec -f tests/autotest-clover.xml; fi"
environment:
REDIS_HOST: redis
services:
- name: redis
image: redis
trigger:
branch:
- master
- develop
- "*-rc"
event:
- pull_request
- push
---
kind: pipeline
name: redis-php7.2
steps:
- name: redis-php7.2
image: friendicaci/php7.2:php7.2.22
commands:
- NOCOVERAGE=true NOINSTALL=true TEST_SELECTION=REDIS ./autotest.sh mysql
environment:
REDIS_HOST: redis
services:
- name: redis
image: redis
trigger:
branch:
- master
- develop
- "*-rc"
event:
- pull_request
- push
---
kind: pipeline
name: redis-php7.3
steps:
- name: redis-php7.3
image: friendicaci/php7.3:php7.3.9
commands:
- NOCOVERAGE=true NOINSTALL=true TEST_SELECTION=REDIS ./autotest.sh mysql
environment:
REDIS_HOST: redis
services:
- name: redis
image: redis
---
kind: pipeline
name: memcache-php7.1
steps:
- name: memcache-php7.1
image: friendicaci/php7.1:php7.1.32
commands:
- phpenmod xdebug
- sleep 20
- NOINSTALL=true TEST_SELECTION=MEMCACHE ./autotest.sh mysql
- wget https://codecov.io/bash -O codecov.sh
- sh -c "if [ '$DRONE_BUILD_EVENT' = 'pull_request' ]; then bash codecov.sh -B $DRONE_BRANCH -C $DRONE_COMMIT -P $DRONE_PULL_REQUEST -t 5ce7d64e-07b4-4adf-8700-e2eae27e14ec -f tests/autotest-clover.xml; fi"
- sh -c "if [ '$DRONE_BUILD_EVENT' != 'pull_request' ]; then bash codecov.sh -B $DRONE_BRANCH -C $DRONE_COMMIT -t 5ce7d64e-07b4-4adf-8700-e2eae27e14ec -f tests/autotest-clover.xml; fi"
environment:
MEMCACHE_HOST: memcached
services:
- name: memcached
image: memcached
trigger:
branch:
- master
- develop
- "*-rc"
event:
- pull_request
- push
---
kind: pipeline
name: memcache-php7.2
steps:
- name: memcache-php7.2
image: friendicaci/php7.2:php7.2.22
commands:
- NOCOVERAGE=true NOINSTALL=true TEST_SELECTION=MEMCACHE ./autotest.sh mysql
environment:
MEMCACHE_HOST: memcached
services:
- name: memcached
image: memcached
trigger:
branch:
- master
- develop
- "*-rc"
event:
- pull_request
- push
---
kind: pipeline
name: memcache-php7.3
steps:
- name: memcache-php7.3
image: friendicaci/php7.3:php7.3.9
commands:
- NOCOVERAGE=true NOINSTALL=true TEST_SELECTION=MEMCACHE ./autotest.sh mysql
environment:
MEMCACHE_HOST: memcached
services:
- name: memcached
image: memcached
---
kind: pipeline
name: memcached-php7.1
steps:
- name: memcached-php7.1
image: friendicaci/php7.1:php7.1.32
commands:
- phpenmod xdebug
- sleep 20
- NOINSTALL=true TEST_SELECTION=MEMCACHED ./autotest.sh mysql
- wget https://codecov.io/bash -O codecov.sh
- sh -c "if [ '$DRONE_BUILD_EVENT' = 'pull_request' ]; then bash codecov.sh -B $DRONE_BRANCH -C $DRONE_COMMIT -P $DRONE_PULL_REQUEST -t 5ce7d64e-07b4-4adf-8700-e2eae27e14ec -f tests/autotest-clover.xml; fi"
- sh -c "if [ '$DRONE_BUILD_EVENT' != 'pull_request' ]; then bash codecov.sh -B $DRONE_BRANCH -C $DRONE_COMMIT -t 5ce7d64e-07b4-4adf-8700-e2eae27e14ec -f tests/autotest-clover.xml; fi"
environment:
MEMCACHED_HOST: memcached
services:
- name: memcached
image: memcached
trigger:
branch:
- master
- develop
- "*-rc"
event:
- pull_request
- push
---
kind: pipeline
name: memcached-php7.2
steps:
- name: memcached-php7.2
image: friendicaci/php7.2:php7.2.22
commands:
- NOCOVERAGE=true NOINSTALL=true TEST_SELECTION=MEMCACHED ./autotest.sh mysql
environment:
MEMCACHED_HOST: memcached
services:
- name: memcached
image: memcached
trigger:
branch:
- master
- develop
- "*-rc"
event:
- pull_request
- push
---
kind: pipeline
name: memcached-php7.3
steps:
- name: memcached-php7.3
image: friendicaci/php7.3:php7.3.9
commands:
- NOCOVERAGE=true NOINSTALL=true TEST_SELECTION=MEMCACHED ./autotest.sh mysql
environment:
MEMCACHED_HOST: memcached
services:
- name: memcached
image: memcached

View file

@ -26,4 +26,4 @@ before_script:
- phpenv config-add .travis/redis.ini
- phpenv config-add .travis/memcached.ini
after_success: bash <(curl -s https://codecov.io/bash)
script: vendor/bin/phpunit --configuration tests/phpunit.xml

View file

@ -1,24 +1,44 @@
Version 2019.09-dev (UNRELEASED)
Version 2019.12-dev (unreleased)
Friendica Core:
Update to the translations (CS, DE, FR, JA, NL) [translation teams]
Enhanced the manage functionality [annando]
Fixed some problems with the remote auth functionality [annando]
Added router configuration file [nupplaphil]
Added drone.io as CI service [nupplaphil]
Friendica Addons:
mailstream:
Support for new img format was added [mexon]
BB Code is now included as plaintext [mexon]
Logging format is enhanced [mexon]
ActivityPub "announce" notifications are not included [mexon]
Closed Issues:
1071, 7548, 7657, 7681
Version 2019.09 (2019-09-29)
Friendica Core:
Update to the translations (CS, DE, EN GB, EN US, FR, JA, NL, PL) [translation teams]
Update to the themes (frio, vier) [JeroenED, MrPetovan, tobiasd, vinzv]
Update to the documentation [guzzisti, vinzv]
Update to the documentation [annando, tobiasd, guzzisti, vinzv]
Enhanced the log output of the background process [annando]
Enhanced the vcard translation in the profile (JeroenED)
Enhanced the vcard translation in the profile [JeroenED]
Enhanced the delivery count [annando]
Enhanced ActivityPub envelopes [MrPetovan]
Enhanced communication about deleted accounts via AP [annando]
Enhanced the following process [annando]
Enhanced the tests [nupplaphil]
Enhanced the frontend worker [annando]
Enhanced the front-end worker [annando]
Enhanced the img format to allow alternative texts [annando]
Enhanced the detection of supported protocols for contacts [annando]
Enhanced the reshare of items [annando]
Enhanced the re-share of items [annando]
Enhanced 2FA process [MrPetovan]
Enhanced server wide theme settings [MrPetovan]
Enhanced config loading process [MrPetovan, nupplaphil]
Enhanced handling of emoticons [MrPetovan]
Fixed a bug in the admin panel leading to orphand options [tobiasd]
Enhanced performance [annando]
Fixed a bug in the admin panel leading to orphaned options [tobiasd]
Fixed a problem that could lead to duplicated Pleroma contacts [annando]
Fixed a problem with the hide profile setting [annando]
Fixed the problem sending out the post when hitting the enter key in the ACL dialog [MrPetovan]
Fixed a bug in HTML special character escaping of event titles [MrPetovan]
Fixed a bug in HTML special character conversion in item titles [MrPetovan]
@ -26,7 +46,19 @@ Version 2019.09-dev (UNRELEASED)
Fixed a bug that prevented the display of images in some postings from diaspora* [MrPetovan]
Fixed a bug in setting the permissions on uploaded images [annando]
Fixed a bug that lead to potentially unwanted importing threads started by contacts of contacts [annando]
Fixed implicit self mentions [MrPetovan]
Fixed display of register links on closed nodes landing pages [MrPetovan]
Fixed the display of [spoiler] tags [MrPetovan]
Fixed an issue with photo permissions in private mails [annando]
Fixed a bug in the process of following Pleroma accounts [annando]
Fixed a bug that caused notifications about locally deleted items [annando]
Fixed the link to the source of an event [MrPetovan]
Fixed a problem that caused authors from twitter postings having no profile pic [annando]
Fixed a bug in BBCode -> Markdown conversation for font size [annando]
Fixed a BBCode parser problem with the audio tag [MrPetovan]
Fixed a session problem [annando]
Fixed a problem with the auto-installer [nupplaphil]
Fixed a bug with magic links redirection for non profiles [annando]
General code cleaning [annando, MrPetovan, nupplaphil]
Removed contacts auto completion (in /contacts [MrPetovan]
Replaced FontAwesome by ForkAwesome in frio theme [vinzv]
@ -37,19 +69,29 @@ Version 2019.09-dev (UNRELEASED)
Added support of wildcards to server block lists [MrPetovan]
Added app specific passwords when using 2FA [MrPetovan]
Added fetching of postings via URL to interact with public postings [annando]
Added opt-out flag for federated search engines and associated header information for profiles [annando]
Friendica Addons:
Update to the translation (CS, DE, FR, JA, NL SV) [translation teams]
Update to the translation (CS, DE, EN GB, EN US, ES, FR, JA, NL SV) [translation teams]
General code cleanup [nupplaphil, Quix0r]
blockbot:
Added translations
Added more bots [annando]
Added admin panel settings [annando]
tumblr:
Changed used URLs to https adopting tumblrs change [annando]
twitter:
Enhanced handling of multi image postings [annando]
Enhanced display of quoted tweets [MrPetovan]
Added alternative text support for images [annando]
Closed Issues:
3816, 4815, 6384, 6675, 7235, 7293, 7314, 7317, 7337, 7338, 7346,
7350, 7367, 7383, 7396, 7397, 7401, 7406, 7408, 7426, 7428, 7456,
7442, 7457, 7468, 7471, 7473, 7488, 7497, 7498, 7501, 7507, 7522,
7527, 7536, 7542, 7545
870, 1605, 2199, 3239, 3816, 4117, 4815, 5721, 6384, 6521, 6553,
6675, 7212, 7235, 7285, 7293, 7314, 7317, 7337, 7338, 7346, 7350,
7367, 7383, 7396, 7397, 7401, 7406, 7408, 7426, 7428, 7456, 7442,
7457, 7468, 7471, 7473, 7488, 7497, 7498, 7501, 7507, 7521, 7526,
7527, 7536, 7542, 7545, 7576, 7586, 7594, 7597, 7603, 7610, 7618,
7629, 7635, 7638, 7663, 7665, 7672
Version 2019.06 (2019-06-23)
Friendica Core:

View file

@ -1 +1 @@
2019.09-rc
2019.12-dev

4
Vagrantfile vendored
View file

@ -6,8 +6,8 @@ server_timezone = "UTC"
public_folder = "/vagrant"
Vagrant.configure(2) do |config|
# Set server to Ubuntu 16.04
config.vm.box = "ubuntu/xenial64"
# Set server to Debian 10 / Buster 64bit
config.vm.box = "debian/buster64"
# Disable automatic box update checking. If you disable this, then
# boxes will only be checked for updates when the user runs

279
autotest.sh Executable file
View file

@ -0,0 +1,279 @@
#!/usr/bin/env bash
#
# This script is used for autotesting the Friendica codebase with different
# types of tests and environments.
#
# Currently, there are three types of autotesting possibilities:
# - "USEDOCKER=true ./autotest.sh" will start a database docker container for testing
# - "./autotest.sh" on the Drone CI environment will use the database container of the drone CI pipeline
# - "./autotest.sh" on a local environment will try to use the local database instance for testing
#
# You can specify a database (mysql, mariadb currently) for the db backend of Friendica ("./autotest.sh mysql")
# And you can specify some parameters for the test, like:
# - NOCOVERAGE=true ... Don't create a coverage XML (this is only useful if you will send coverage to codecov.io)
# - NOINSTALL=true ... Skip the whole Friendica installation process (e.g. you just test Caching drivers)
# - 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
DBCONFIGS="mysql mariadb"
TESTS="REDIS MEMCACHE MEMCACHED APCU NODB"
export MYSQL_DATABASE="$DATABASENAME"
export MYSQL_USERNAME="$DATABASEUSER"
export MYSQL_PASSWORD="friendica"
if [ -z "$PHP_EXE" ]; then
PHP_EXE=php
fi
PHP=$(which "$PHP_EXE")
# Use the Friendica internal composer
COMPOSER="$BASEDIR/bin/composer.phar"
set -e
_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\"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
echo -e "\t\"MYSQL_USDRNAME\" Mysql Username (Default: friendica)" >&2
echo -e "\t\"MYSQL_DATABASE\" Mysql Database (Default: test)" >&2
echo -e "\nOther environment variables:\n" >&2
echo -e "\t\"TEST_SELECTION\" test a specific group of tests, can be one of: $TESTS" >&2
echo -e "\t\"NOINSTALL\" If set to true, skip the db and install process" >&2
echo -e "\t\"NOCOVERAGE\" If set to true, don't create a coverage output" >&2
echo -e "\t\"USEDOCKER\" If set to true, the DB server will be executed inside a docker container" >&2
echo -e "\nExample: NOCOVERAGE=true ./autotest.sh mysql src/Core/Cache/MemcacheTest.php" >&2
echo "will run the test suite from \"tests/src/Core/Cache/MemcacheTest.php\" without a Coverage" >&2
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"
else
echo "Could not find PHP executable $PHP_EXE" >&2
exit 3
fi
echo "Installing depdendencies"
$PHP "$COMPOSER" install
PHPUNIT="$BASEDIR/vendor/bin/phpunit"
if [ -x "$PHPUNIT" ]; then
echo "Using PHPUnit executable $PHPUNIT"
else
echo "Could not find PHPUnit executable after composer $PHPUNIT" >&2
exit 3
fi
if ! [ \( -w config -a ! -f config/local.config.php \) -o \( -f config/local.config.php -a -w config/local.config.php \) ]; then
echo "Please enable write permissions on config and config/config.php" >&2
exit 1
fi
if [ "$1" ]; then
FOUND=0
for DBCONFIG in $DBCONFIGS; do
if [ "$1" = "$DBCONFIG" ]; then
FOUND=1
break
fi
done
if [ $FOUND = 0 ]; then
echo -e "Unknown database config name \"$1\"\n" >&2
show_syntax
exit 2
fi
fi
# Back up existing (dev) config if one exists and backup not already there
if [ -f config/local.config.php ] && [ ! -f config/local.config-autotest-backup.php ]; then
mv config/local.config.php config/local.config-autotest-backup.php
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"
fi
cd "$BASEDIR"
# Restore existing config
if [ -f config/local.config-autotest-backup.php ]; then
mv config/local.config-autotest-backup.php config/local.config.php
fi
}
# restore config on exit
trap cleanup_config EXIT
function execute_tests() {
DB=$1
echo "Setup environment for $DB testing ..."
# back to root folder
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
#drop database
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_PASSWORD=friendica \
-e MYSQL_DATABASE="$DATABASENAME" \
-d mysql)
DATABASEHOST=$(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 [ "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
else
DATABASEHOST=mysql
fi
fi
echo "Waiting for MySQL $DATABASEHOST initialization..."
if ! bin/wait-for-connection $DATABASEHOST 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
echo "Fire up the mariadb docker"
DOCKER_CONTAINER_ID=$(docker run \
-e MYSQL_ROOT_PASSWORD=friendica \
-e MYSQL_USER="$DATABASEUSER" \
-e MYSQL_PASSWORD=friendica \
-e MYSQL_DATABASE="$DATABASENAME" \
-d mariadb)
DATABASEHOST=$(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 [ "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
else
DATABASEHOST=mariadb
fi
fi
echo "Waiting for MariaDB $DATABASEHOST initialization..."
if ! bin/wait-for-connection $DATABASEHOST 3306 300; then
echo "[ERROR] Waited 300 seconds, no response" >&2
exit 1
fi
echo "MariaDB is up."
fi
if [ -n "$USEDOCKER" ]; then
echo "Initialize database..."
docker exec $DOCKER_CONTAINER_ID mysql -u root -pfriendica -e 'CREATE DATABASE IF NOT EXISTS $DATABASENAME;'
fi
export MYSQL_HOST="$DATABASEHOST"
#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
fi
#test execution
echo "Testing..."
rm -fr "coverage-html"
mkdir "coverage-html"
if [[ "$_XDEBUG_CONFIG" ]]; then
export XDEBUG_CONFIG=$_XDEBUG_CONFIG
fi
COVER=''
if [ -z "$NOCOVERAGE" ]; then
COVER="--coverage-clover tests/autotest-clover.xml"
else
echo "No coverage"
fi
# per default, there is no cache installed
GROUP='--exclude-group REDIS,MEMCACHE,MEMCACHED,APCU'
if [ "$TEST_SELECTION" == "REDIS" ]; then
GROUP="--group REDIS"
fi
if [ "$TEST_SELECTION" == "MEMCACHE" ]; then
GROUP="--group MEMCACHE"
fi
if [ "$TEST_SELECTION" == "MEMCACHED" ]; then
GROUP="--group MEMCACHED"
fi
if [ "$TEST_SELECTION" == "APCU" ]; then
GROUP="--group APCU"
fi
if [ "$TEST_SELECTION" == "NODB" ]; then
GROUP="--exclude-group DB,SLOWDB"
fi
INPUT="$BASEDIR/tests"
if [ -n "$2" ]; then
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"
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
fi
}
#
# Start the test execution
#
if [ -z "$1" ] && [ -n "$TEST_SELECTION" ]; then
# run all known database configs
for DBCONFIG in $DBCONFIGS; do
execute_tests "$DBCONFIG"
done
else
FILENAME="$2"
if [ -n "$2" ] && [ ! -f "tests/$FILENAME" ] && [ "${FILENAME:0:2}" != "--" ]; then
FILENAME="../$FILENAME"
fi
execute_tests "$1" "$FILENAME" "$3"
fi

View file

@ -36,6 +36,7 @@ use Dice\Dice;
use Friendica\App\Mode;
use Friendica\BaseObject;
use Friendica\Util\ExAuth;
use Psr\Log\LoggerInterface;
if (sizeof($_SERVER["argv"]) == 0) {
die();
@ -54,6 +55,8 @@ chdir($directory);
require dirname(__DIR__) . '/vendor/autoload.php';
$dice = (new Dice())->addRules(include __DIR__ . '/../static/dependencies.config.php');
$dice = $dice->addRule(LoggerInterface::class,['constructParams' => ['auth_ejabberd']]);
BaseObject::setDependencyInjection($dice);
$appMode = $dice->create(Mode::class);

View file

@ -2,9 +2,11 @@
<?php
use Dice\Dice;
use Psr\Log\LoggerInterface;
require dirname(__DIR__) . '/vendor/autoload.php';
$dice = (new Dice())->addRules(include __DIR__ . '/../static/dependencies.config.php');
$dice = $dice->addRule(LoggerInterface::class,['constructParams' => ['console']]);
(new Friendica\Core\Console($dice, $argv))->execute();

View file

@ -12,6 +12,7 @@ use Friendica\Core\Config;
use Friendica\Core\Logger;
use Friendica\Core\Worker;
use Friendica\Database\DBA;
use Psr\Log\LoggerInterface;
// Get options
$shortopts = 'f';
@ -33,6 +34,7 @@ if (!file_exists("boot.php") && (sizeof($_SERVER["argv"]) != 0)) {
require dirname(__DIR__) . '/vendor/autoload.php';
$dice = (new Dice())->addRules(include __DIR__ . '/../static/dependencies.config.php');
$dice = $dice->addRule(LoggerInterface::class,['constructParams' => ['daemon']]);
\Friendica\BaseObject::setDependencyInjection($dice);
$a = \Friendica\BaseObject::getApp();

View file

@ -48,9 +48,9 @@ sudo systemctl restart apache2
#Install mysql
echo ">>> Installing Mysql"
sudo debconf-set-selections <<< "mysql-server mysql-server/root_password password root"
sudo debconf-set-selections <<< "mysql-server mysql-server/root_password_again password root"
sudo apt-get install -qq mysql-server
sudo debconf-set-selections <<< "mariadb-server mariadb-server/root_password password root"
sudo debconf-set-selections <<< "mariadb-server mariadb-server/root_password_again password root"
sudo apt-get install -qq mariadb-server
# enable remote access
# setting the mysql bind-address to allow connections from everywhere
sed -i "s/bind-address.*/bind-address = 0.0.0.0/" /etc/mysql/my.cnf
@ -76,6 +76,9 @@ debconf-set-selections <<< "postfix postfix/main_mailer_type string 'Local Only'
sudo apt-get install -y postfix mailutils libmailutils-dev
sudo echo -e "friendica1: vagrant\nfriendica2: vagrant\nfriendica3: vagrant\nfriendica4: vagrant\nfriendica5: vagrant" >> /etc/aliases && sudo newaliases
# Friendica needs git for fetching some dependencies
sudo apt-get install -y git
#make the vagrant directory the docroot
sudo rm -rf /var/www/
sudo ln -fs /vagrant /var/www
@ -83,7 +86,7 @@ sudo ln -fs /vagrant /var/www
# install deps with composer
sudo apt install unzip
cd /var/www
php bin/composer.phar install
sudo -u www-data php bin/composer.phar install
# initial config file for friendica in vagrant
cp /vagrant/mods/local.config.vagrant.php /vagrant/config/local.config.php

45
bin/wait-for-connection Executable file
View file

@ -0,0 +1,45 @@
#!/usr/bin/php
#
# This script tries to connect to a database for a given interval
# Useful in case of installation e.g. to wait for the database to not generate unnecessary errors
#
# Usage: php bin/wait-for-connection {HOST} {PORT} [{TIMEOUT}]
<?php
$timeout = 60;
switch ($argc) {
case 4:
$timeout = (float)$argv[3];
case 3:
$host = $argv[1];
$port = (int)$argv[2];
break;
default:
fwrite(STDERR, 'Usage: '.$argv[0].' host port [timeout]'."\n");
exit(2);
}
if ($timeout < 0) {
fwrite(STDERR, 'Timeout must be greater than zero'."\n");
exit(2);
}
if ($port < 1) {
fwrite(STDERR, 'Port must be an integer greater than zero'."\n");
exit(2);
}
$socketTimeout = (float)ini_get('default_socket_timeout');
if ($socketTimeout > $timeout) {
$socketTimeout = $timeout;
}
$stopTime = time() + $timeout;
do {
$sock = @fsockopen($host, $port, $errno, $errstr, $socketTimeout);
if ($sock !== false) {
fclose($sock);
fwrite(STDOUT, "\n");
exit(0);
}
sleep(1);
fwrite(STDOUT, '.');
} while (time() < $stopTime);
fwrite(STDOUT, "\n");
exit(1);

View file

@ -11,6 +11,7 @@ use Friendica\BaseObject;
use Friendica\Core\Config;
use Friendica\Core\Update;
use Friendica\Core\Worker;
use Psr\Log\LoggerInterface;
// Get options
$shortopts = 'sn';
@ -32,6 +33,7 @@ if (!file_exists("boot.php") && (sizeof($_SERVER["argv"]) != 0)) {
require dirname(__DIR__) . '/vendor/autoload.php';
$dice = (new Dice())->addRules(include __DIR__ . '/../static/dependencies.config.php');
$dice = $dice->addRule(LoggerInterface::class,['constructParams' => ['worker']]);
BaseObject::setDependencyInjection($dice);
$a = BaseObject::getApp();

View file

@ -23,6 +23,7 @@ use Friendica\Core\Config;
use Friendica\Core\PConfig;
use Friendica\Core\Protocol;
use Friendica\Core\System;
use Friendica\Core\Session;
use Friendica\Database\DBA;
use Friendica\Model\Contact;
use Friendica\Model\Term;
@ -31,7 +32,7 @@ use Friendica\Util\DateTimeFormat;
define('FRIENDICA_PLATFORM', 'Friendica');
define('FRIENDICA_CODENAME', 'Dalmatian Bellflower');
define('FRIENDICA_VERSION', '2019.09-rc');
define('FRIENDICA_VERSION', '2019.12-dev');
define('DFRN_PROTOCOL_VERSION', '2.23');
define('NEW_UPDATE_ROUTINE_VERSION', 1170);
@ -321,47 +322,6 @@ function get_app()
return BaseObject::getApp();
}
/**
* Return the provided variable value if it exists and is truthy or the provided
* default value instead.
*
* Works with initialized variables and potentially uninitialized array keys
*
* Usages:
* - defaults($var, $default)
* - defaults($array, 'key', $default)
*
* @param array $args
* @brief Returns a defaut value if the provided variable or array key is falsy
* @return mixed
* @deprecated since version 2019.06, use native coalesce operator (??) instead
*/
function defaults(...$args)
{
if (count($args) < 2) {
throw new BadFunctionCallException('defaults() requires at least 2 parameters');
}
if (count($args) > 3) {
throw new BadFunctionCallException('defaults() cannot use more than 3 parameters');
}
if (count($args) === 3 && is_null($args[1])) {
throw new BadFunctionCallException('defaults($arr, $key, $def) $key is null');
}
// The default value always is the last argument
$return = array_pop($args);
if (count($args) == 2 && is_array($args[0]) && !empty($args[0][$args[1]])) {
$return = $args[0][$args[1]];
}
if (count($args) == 1 && !empty($args[0])) {
$return = $args[0];
}
return $return;
}
/**
* @brief Used to end the current process, after saving session state.
* @deprecated
@ -415,20 +375,14 @@ function public_contact()
*/
function remote_user()
{
// You cannot be both local and remote.
// Unncommented by rabuzarus because remote authentication to local
// profiles wasn't possible anymore (2018-04-12).
// if (local_user()) {
// return false;
// }
if (empty($_SESSION)) {
if (empty($_SESSION['authenticated'])) {
return false;
}
if (!empty($_SESSION['authenticated']) && !empty($_SESSION['visitor_id'])) {
if (!empty($_SESSION['visitor_id'])) {
return intval($_SESSION['visitor_id']);
}
return false;
}
@ -532,7 +486,7 @@ function is_site_admin()
$adminlist = explode(',', str_replace(' ', '', $admin_email));
return local_user() && $admin_email && in_array(defaults($a->user, 'email', ''), $adminlist);
return local_user() && $admin_email && in_array($a->user['email'] ?? '', $adminlist);
}
function explode_querystring($query)

564
composer.lock generated

File diff suppressed because it is too large Load diff

View file

@ -533,7 +533,7 @@ Here is a complete list of all hook callbacks with file locations (as of 24-Sep-
Hook::callAll("parse_link", $arr);
### mod/manage.php
### src/Module/Delegation.php
Hook::callAll('home_init', $ret);

View file

@ -602,6 +602,9 @@ While taking pictures in the woods I had a really strange encounter...</td>
The [abstract] element is not working with connectors where we post HTML directly, like Tumblr, Wordpress or Pump.io.
For the native connections--that is to e.g. Friendica, Hubzilla, Diaspora or GNU Social--the full posting is used and the contacts instance will display the posting as desired.
For postings that are delivered via ActivityPub, the text from the abstract is placed in the summary field.
On Mastodon this field is used for the content warning.
## Special
<table class="bbcodes">

View file

@ -81,6 +81,7 @@ Here's a few primers if you are new to Friendica or to the PSR-2 coding standard
* No closing PHP tag
* No trailing spaces
* Array declarations use the new square brackets syntax
* Quoting style is single quotes by default, except for needed string interpolation, SQL query strings by convention and comments that should stay in natural language.
Don't worry, you don't have to know by heart the PSR-2 coding standards to start contributing to Friendica.
There are a few tools you can use to check or fix your files before you commit.

View file

@ -40,7 +40,7 @@ You are not required to do this, but the alternative is to log out and log back
This could get cumbersome if you manage several different forums/identities.
You may also appoint a delegate to manage your forum.
Do this by visiting the [Delegation Setup Page](delegate).
Do this by visiting the [Delegation Setup Page](settings/delegation).
This will provide you with a list of contacts on this system under "Potential Delegates".
Selecting one or more persons will give them access to manage your forum.
They will be able to edit contacts, profiles, and all content for this account/page.

View file

@ -11,13 +11,13 @@ with your web browser.
You will need to be logged in at the time.
You will be asked for your password to confirm the request.
If this matches your stored password, your account will immediately be blocked to all probing.
Unlike some social networks we do **not** hold onto it for a grace period in case you change your mind.
All your content and user data, etc is instantly removed.
For all intents and purposes, the account is gone in moments.
If this matches your stored password, your account will immediately be marked as deleted.
There is no grace period, this action cannot be reverted.
Most of your content and user data will be deleted shortly in the background.
We then send out an "unfriend" signal to all of your contacts.
This signal deletes all content on those networks.
Unfortunately, due to limitations of the other networks, this only works well with Friendica contacts.
We allow four days for this, in case some servers were down and the unfriend signal was queued.
After this, we finish off deleting the account.
We then send out a notification about the account removal to all of your contacts so that they can do the same with their copy of your data.
For technical reasons some of your user data is still needed to transmit this removal message.
This remaining data will be deleted after a period of around seven days.
To disallow impersonation we have to save your used nickname, so that it can't be used again to register on this node.

View file

@ -256,7 +256,7 @@ Eine komplette Liste aller Hook-Callbacks mit den zugehörigen Dateien (am 01-Ap
Hook::callAll("parse_link", $arr);
### mod/manage.php
### src/Module/Delegation.php
Hook::callAll('home_init', $ret);

View file

@ -580,6 +580,9 @@ F&uuml;r Verbindungen zu Netzwerken, zu denen Friendica den HTML Code postet, wi
Bei nativen Verbindungen; das hei&szlig;t zu z.B. Friendica, Hubzilla, Diaspora oder GNU Social Kontakten; wird der ungek&uuml;rzte Beitrag &uuml;bertragen.
Die Instanz des Kontakts k&uuml;mmert sich um die Darstellung.
Wird ein Beitrag über das ActivityPub Protokoll &uuml;bermittelt, wird der Text des Abstracts f&uuml;r das "summary" (Zusammenfassung) Feld verwendet.
Dieses Feld wird von Mastodon f&uuml;r die Inhaltswarnung (content warning) verwendet.
## Special
<table class="bbcodes">

View file

@ -38,7 +38,7 @@ Du musst das nicht machen, die Alternative ist allerdings, Dich immer wieder aus
Und das kann umständlich sein, wenn Du mehrere verschiedene Foren/Identitäten verwaltest.
Du kannst ebenso jemanden wählen, der Dein Forum verwaltet.
Mach das, indem Du die [Delegations-Setup-Seite](/delegate) besuchst.
Mach das, indem Du die [Delegations-Setup-Seite](/settings/delegation) besuchst.
Dort wird Dir eine Liste an "Potentiellen Bevollmächtigen" angezeigt.
Die Auswahl einer oder mehrerer Personen gibt diesen die Möglichkeit, Dein Forum zu verwalten.
Sie können Kontakte, Profile und alle Inhalte Deines Accounts/deiner Seite bearbeiten.

View file

@ -10,24 +10,14 @@ Wir freuen uns nicht, wenn Leute Friendica verlassen, aber wenn du deinen Accoun
in deinem Webbrowser. Du musst dabei eingeloggt sein.
Du wirst nach deinem Passwort gefragt, um die Anfrage zu bestätigen.
Wenn dieses mit deinem gespeichertem Passwort übereinstimmt, dann wird dein Account sofort gelöscht.
Anders als andere Netzwerke, behalten wir die Daten **nicht** für eine gewisse Zeit, falls du deine Meinung noch änderst.
Deine Nutzerdetails, deine Unterhaltungen, deine Photos, deine Freunde - alles; wird sofort gelöscht und du wirst ausgeloggt.
Wenn dieses mit deinem gespeichertem Passwort übereinstimmt, dann wird dein Account als "gelöscht" markiert.
Dies passiert sofort und kann nicht rückgängig gemacht werden.
Die meisten Deiner Inhalte und Benutzerdaten werden kurzfristig danach durch Hintergrundprozesse gelöscht.
Wenn Beiträge ablaufen, schicken wir Mitteilungen an Friendica, um diese zu löschen.
Diaspora hat keine automatische Löschfunktion, so dass diese Funktion in dem Netzwerk deaktiviert ist.
Und hoffentlich ist klar, dass das Löschen auch in anderen Netzwerken nicht funktioniert.
Wenn du manuell einen Beitrag bzw. eine Reihe von Beiträgen löschst, dann senden wir individuelle Mitteilungen zu Friendica und Diaspora für jeden gelöschten Post.
Parallel dazu senden wir eine Mitteilung an die Server deiner Kontakte, damit sie deine dort vorliegenden Daten ebenfalls löschen.
Wir haben keinen Einfluss darauf, wie sorgfältig und ob überhaupt diese Systeme der Löschaufforderung nachgehen.
Diaspora versäumt dieses oft.
Aus technischen Gründen benötigen wir für die Übetragung dieser Mitteilung ein paar Benutzerdaten.
Diese Daten werden dann nach einer Frist von etwa sieben Tagen ebenfalls gelöscht.
Wenn du einen Beitrag löscht, aber jemand diesem Beitrag folgt, wird es trotzdem gelöscht.
Dein Wunsch hat Priorität.
Wenn du deinen Account löscht, dann löschen wir alle Beiträge, dein Profil, die Nutzerdaten etc. sofort.
Um einen Gesamtlöschauftrag zu versenden, bräuchten wir zunächst noch deinen Account; auch, um deinen Freunden zu zeigen, wer diese Anfrage stellt.
Das können wir nicht tun, wenn du keinen Account mehr hast.
Deine Freunde können möglicherweise noch deine Beiträge sehen, wenn dein Account gelöscht wurde, aber es gibt keinen öffentlichen Ort in Friendica mehr, wo diese angeschaut werden können.
Wenn du Freunde bei Diaspora hast, kann es sein, dass deine Beiträge weiterhin vorhanden und für andere aus diesem Netzwerk sichtbar sind.
Wir speichern deinen Benutzernamen dauerhaft, damit sich niemand einen Account unter deinem Spitznamen anlegen kann.

View file

@ -177,6 +177,7 @@ Field parameter:
1. Label for the input box,
2. Current text for the box,
3. Help text for the input box.
4. if set to "required" modern browser will check that this input box is filled when submitting the form,
### field_yesno.tpl

View file

@ -48,9 +48,9 @@ use Friendica\Util\Proxy as ProxyUtils;
use Friendica\Util\Strings;
use Friendica\Util\XML;
require_once 'mod/share.php';
require_once 'mod/item.php';
require_once 'mod/wall_upload.php';
require_once __DIR__ . '/../mod/share.php';
require_once __DIR__ . '/../mod/item.php';
require_once __DIR__ . '/../mod/wall_upload.php';
define('API_METHOD_ANY', '*');
define('API_METHOD_GET', 'GET');
@ -162,6 +162,7 @@ function api_register_func($path, $func, $auth = false, $method = API_METHOD_ANY
* @brief Login API user
*
* @param App $a App
* @throws ForbiddenException
* @throws InternalServerErrorException
* @throws UnauthorizedException
* @hook 'authenticate'
@ -170,8 +171,6 @@ function api_register_func($path, $func, $auth = false, $method = API_METHOD_ANY
* 'password' => password from login form
* 'authenticated' => return status,
* 'user_record' => return authenticated user record
* @hook 'logged_in'
* array $user logged user record
*/
function api_login(App $a)
{
@ -182,7 +181,7 @@ function api_login(App $a)
list($consumer, $token) = $oauth1->verify_request($request);
if (!is_null($token)) {
$oauth1->loginUser($token->uid);
Hook::callAll('logged_in', $a->user);
Session::set('allow_api', true);
return;
}
echo __FILE__.__LINE__.__FUNCTION__ . "<pre>";
@ -208,8 +207,8 @@ function api_login(App $a)
throw new UnauthorizedException("This API requires login");
}
$user = defaults($_SERVER, 'PHP_AUTH_USER', '');
$password = defaults($_SERVER, 'PHP_AUTH_PW', '');
$user = $_SERVER['PHP_AUTH_USER'] ?? '';
$password = $_SERVER['PHP_AUTH_PW'] ?? '';
// allow "user@server" login (but ignore 'server' part)
$at = strstr($user, "@", true);
@ -273,7 +272,7 @@ function api_check_method($method)
if ($method == "*") {
return true;
}
return (stripos($method, defaults($_SERVER, 'REQUEST_METHOD', 'GET')) !== false);
return (stripos($method, $_SERVER['REQUEST_METHOD'] ?? 'GET') !== false);
}
/**
@ -323,7 +322,7 @@ function api_call(App $a)
$stamp = microtime(true);
$return = call_user_func($info['func'], $type);
$duration = (float) (microtime(true) - $stamp);
$duration = floatval(microtime(true) - $stamp);
Logger::info(API_LOG_PREFIX . 'username {username}', ['module' => 'api', 'action' => 'call', 'username' => $a->user['username'], 'duration' => round($duration, 2)]);
@ -776,14 +775,14 @@ function api_get_user(App $a, $contact_id = null)
*/
function api_item_get_user(App $a, $item)
{
$status_user = api_get_user($a, defaults($item, 'author-id', null));
$status_user = api_get_user($a, $item['author-id'] ?? null);
$author_user = $status_user;
$status_user["protected"] = defaults($item, 'private', 0);
$status_user["protected"] = $item['private'] ?? 0;
if (defaults($item, 'thr-parent', '') == defaults($item, 'uri', '')) {
$owner_user = api_get_user($a, defaults($item, 'owner-id', null));
if (($item['thr-parent'] ?? '') == ($item['uri'] ?? '')) {
$owner_user = api_get_user($a, $item['owner-id'] ?? null);
} else {
$owner_user = $author_user;
}
@ -947,7 +946,7 @@ function api_account_verify_credentials($type)
unset($_REQUEST["screen_name"]);
unset($_GET["screen_name"]);
$skip_status = defaults($_REQUEST, 'skip_status', false);
$skip_status = $_REQUEST['skip_status'] ?? false;
$user_info = api_get_user($a);
@ -1518,10 +1517,12 @@ function api_search($type)
$count = $_REQUEST['count'];
}
$since_id = defaults($_REQUEST, 'since_id', 0);
$max_id = defaults($_REQUEST, 'max_id', 0);
$page = (!empty($_REQUEST['page']) ? $_REQUEST['page'] - 1 : 0);
$start = $page * $count;
$since_id = $_REQUEST['since_id'] ?? 0;
$max_id = $_REQUEST['max_id'] ?? 0;
$page = $_REQUEST['page'] ?? 1;
$start = max(0, ($page - 1) * $count);
$params = ['order' => ['id' => true], 'limit' => [$start, $count]];
if (preg_match('/^#(\w+)$/', $searchTerm, $matches) === 1 && isset($matches[1])) {
$searchTerm = $matches[1];
@ -1609,17 +1610,14 @@ function api_statuses_home_timeline($type)
// get last network messages
// params
$count = defaults($_REQUEST, 'count', 20);
$page = (!empty($_REQUEST['page']) ? $_REQUEST['page'] - 1 : 0);
if ($page < 0) {
$page = 0;
}
$since_id = defaults($_REQUEST, 'since_id', 0);
$max_id = defaults($_REQUEST, 'max_id', 0);
$count = $_REQUEST['count'] ?? 20;
$page = $_REQUEST['page']?? 0;
$since_id = $_REQUEST['since_id'] ?? 0;
$max_id = $_REQUEST['max_id'] ?? 0;
$exclude_replies = !empty($_REQUEST['exclude_replies']);
$conversation_id = defaults($_REQUEST, 'conversation_id', 0);
$conversation_id = $_REQUEST['conversation_id'] ?? 0;
$start = $page * $count;
$start = max(0, ($page - 1) * $count);
$condition = ["`uid` = ? AND `gravity` IN (?, ?) AND `item`.`id` > ?",
api_user(), GRAVITY_PARENT, GRAVITY_COMMENT, $since_id];
@ -1699,17 +1697,14 @@ function api_statuses_public_timeline($type)
// get last network messages
// params
$count = defaults($_REQUEST, 'count', 20);
$page = (!empty($_REQUEST['page']) ? $_REQUEST['page'] -1 : 0);
if ($page < 0) {
$page = 0;
}
$since_id = defaults($_REQUEST, 'since_id', 0);
$max_id = defaults($_REQUEST, 'max_id', 0);
$count = $_REQUEST['count'] ?? 20;
$page = $_REQUEST['page'] ?? 1;
$since_id = $_REQUEST['since_id'] ?? 0;
$max_id = $_REQUEST['max_id'] ?? 0;
$exclude_replies = (!empty($_REQUEST['exclude_replies']) ? 1 : 0);
$conversation_id = defaults($_REQUEST, 'conversation_id', 0);
$conversation_id = $_REQUEST['conversation_id'] ?? 0;
$start = $page * $count;
$start = max(0, ($page - 1) * $count);
if ($exclude_replies && !$conversation_id) {
$condition = ["`gravity` IN (?, ?) AND `iid` > ? AND NOT `private` AND `wall` AND NOT `user`.`hidewall` AND NOT `author`.`hidden`",
@ -1784,16 +1779,14 @@ function api_statuses_networkpublic_timeline($type)
throw new ForbiddenException();
}
$since_id = defaults($_REQUEST, 'since_id', 0);
$max_id = defaults($_REQUEST, 'max_id', 0);
$since_id = $_REQUEST['since_id'] ?? 0;
$max_id = $_REQUEST['max_id'] ?? 0;
// pagination
$count = defaults($_REQUEST, 'count', 20);
$page = defaults($_REQUEST, 'page', 1);
if ($page < 1) {
$page = 1;
}
$start = ($page - 1) * $count;
$count = $_REQUEST['count'] ?? 20;
$page = $_REQUEST['page'] ?? 1;
$start = max(0, ($page - 1) * $count);
$condition = ["`uid` = 0 AND `gravity` IN (?, ?) AND `thread`.`iid` > ? AND NOT `private`",
GRAVITY_PARENT, GRAVITY_COMMENT, $since_id];
@ -1848,15 +1841,15 @@ function api_statuses_show($type)
}
// params
$id = intval(defaults($a->argv, 3, 0));
$id = intval($a->argv[3] ?? 0);
if ($id == 0) {
$id = intval(defaults($_REQUEST, 'id', 0));
$id = intval($_REQUEST['id'] ?? 0);
}
// Hotot workaround
if ($id == 0) {
$id = intval(defaults($a->argv, 4, 0));
$id = intval($a->argv[4] ?? 0);
}
Logger::log('API: api_statuses_show: ' . $id);
@ -1927,24 +1920,21 @@ function api_conversation_show($type)
}
// params
$id = intval(defaults($a->argv , 3 , 0));
$since_id = intval(defaults($_REQUEST, 'since_id', 0));
$max_id = intval(defaults($_REQUEST, 'max_id' , 0));
$count = intval(defaults($_REQUEST, 'count' , 20));
$page = intval(defaults($_REQUEST, 'page' , 1)) - 1;
if ($page < 0) {
$page = 0;
}
$id = intval($a->argv[3] ?? 0);
$since_id = intval($_REQUEST['since_id'] ?? 0);
$max_id = intval($_REQUEST['max_id'] ?? 0);
$count = intval($_REQUEST['count'] ?? 20);
$page = intval($_REQUEST['page'] ?? 1);
$start = $page * $count;
$start = max(0, ($page - 1) * $count);
if ($id == 0) {
$id = intval(defaults($_REQUEST, 'id', 0));
$id = intval($_REQUEST['id'] ?? 0);
}
// Hotot workaround
if ($id == 0) {
$id = intval(defaults($a->argv, 4, 0));
$id = intval($a->argv[4] ?? 0);
}
Logger::info(API_LOG_PREFIX . '{subaction}', ['module' => 'api', 'action' => 'conversation', 'subaction' => 'show', 'id' => $id]);
@ -2013,15 +2003,15 @@ function api_statuses_repeat($type)
api_get_user($a);
// params
$id = intval(defaults($a->argv, 3, 0));
$id = intval($a->argv[3] ?? 0);
if ($id == 0) {
$id = intval(defaults($_REQUEST, 'id', 0));
$id = intval($_REQUEST['id'] ?? 0);
}
// Hotot workaround
if ($id == 0) {
$id = intval(defaults($a->argv, 4, 0));
$id = intval($a->argv[4] ?? 0);
}
Logger::log('API: api_statuses_repeat: '.$id);
@ -2084,15 +2074,15 @@ function api_statuses_destroy($type)
api_get_user($a);
// params
$id = intval(defaults($a->argv, 3, 0));
$id = intval($a->argv[3] ?? 0);
if ($id == 0) {
$id = intval(defaults($_REQUEST, 'id', 0));
$id = intval($_REQUEST['id'] ?? 0);
}
// Hotot workaround
if ($id == 0) {
$id = intval(defaults($a->argv, 4, 0));
$id = intval($a->argv[4] ?? 0);
}
Logger::log('API: api_statuses_destroy: '.$id);
@ -2138,15 +2128,12 @@ function api_statuses_mentions($type)
// get last network messages
// params
$since_id = defaults($_REQUEST, 'since_id', 0);
$max_id = defaults($_REQUEST, 'max_id' , 0);
$count = defaults($_REQUEST, 'count' , 20);
$page = defaults($_REQUEST, 'page' , 1);
if ($page < 1) {
$page = 1;
}
$since_id = $_REQUEST['since_id'] ?? 0;
$max_id = $_REQUEST['max_id'] ?? 0;
$count = $_REQUEST['count'] ?? 20;
$page = $_REQUEST['page'] ?? 1;
$start = ($page - 1) * $count;
$start = max(0, ($page - 1) * $count);
$condition = ["`uid` = ? AND `gravity` IN (?, ?) AND `item`.`id` > ? AND `author-id` != ?
AND `item`.`parent` IN (SELECT `iid` FROM `thread` WHERE `thread`.`uid` = ? AND `thread`.`mention` AND NOT `thread`.`ignored`)",
@ -2208,18 +2195,16 @@ function api_statuses_user_timeline($type)
Logger::DEBUG
);
$since_id = defaults($_REQUEST, 'since_id', 0);
$max_id = defaults($_REQUEST, 'max_id', 0);
$since_id = $_REQUEST['since_id'] ?? 0;
$max_id = $_REQUEST['max_id'] ?? 0;
$exclude_replies = !empty($_REQUEST['exclude_replies']);
$conversation_id = defaults($_REQUEST, 'conversation_id', 0);
$conversation_id = $_REQUEST['conversation_id'] ?? 0;
// pagination
$count = defaults($_REQUEST, 'count', 20);
$page = defaults($_REQUEST, 'page', 1);
if ($page < 1) {
$page = 1;
}
$start = ($page - 1) * $count;
$count = $_REQUEST['count'] ?? 20;
$page = $_REQUEST['page'] ?? 1;
$start = max(0, ($page - 1) * $count);
$condition = ["`uid` = ? AND `gravity` IN (?, ?) AND `item`.`id` > ? AND `item`.`contact-id` = ?",
api_user(), GRAVITY_PARENT, GRAVITY_COMMENT, $since_id, $user_info['cid']];
@ -2298,9 +2283,9 @@ function api_favorites_create_destroy($type)
}
$action = str_replace("." . $type, "", $a->argv[$action_argv_id]);
if ($a->argc == $action_argv_id + 2) {
$itemid = intval(defaults($a->argv, $action_argv_id + 1, 0));
$itemid = intval($a->argv[$action_argv_id + 1] ?? 0);
} else {
$itemid = intval(defaults($_REQUEST, 'id', 0));
$itemid = intval($_REQUEST['id'] ?? 0);
}
$item = Item::selectFirstForUser(api_user(), [], ['id' => $itemid, 'uid' => api_user()]);
@ -2380,15 +2365,12 @@ function api_favorites($type)
$ret = [];
} else {
// params
$since_id = defaults($_REQUEST, 'since_id', 0);
$max_id = defaults($_REQUEST, 'max_id', 0);
$count = defaults($_GET, 'count', 20);
$page = (!empty($_REQUEST['page']) ? $_REQUEST['page'] -1 : 0);
if ($page < 0) {
$page = 0;
}
$since_id = $_REQUEST['since_id'] ?? 0;
$max_id = $_REQUEST['max_id'] ?? 0;
$count = $_GET['count'] ?? 20;
$page = $_REQUEST['page'] ?? 1;
$start = $page*$count;
$start = max(0, ($page - 1) * $count);
$condition = ["`uid` = ? AND `gravity` IN (?, ?) AND `id` > ? AND `starred`",
api_user(), GRAVITY_PARENT, GRAVITY_COMMENT, $since_id];
@ -2439,14 +2421,14 @@ function api_format_messages($item, $recipient, $sender)
'sender_id' => $sender['id'],
'text' => "",
'recipient_id' => $recipient['id'],
'created_at' => api_date(defaults($item, 'created', DateTimeFormat::utcNow())),
'created_at' => api_date($item['created'] ?? DateTimeFormat::utcNow()),
'sender_screen_name' => $sender['screen_name'],
'recipient_screen_name' => $recipient['screen_name'],
'sender' => $sender,
'recipient' => $recipient,
'title' => "",
'friendica_seen' => defaults($item, 'seen', 0),
'friendica_parent_uri' => defaults($item, 'parent-uri', ''),
'friendica_seen' => $item['seen'] ?? 0,
'friendica_parent_uri' => $item['parent-uri'] ?? '',
];
// "uid" and "self" are only needed for some internal stuff, so remove it from here
@ -2509,8 +2491,8 @@ function api_convert_item($item)
$statustext = trim($statustitle."\n\n".$statusbody);
}
if ((defaults($item, 'network', Protocol::PHANTOM) == Protocol::FEED) && (mb_strlen($statustext)> 1000)) {
$statustext = mb_substr($statustext, 0, 1000) . "... \n" . defaults($item, 'plink', '');
if ((($item['network'] ?? Protocol::PHANTOM) == Protocol::FEED) && (mb_strlen($statustext)> 1000)) {
$statustext = mb_substr($statustext, 0, 1000) . "... \n" . ($item['plink'] ?? '');
}
$statushtml = BBCode::convert(api_clean_attachments($body), false);
@ -2544,7 +2526,7 @@ function api_convert_item($item)
}
// feeds without body should contain the link
if ((defaults($item, 'network', Protocol::PHANTOM) == Protocol::FEED) && (strlen($item['body']) == 0)) {
if ((($item['network'] ?? Protocol::PHANTOM) == Protocol::FEED) && (strlen($item['body']) == 0)) {
$statushtml .= BBCode::convert($item['plink']);
}
@ -2587,7 +2569,7 @@ function api_get_attachments(&$body)
}
}
if (strstr(defaults($_SERVER, 'HTTP_USER_AGENT', ''), "AndStatus")) {
if (strstr($_SERVER['HTTP_USER_AGENT'] ?? '', 'AndStatus')) {
foreach ($images[0] as $orig) {
$body = str_replace($orig, "", $body);
}
@ -2607,7 +2589,7 @@ function api_get_attachments(&$body)
*/
function api_get_entitities(&$text, $bbcode)
{
$include_entities = strtolower(defaults($_REQUEST, 'include_entities', "false"));
$include_entities = strtolower($_REQUEST['include_entities'] ?? 'false');
if ($include_entities != "true") {
preg_match_all("/\[img](.*?)\[\/img\]/ism", $bbcode, $images);
@ -3040,6 +3022,8 @@ function api_format_item($item, $type = "json", $status_user = null, $author_use
'statusnet_conversation_id' => $item['parent'],
'external_url' => System::baseUrl() . "/display/" . $item['guid'],
'friendica_activities' => api_format_items_activities($item, $type),
'friendica_title' => $item['title'],
'friendica_html' => BBCode::convert($item['body'], false)
];
if (count($converted["attachments"]) > 0) {
@ -3310,17 +3294,14 @@ function api_lists_statuses($type)
}
// params
$count = defaults($_REQUEST, 'count', 20);
$page = (!empty($_REQUEST['page']) ? $_REQUEST['page'] - 1 : 0);
if ($page < 0) {
$page = 0;
}
$since_id = defaults($_REQUEST, 'since_id', 0);
$max_id = defaults($_REQUEST, 'max_id', 0);
$count = $_REQUEST['count'] ?? 20;
$page = $_REQUEST['page'] ?? 1;
$since_id = $_REQUEST['since_id'] ?? 0;
$max_id = $_REQUEST['max_id'] ?? 0;
$exclude_replies = (!empty($_REQUEST['exclude_replies']) ? 1 : 0);
$conversation_id = defaults($_REQUEST, 'conversation_id', 0);
$conversation_id = $_REQUEST['conversation_id'] ?? 0;
$start = $page * $count;
$start = max(0, ($page - 1) * $count);
$condition = ["`uid` = ? AND `gravity` IN (?, ?) AND `id` > ? AND `group_member`.`gid` = ?",
api_user(), GRAVITY_PARENT, GRAVITY_COMMENT, $since_id, $_REQUEST['list_id']];
@ -3380,12 +3361,10 @@ function api_statuses_f($qtype)
}
// pagination
$count = defaults($_GET, 'count', 20);
$page = defaults($_GET, 'page', 1);
if ($page < 1) {
$page = 1;
}
$start = ($page - 1) * $count;
$count = $_GET['count'] ?? 20;
$page = $_GET['page'] ?? 1;
$start = max(0, ($page - 1) * $count);
$user_info = api_get_user($a);
@ -3632,7 +3611,7 @@ function api_ff_ids($type)
api_get_user($a);
$stringify_ids = defaults($_REQUEST, 'stringify_ids', false);
$stringify_ids = $_REQUEST['stringify_ids'] ?? false;
$r = q(
"SELECT `pcontact`.`id` FROM `contact`
@ -3807,9 +3786,9 @@ function api_direct_messages_destroy($type)
// params
$user_info = api_get_user($a);
//required
$id = defaults($_REQUEST, 'id', 0);
$id = $_REQUEST['id'] ?? 0;
// optional
$parenturi = defaults($_REQUEST, 'friendica_parenturi', "");
$parenturi = $_REQUEST['friendica_parenturi'] ?? '';
$verbose = (!empty($_GET['friendica_verbose']) ? strtolower($_GET['friendica_verbose']) : "false");
/// @todo optional parameter 'include_entities' from Twitter API not yet implemented
@ -3890,7 +3869,7 @@ function api_friendships_destroy($type)
throw new ForbiddenException();
}
$contact_id = defaults($_REQUEST, 'user_id');
$contact_id = $_REQUEST['user_id'] ?? 0;
if (empty($contact_id)) {
Logger::notice(API_LOG_PREFIX . 'No user_id specified', ['module' => 'api', 'action' => 'friendships_destroy']);
@ -3971,17 +3950,14 @@ function api_direct_messages_box($type, $box, $verbose)
throw new ForbiddenException();
}
// params
$count = defaults($_GET, 'count', 20);
$page = defaults($_REQUEST, 'page', 1) - 1;
if ($page < 0) {
$page = 0;
}
$count = $_GET['count'] ?? 20;
$page = $_REQUEST['page'] ?? 1;
$since_id = defaults($_REQUEST, 'since_id', 0);
$max_id = defaults($_REQUEST, 'max_id', 0);
$since_id = $_REQUEST['since_id'] ?? 0;
$max_id = $_REQUEST['max_id'] ?? 0;
$user_id = defaults($_REQUEST, 'user_id', '');
$screen_name = defaults($_REQUEST, 'screen_name', '');
$user_id = $_REQUEST['user_id'] ?? '';
$screen_name = $_REQUEST['screen_name'] ?? '';
// caller user info
unset($_REQUEST["user_id"]);
@ -3997,7 +3973,7 @@ function api_direct_messages_box($type, $box, $verbose)
$profile_url = $user_info["url"];
// pagination
$start = $page * $count;
$start = max(0, ($page - 1) * $count);
$sql_extra = "";
@ -4005,7 +3981,7 @@ function api_direct_messages_box($type, $box, $verbose)
if ($box=="sentbox") {
$sql_extra = "`mail`.`from-url`='" . DBA::escape($profile_url) . "'";
} elseif ($box == "conversation") {
$sql_extra = "`mail`.`parent-uri`='" . DBA::escape(defaults($_GET, 'uri', '')) . "'";
$sql_extra = "`mail`.`parent-uri`='" . DBA::escape($_GET['uri'] ?? '') . "'";
} elseif ($box == "all") {
$sql_extra = "true";
} elseif ($box == "inbox") {
@ -4185,7 +4161,7 @@ function api_fr_photoalbum_delete($type)
throw new ForbiddenException();
}
// input params
$album = defaults($_REQUEST, 'album', "");
$album = $_REQUEST['album'] ?? '';
// we do not allow calls without album string
if ($album == "") {
@ -4240,8 +4216,8 @@ function api_fr_photoalbum_update($type)
throw new ForbiddenException();
}
// input params
$album = defaults($_REQUEST, 'album', "");
$album_new = defaults($_REQUEST, 'album_new', "");
$album = $_REQUEST['album'] ?? '';
$album_new = $_REQUEST['album_new'] ?? '';
// we do not allow calls without album string
if ($album == "") {
@ -4332,14 +4308,14 @@ function api_fr_photo_create_update($type)
throw new ForbiddenException();
}
// input params
$photo_id = defaults($_REQUEST, 'photo_id', null);
$desc = defaults($_REQUEST, 'desc', (array_key_exists('desc', $_REQUEST) ? "" : null)) ; // extra check necessary to distinguish between 'not provided' and 'empty string'
$album = defaults($_REQUEST, 'album', null);
$album_new = defaults($_REQUEST, 'album_new', null);
$allow_cid = defaults($_REQUEST, 'allow_cid', (array_key_exists('allow_cid', $_REQUEST) ? " " : null));
$deny_cid = defaults($_REQUEST, 'deny_cid' , (array_key_exists('deny_cid' , $_REQUEST) ? " " : null));
$allow_gid = defaults($_REQUEST, 'allow_gid', (array_key_exists('allow_gid', $_REQUEST) ? " " : null));
$deny_gid = defaults($_REQUEST, 'deny_gid' , (array_key_exists('deny_gid' , $_REQUEST) ? " " : null));
$photo_id = $_REQUEST['photo_id'] ?? null;
$desc = $_REQUEST['desc'] ?? null;
$album = $_REQUEST['album'] ?? null;
$album_new = $_REQUEST['album_new'] ?? null;
$allow_cid = $_REQUEST['allow_cid'] ?? null;
$deny_cid = $_REQUEST['deny_cid' ] ?? null;
$allow_gid = $_REQUEST['allow_gid'] ?? null;
$deny_gid = $_REQUEST['deny_gid' ] ?? null;
$visibility = !empty($_REQUEST['visibility']) && $_REQUEST['visibility'] !== "false";
// do several checks on input parameters
@ -4470,7 +4446,7 @@ function api_fr_photo_delete($type)
}
// input params
$photo_id = defaults($_REQUEST, 'photo_id', null);
$photo_id = $_REQUEST['photo_id'] ?? null;
// do several checks on input parameters
// we do not allow calls without photo id
@ -4557,7 +4533,7 @@ function api_account_update_profile_image($type)
throw new ForbiddenException();
}
// input params
$profile_id = defaults($_REQUEST, 'profile_id', 0);
$profile_id = $_REQUEST['profile_id'] ?? 0;
// error if image data is missing
if (empty($_FILES['image'])) {
@ -4689,9 +4665,10 @@ api_register_func('api/account/update_profile', 'api_account_update_profile', tr
*/
function check_acl_input($acl_string)
{
if ($acl_string == null || $acl_string == " ") {
if (empty($acl_string)) {
return false;
}
$contact_not_found = false;
// split <x><y><z> into array of cid's
@ -4709,7 +4686,6 @@ function check_acl_input($acl_string)
}
/**
*
* @param string $mediatype
* @param array $media
* @param string $type
@ -4728,6 +4704,7 @@ function check_acl_input($acl_string)
* @throws ImagickException
* @throws InternalServerErrorException
* @throws NotFoundException
* @throws UnauthorizedException
*/
function save_media_to_database($mediatype, $media, $type, $album, $allow_cid, $deny_cid, $allow_gid, $deny_gid, $desc, $profile = 0, $visibility = false, $photo_id = null)
{
@ -5062,8 +5039,8 @@ function prepare_photo_data($type, $scale, $photo_id)
*/
function api_friendica_remoteauth()
{
$url = defaults($_GET, 'url', '');
$c_url = defaults($_GET, 'c_url', '');
$url = $_GET['url'] ?? '';
$c_url = $_GET['c_url'] ?? '';
if ($url === '' || $c_url === '') {
throw new BadRequestException("Wrong parameters.");
@ -5081,7 +5058,7 @@ function api_friendica_remoteauth()
$cid = $contact['id'];
$dfrn_id = defaults($contact, 'issued-id', $contact['dfrn-id']);
$dfrn_id = $contact['issued-id'] ?? $contact['dfrn-id'];
if ($contact['duplex'] && $contact['issued-id']) {
$orig_id = $contact['issued-id'];
@ -5416,7 +5393,7 @@ function api_in_reply_to($item)
*/
function api_clean_plain_items($text)
{
$include_entities = strtolower(defaults($_REQUEST, 'include_entities', "false"));
$include_entities = strtolower($_REQUEST['include_entities'] ?? 'false');
$text = BBCode::cleanPictureLinks($text);
$URLSearchString = "^\[\]";
@ -5554,7 +5531,7 @@ function api_friendica_group_show($type)
// params
$user_info = api_get_user($a);
$gid = defaults($_REQUEST, 'gid', 0);
$gid = $_REQUEST['gid'] ?? 0;
$uid = $user_info['uid'];
// get data of the specified group id or all groups if not specified
@ -5624,8 +5601,8 @@ function api_friendica_group_delete($type)
// params
$user_info = api_get_user($a);
$gid = defaults($_REQUEST, 'gid', 0);
$name = defaults($_REQUEST, 'name', "");
$gid = $_REQUEST['gid'] ?? 0;
$name = $_REQUEST['name'] ?? '';
$uid = $user_info['uid'];
// error if no gid specified
@ -5691,7 +5668,7 @@ function api_lists_destroy($type)
// params
$user_info = api_get_user($a);
$gid = defaults($_REQUEST, 'list_id', 0);
$gid = $_REQUEST['list_id'] ?? 0;
$uid = $user_info['uid'];
// error if no gid specified
@ -5813,7 +5790,7 @@ function api_friendica_group_create($type)
// params
$user_info = api_get_user($a);
$name = defaults($_REQUEST, 'name', "");
$name = $_REQUEST['name'] ?? '';
$uid = $user_info['uid'];
$json = json_decode($_POST['json'], true);
$users = $json['user'];
@ -5847,7 +5824,7 @@ function api_lists_create($type)
// params
$user_info = api_get_user($a);
$name = defaults($_REQUEST, 'name', "");
$name = $_REQUEST['name'] ?? '';
$uid = $user_info['uid'];
$success = group_create($name, $uid);
@ -5887,8 +5864,8 @@ function api_friendica_group_update($type)
// params
$user_info = api_get_user($a);
$uid = $user_info['uid'];
$gid = defaults($_REQUEST, 'gid', 0);
$name = defaults($_REQUEST, 'name', "");
$gid = $_REQUEST['gid'] ?? 0;
$name = $_REQUEST['name'] ?? '';
$json = json_decode($_POST['json'], true);
$users = $json['user'];
@ -5965,8 +5942,8 @@ function api_lists_update($type)
// params
$user_info = api_get_user($a);
$gid = defaults($_REQUEST, 'list_id', 0);
$name = defaults($_REQUEST, 'name', "");
$gid = $_REQUEST['list_id'] ?? 0;
$name = $_REQUEST['name'] ?? '';
$uid = $user_info['uid'];
// error if no gid specified
@ -6015,7 +5992,7 @@ function api_friendica_activity($type)
$verb = strtolower($a->argv[3]);
$verb = preg_replace("|\..*$|", "", $verb);
$id = defaults($_REQUEST, 'id', 0);
$id = $_REQUEST['id'] ?? 0;
$res = Item::performLike($id, $verb);
@ -6152,7 +6129,7 @@ function api_friendica_direct_messages_setseen($type)
// params
$user_info = api_get_user($a);
$uid = $user_info['uid'];
$id = defaults($_REQUEST, 'id', 0);
$id = $_REQUEST['id'] ?? 0;
// return error if id is zero
if ($id == "") {
@ -6206,7 +6183,7 @@ function api_friendica_direct_messages_search($type, $box = "")
// params
$user_info = api_get_user($a);
$searchstring = defaults($_REQUEST, 'searchstring', "");
$searchstring = $_REQUEST['searchstring'] ?? '';
$uid = $user_info['uid'];
// error if no searchstring specified
@ -6273,7 +6250,7 @@ function api_friendica_profile_show($type)
}
// input params
$profile_id = defaults($_REQUEST, 'profile_id', 0);
$profile_id = $_REQUEST['profile_id'] ?? 0;
// retrieve general information about profiles for user
$multi_profiles = Feature::isEnabled(api_user(), 'multi_profiles');

View file

@ -365,7 +365,7 @@ function localize_item(&$item)
'network' => $item['author-network'], 'url' => $item['author-link']];
// Only create a redirection to a magic link when logged in
if (!empty($item['plink']) && (local_user() || remote_user())) {
if (!empty($item['plink']) && Session::isAuthenticated()) {
$item['plink'] = Contact::magicLinkByContact($author, $item['plink']);
}
}
@ -1208,7 +1208,7 @@ function status_editor(App $a, $x, $notes_cid = 0, $popup = false)
'$new_post' => L10n::t('New Post'),
'$return_path' => $query_str,
'$action' => 'item',
'$share' => defaults($x, 'button', L10n::t('Share')),
'$share' => ($x['button'] ?? '') ?: L10n::t('Share'),
'$upload' => L10n::t('Upload photo'),
'$shortupload' => L10n::t('upload photo'),
'$attach' => L10n::t('Attach file'),
@ -1225,17 +1225,17 @@ function status_editor(App $a, $x, $notes_cid = 0, $popup = false)
'$shortsetloc' => L10n::t('set location'),
'$noloc' => L10n::t('Clear browser location'),
'$shortnoloc' => L10n::t('clear location'),
'$title' => defaults($x, 'title', ''),
'$title' => $x['title'] ?? '',
'$placeholdertitle' => L10n::t('Set title'),
'$category' => defaults($x, 'category', ''),
'$category' => $x['category'] ?? '',
'$placeholdercategory' => Feature::isEnabled(local_user(), 'categories') ? L10n::t("Categories \x28comma-separated list\x29") : '',
'$wait' => L10n::t('Please wait'),
'$permset' => L10n::t('Permission settings'),
'$shortpermset' => L10n::t('permissions'),
'$wall' => $notes_cid ? 0 : 1,
'$posttype' => $notes_cid ? Item::PT_PERSONAL_NOTE : Item::PT_ARTICLE,
'$content' => defaults($x, 'content', ''),
'$post_id' => defaults($x, 'post_id', ''),
'$content' => $x['content'] ?? '',
'$post_id' => $x['post_id'] ?? '',
'$baseurl' => System::baseUrl(true),
'$defloc' => $x['default_location'],
'$visitor' => $x['visitor'],
@ -1527,9 +1527,9 @@ function get_responses(array $conv_responses, array $response_verbs, array $item
$ret = [];
foreach ($response_verbs as $v) {
$ret[$v] = [];
$ret[$v]['count'] = defaults($conv_responses[$v], $item['uri'], 0);
$ret[$v]['list'] = defaults($conv_responses[$v], $item['uri'] . '-l', []);
$ret[$v]['self'] = defaults($conv_responses[$v], $item['uri'] . '-self', '0');
$ret[$v]['count'] = $conv_responses[$v][$item['uri']] ?? 0;
$ret[$v]['list'] = $conv_responses[$v][$item['uri'] . '-l'] ?? [];
$ret[$v]['self'] = $conv_responses[$v][$item['uri'] . '-self'] ?? '0';
if (count($ret[$v]['list']) > MAX_LIKERS) {
$ret[$v]['list_part'] = array_slice($ret[$v]['list'], 0, MAX_LIKERS);
array_push($ret[$v]['list_part'], '<a href="#" data-toggle="modal" data-target="#' . $v . 'Modal-'

View file

@ -46,10 +46,10 @@ function notification($params)
return false;
}
$params['notify_flags'] = defaults($params, 'notify_flags', $user['notify-flags']);
$params['language'] = defaults($params, 'language' , $user['language']);
$params['to_name'] = defaults($params, 'to_name' , $user['username']);
$params['to_email'] = defaults($params, 'to_email' , $user['email']);
$params['notify_flags'] = ($params['notify_flags'] ?? '') ?: $user['notify-flags'];
$params['language'] = ($params['language'] ?? '') ?: $user['language'];
$params['to_name'] = ($params['to_name'] ?? '') ?: $user['username'];
$params['to_email'] = ($params['to_email'] ?? '') ?: $user['email'];
// from here on everything is in the recipients language
L10n::pushLang($params['language']);
@ -142,7 +142,7 @@ function notification($params)
}
if ($params['type'] == NOTIFY_COMMENT || $params['type'] == NOTIFY_TAGSELF) {
$thread = Item::selectFirstThreadForUser($params['uid'], ['ignored'], ['iid' => $parent_id]);
$thread = Item::selectFirstThreadForUser($params['uid'], ['ignored'], ['iid' => $parent_id, 'deleted' => false]);
if (DBA::isResult($thread) && $thread['ignored']) {
Logger::log('Thread ' . $parent_id . ' will be ignored', Logger::DEBUG);
L10n::popLang();
@ -161,7 +161,7 @@ function notification($params)
// if it's a post figure out who's post it is.
$item = null;
if ($params['otype'] === 'item' && $parent_id) {
$item = Item::selectFirstForUser($params['uid'], Item::ITEM_FIELDLIST, ['id' => $parent_id]);
$item = Item::selectFirstForUser($params['uid'], Item::ITEM_FIELDLIST, ['id' => $parent_id, 'deleted' => false]);
}
$item_post_type = Item::postType($item);
@ -456,17 +456,17 @@ function notification($params)
if (!isset($params['subject'])) {
Logger::warning('subject isn\'t set.', ['type' => $params['type']]);
}
$subject = defaults($params, 'subject', '');
$subject = $params['subject'] ?? '';
if (!isset($params['preamble'])) {
Logger::warning('preamble isn\'t set.', ['type' => $params['type'], 'subject' => $subject]);
}
$preamble = defaults($params, 'preamble', '');
$preamble = $params['preamble'] ?? '';
if (!isset($params['body'])) {
Logger::warning('body isn\'t set.', ['type' => $params['type'], 'subject' => $subject, 'preamble' => $preamble]);
}
$body = defaults($params, 'body', '');
$body = $params['body'] ?? '';
$show_in_notification_page = false;
}
@ -613,11 +613,11 @@ function notification($params)
$datarray['siteurl'] = $siteurl;
$datarray['type'] = $params['type'];
$datarray['parent'] = $parent_id;
$datarray['source_name'] = defaults($params, 'source_name', '');
$datarray['source_link'] = defaults($params, 'source_link', '');
$datarray['source_photo'] = defaults($params, 'source_photo', '');
$datarray['source_name'] = $params['source_name'] ?? '';
$datarray['source_link'] = $params['source_link'] ?? '';
$datarray['source_photo'] = $params['source_photo'] ?? '';
$datarray['uid'] = $params['uid'];
$datarray['username'] = defaults($params, 'to_name', '');
$datarray['username'] = $params['to_name'] ?? '';
$datarray['hsitelink'] = $hsitelink;
$datarray['tsitelink'] = $tsitelink;
$datarray['hitemlink'] = '<a href="'.$itemlink.'">'.$itemlink.'</a>';
@ -783,7 +783,7 @@ function check_item_notification($itemid, $uid, $defaulttype = "") {
$fields = ['id', 'mention', 'tag', 'parent', 'title', 'body',
'author-link', 'author-name', 'author-avatar', 'author-id',
'guid', 'parent-uri', 'uri', 'contact-id', 'network'];
$condition = ['id' => $itemid, 'gravity' => [GRAVITY_PARENT, GRAVITY_COMMENT]];
$condition = ['id' => $itemid, 'gravity' => [GRAVITY_PARENT, GRAVITY_COMMENT], 'deleted' => false];
$item = Item::selectFirstForUser($uid, $fields, $condition);
if (!DBA::isResult($item) || in_array($item['author-id'], $contacts)) {
return false;
@ -840,7 +840,7 @@ function check_item_notification($itemid, $uid, $defaulttype = "") {
// Is it a post that the user had started?
$fields = ['ignored', 'mention'];
$thread = Item::selectFirstThreadForUser($params['uid'], $fields, ['iid' => $item["parent"]]);
$thread = Item::selectFirstThreadForUser($params['uid'], $fields, ['iid' => $item["parent"], 'deleted' => false]);
if ($thread['mention'] && !$thread['ignored'] && !isset($params["type"])) {
$params["type"] = NOTIFY_COMMENT;
@ -848,7 +848,7 @@ function check_item_notification($itemid, $uid, $defaulttype = "") {
}
// And now we check for participation of one of our contacts in the thread
$condition = ['parent' => $item["parent"], 'author-id' => $contacts];
$condition = ['parent' => $item["parent"], 'author-id' => $contacts, 'deleted' => false];
if (!$thread['ignored'] && !isset($params["type"]) && Item::exists($condition)) {
$params["type"] = NOTIFY_COMMENT;

View file

@ -13,6 +13,7 @@ use Friendica\Core\PConfig;
use Friendica\Core\Protocol;
use Friendica\Core\Renderer;
use Friendica\Core\System;
use Friendica\Core\Session;
use Friendica\Database\DBA;
use Friendica\Model\Item;
use Friendica\Protocol\DFRN;
@ -41,7 +42,7 @@ function add_page_info_data(array $data, $no_photos = false)
$data["type"] = "link";
}
$data["title"] = defaults($data, "title", "");
$data["title"] = $data["title"] ?? '';
if ((($data["type"] != "link") && ($data["type"] != "video") && ($data["type"] != "photo")) || ($data["title"] == $data["url"])) {
return "";
@ -326,7 +327,7 @@ function drop_items(array $items)
{
$uid = 0;
if (!local_user() && !remote_user()) {
if (!Session::isAuthenticated()) {
return;
}
@ -362,14 +363,8 @@ function drop_item($id, $return = '')
$contact_id = 0;
// check if logged in user is either the author or owner of this item
if (!empty($_SESSION['remote'])) {
foreach ($_SESSION['remote'] as $visitor) {
if ($visitor['uid'] == $item['uid'] && $visitor['cid'] == $item['contact-id']) {
$contact_id = $visitor['cid'];
break;
}
}
if (Session::getRemoteContactID($item['uid']) == $item['contact-id']) {
$contact_id = $item['contact-id'];
}
if ((local_user() == $item['uid']) || $contact_id) {

View file

@ -122,7 +122,7 @@ function redir_private_images($a, &$item)
}
if ((local_user() == $item['uid']) && ($item['private'] == 1) && ($item['contact-id'] != $a->contact['id']) && ($item['network'] == Protocol::DFRN)) {
$img_url = 'redir?f=1&quiet=1&url=' . urlencode($mtch[1]) . '&conurl=' . urlencode($item['author-link']);
$img_url = 'redir/' . $item['contact-id'] . '?url=' . urlencode($mtch[1]);
$item['body'] = str_replace($mtch[0], '[img]' . $img_url . '[/img]', $item['body']);
}
}

View file

@ -13,6 +13,7 @@ if (!file_exists(__DIR__ . '/vendor/autoload.php')) {
require __DIR__ . '/vendor/autoload.php';
$dice = (new Dice())->addRules(include __DIR__ . '/static/dependencies.config.php');
$dice = $dice->addRule(Friendica\App\Mode::class, ['call' => [['determineRunMode', [false, $_SERVER], Dice::CHAIN_CALL]]]);
\Friendica\BaseObject::setDependencyInjection($dice);

View file

@ -4,27 +4,30 @@
/* Generic exception class
*/
if (!class_exists('OAuthException', false)) {
class OAuthException extends Exception {
// pass
}
class OAuthException extends Exception
{ }
}
class OAuthConsumer {
class OAuthConsumer
{
public $key;
public $secret;
function __construct($key, $secret, $callback_url=NULL) {
function __construct($key, $secret, $callback_url = NULL)
{
$this->key = $key;
$this->secret = $secret;
$this->callback_url = $callback_url;
}
function __toString() {
function __toString()
{
return "OAuthConsumer[key=$this->key,secret=$this->secret]";
}
}
class OAuthToken {
class OAuthToken
{
// access tokens and request tokens
public $key;
public $secret;
@ -37,7 +40,8 @@ class OAuthToken {
* key = the token
* secret = the token secret
*/
function __construct($key, $secret) {
function __construct($key, $secret)
{
$this->key = $key;
$this->secret = $secret;
}
@ -46,14 +50,16 @@ class OAuthToken {
* generates the basic string serialization of a token that a server
* would respond to request_token and access_token calls with
*/
function to_string() {
function to_string()
{
return "oauth_token=" .
OAuthUtil::urlencode_rfc3986($this->key) .
"&oauth_token_secret=" .
OAuthUtil::urlencode_rfc3986($this->secret);
}
function __toString() {
function __toString()
{
return $this->to_string();
}
}
@ -62,7 +68,8 @@ class OAuthToken {
* A class for implementing a Signature Method
* See section 9 ("Signing Requests") in the spec
*/
abstract class OAuthSignatureMethod {
abstract class OAuthSignatureMethod
{
/**
* Needs to return the name of the Signature Method (ie HMAC-SHA1)
* @return string
@ -89,7 +96,8 @@ abstract class OAuthSignatureMethod {
* @param string $signature
* @return bool
*/
public function check_signature($request, $consumer, $token, $signature) {
public function check_signature($request, $consumer, $token, $signature)
{
$built = $this->build_signature($request, $consumer, $token);
return ($built == $signature);
}
@ -102,12 +110,15 @@ abstract class OAuthSignatureMethod {
* character (ASCII code 38) even if empty.
* - Chapter 9.2 ("HMAC-SHA1")
*/
class OAuthSignatureMethod_HMAC_SHA1 extends OAuthSignatureMethod {
function get_name() {
class OAuthSignatureMethod_HMAC_SHA1 extends OAuthSignatureMethod
{
function get_name()
{
return "HMAC-SHA1";
}
public function build_signature($request, $consumer, $token) {
public function build_signature($request, $consumer, $token)
{
$base_string = $request->get_signature_base_string();
$request->base_string = $base_string;
@ -130,8 +141,10 @@ class OAuthSignatureMethod_HMAC_SHA1 extends OAuthSignatureMethod {
* over a secure channel such as HTTPS. It does not use the Signature Base String.
* - Chapter 9.4 ("PLAINTEXT")
*/
class OAuthSignatureMethod_PLAINTEXT extends OAuthSignatureMethod {
public function get_name() {
class OAuthSignatureMethod_PLAINTEXT extends OAuthSignatureMethod
{
public function get_name()
{
return "PLAINTEXT";
}
@ -144,7 +157,8 @@ class OAuthSignatureMethod_PLAINTEXT extends OAuthSignatureMethod {
* Please note that the second encoding MUST NOT happen in the SignatureMethod, as
* OAuthRequest handles this!
*/
public function build_signature($request, $consumer, $token) {
public function build_signature($request, $consumer, $token)
{
$key_parts = array(
$consumer->secret,
($token) ? $token->secret : ""
@ -166,8 +180,10 @@ class OAuthSignatureMethod_PLAINTEXT extends OAuthSignatureMethod {
* specification.
* - Chapter 9.3 ("RSA-SHA1")
*/
abstract class OAuthSignatureMethod_RSA_SHA1 extends OAuthSignatureMethod {
public function get_name() {
abstract class OAuthSignatureMethod_RSA_SHA1 extends OAuthSignatureMethod
{
public function get_name()
{
return "RSA-SHA1";
}
@ -185,7 +201,8 @@ abstract class OAuthSignatureMethod_RSA_SHA1 extends OAuthSignatureMethod {
// Either way should return a string representation of the certificate
protected abstract function fetch_private_cert(&$request);
public function build_signature($request, $consumer, $token) {
public function build_signature($request, $consumer, $token)
{
$base_string = $request->get_signature_base_string();
$request->base_string = $base_string;
@ -204,7 +221,8 @@ abstract class OAuthSignatureMethod_RSA_SHA1 extends OAuthSignatureMethod {
return base64_encode($signature);
}
public function check_signature($request, $consumer, $token, $signature) {
public function check_signature($request, $consumer, $token, $signature)
{
$decoded_sig = base64_decode($signature);
$base_string = $request->get_signature_base_string();
@ -225,7 +243,8 @@ abstract class OAuthSignatureMethod_RSA_SHA1 extends OAuthSignatureMethod {
}
}
class OAuthRequest {
class OAuthRequest
{
private $parameters;
private $http_method;
private $http_url;
@ -234,7 +253,8 @@ class OAuthRequest {
public static $version = '1.0';
public static $POST_INPUT = 'php://input';
function __construct($http_method, $http_url, $parameters=NULL) {
function __construct($http_method, $http_url, $parameters = NULL)
{
@$parameters or $parameters = array();
$parameters = array_merge(OAuthUtil::parse_parameters(parse_url($http_url, PHP_URL_QUERY)), $parameters);
$this->parameters = $parameters;
@ -246,7 +266,8 @@ class OAuthRequest {
/**
* attempt to build up a request from what was passed to the server
*/
public static function from_request($http_method=NULL, $http_url=NULL, $parameters=NULL) {
public static function from_request($http_method = NULL, $http_url = NULL, $parameters = NULL)
{
$scheme = (!isset($_SERVER['HTTPS']) || $_SERVER['HTTPS'] != "on")
? 'http'
: 'https';
@ -270,9 +291,12 @@ class OAuthRequest {
// It's a POST request of the proper content-type, so parse POST
// parameters and add those overriding any duplicates from GET
if ($http_method == "POST"
&& @strstr($request_headers["Content-Type"],
"application/x-www-form-urlencoded")
if (
$http_method == "POST"
&& @strstr(
$request_headers["Content-Type"],
"application/x-www-form-urlencoded"
)
) {
$post_data = OAuthUtil::parse_parameters(
file_get_contents(self::$POST_INPUT)
@ -288,7 +312,6 @@ class OAuthRequest {
);
$parameters = array_merge($parameters, $header_parameters);
}
}
// fix for friendica redirect system
@ -301,12 +324,15 @@ class OAuthRequest {
/**
* pretty much a helper function to set up the request
*/
public static function from_consumer_and_token($consumer, $token, $http_method, $http_url, $parameters=NULL) {
public static function from_consumer_and_token($consumer, $token, $http_method, $http_url, $parameters = NULL)
{
@$parameters or $parameters = array();
$defaults = array("oauth_version" => OAuthRequest::$version,
$defaults = array(
"oauth_version" => OAuthRequest::$version,
"oauth_nonce" => OAuthRequest::generate_nonce(),
"oauth_timestamp" => OAuthRequest::generate_timestamp(),
"oauth_consumer_key" => $consumer->key);
"oauth_consumer_key" => $consumer->key
);
if ($token)
$defaults['oauth_token'] = $token->key;
@ -315,7 +341,8 @@ class OAuthRequest {
return new OAuthRequest($http_method, $http_url, $parameters);
}
public function set_parameter($name, $value, $allow_duplicates = true) {
public function set_parameter($name, $value, $allow_duplicates = true)
{
if ($allow_duplicates && isset($this->parameters[$name])) {
// We have already added parameter(s) with this name, so add to the list
if (is_scalar($this->parameters[$name])) {
@ -330,15 +357,18 @@ class OAuthRequest {
}
}
public function get_parameter($name) {
public function get_parameter($name)
{
return isset($this->parameters[$name]) ? $this->parameters[$name] : null;
}
public function get_parameters() {
public function get_parameters()
{
return $this->parameters;
}
public function unset_parameter($name) {
public function unset_parameter($name)
{
unset($this->parameters[$name]);
}
@ -346,7 +376,8 @@ class OAuthRequest {
* The request parameters, sorted and concatenated into a normalized string.
* @return string
*/
public function get_signable_parameters() {
public function get_signable_parameters()
{
// Grab all parameters
$params = $this->parameters;
@ -366,7 +397,8 @@ class OAuthRequest {
* and the parameters (normalized), each urlencoded
* and the concated with &.
*/
public function get_signature_base_string() {
public function get_signature_base_string()
{
$parts = array(
$this->get_normalized_http_method(),
$this->get_normalized_http_url(),
@ -381,7 +413,8 @@ class OAuthRequest {
/**
* just uppercases the http method
*/
public function get_normalized_http_method() {
public function get_normalized_http_method()
{
return strtoupper($this->http_method);
}
@ -389,7 +422,8 @@ class OAuthRequest {
* parses the url and rebuilds it to be
* scheme://host/path
*/
public function get_normalized_http_url() {
public function get_normalized_http_url()
{
$parts = parse_url($this->http_url);
$port = @$parts['port'];
@ -400,7 +434,8 @@ class OAuthRequest {
$port or $port = ($scheme == 'https') ? '443' : '80';
if (($scheme == 'https' && $port != '443')
|| ($scheme == 'http' && $port != '80')) {
|| ($scheme == 'http' && $port != '80')
) {
$host = "$host:$port";
}
return "$scheme://$host$path";
@ -409,7 +444,8 @@ class OAuthRequest {
/**
* builds a url usable for a GET request
*/
public function to_url() {
public function to_url()
{
$post_data = $this->to_postdata();
$out = $this->get_normalized_http_url();
if ($post_data) {
@ -421,9 +457,10 @@ class OAuthRequest {
/**
* builds the data one would send in a POST request
*/
public function to_postdata($raw = false) {
public function to_postdata($raw = false)
{
if ($raw)
return($this->parameters);
return $this->parameters;
else
return OAuthUtil::build_http_query($this->parameters);
}
@ -431,7 +468,8 @@ class OAuthRequest {
/**
* builds the Authorization: header
*/
public function to_header($realm=null) {
public function to_header($realm = null)
{
$first = true;
if ($realm) {
$out = 'Authorization: OAuth realm="' . OAuthUtil::urlencode_rfc3986($realm) . '"';
@ -439,7 +477,6 @@ class OAuthRequest {
} else
$out = 'Authorization: OAuth';
$total = array();
foreach ($this->parameters as $k => $v) {
if (substr($k, 0, 5) != "oauth") continue;
if (is_array($v)) {
@ -455,12 +492,14 @@ class OAuthRequest {
return $out;
}
public function __toString() {
public function __toString()
{
return $this->to_url();
}
public function sign_request($signature_method, $consumer, $token) {
public function sign_request($signature_method, $consumer, $token)
{
$this->set_parameter(
"oauth_signature_method",
$signature_method->get_name(),
@ -470,7 +509,8 @@ class OAuthRequest {
$this->set_parameter("oauth_signature", $signature, false);
}
public function build_signature($signature_method, $consumer, $token) {
public function build_signature($signature_method, $consumer, $token)
{
$signature = $signature_method->build_signature($this, $consumer, $token);
return $signature;
}
@ -478,33 +518,35 @@ class OAuthRequest {
/**
* util function: current timestamp
*/
private static function generate_timestamp() {
private static function generate_timestamp()
{
return time();
}
/**
* util function: current nonce
*/
private static function generate_nonce() {
$mt = microtime();
$rand = mt_rand();
return md5($mt . $rand); // md5s look nicer than numbers
private static function generate_nonce()
{
return Friendica\Util\Strings::getRandomHex(32);
}
}
class OAuthServer {
class OAuthServer
{
protected $timestamp_threshold = 300; // in seconds, five minutes
protected $version = '1.0'; // hi blaine
protected $signature_methods = array();
protected $data_store;
function __construct($data_store) {
function __construct($data_store)
{
$this->data_store = $data_store;
}
public function add_signature_method($signature_method) {
public function add_signature_method($signature_method)
{
$this->signature_methods[$signature_method->get_name()] =
$signature_method;
}
@ -515,7 +557,8 @@ class OAuthServer {
* process a request_token request
* returns the request token on success
*/
public function fetch_request_token(&$request) {
public function fetch_request_token(&$request)
{
$this->get_version($request);
$consumer = $this->get_consumer($request);
@ -536,7 +579,8 @@ class OAuthServer {
* process an access_token request
* returns the access token on success
*/
public function fetch_access_token(&$request) {
public function fetch_access_token(&$request)
{
$this->get_version($request);
$consumer = $this->get_consumer($request);
@ -556,19 +600,21 @@ class OAuthServer {
/**
* verify an api call, checks all the parameters
*/
public function verify_request(&$request) {
public function verify_request(&$request)
{
$this->get_version($request);
$consumer = $this->get_consumer($request);
$token = $this->get_token($request, $consumer, "access");
$this->check_signature($request, $consumer, $token);
return array($consumer, $token);
return [$consumer, $token];
}
// Internals from here
/**
* version 1
*/
private function get_version(&$request) {
private function get_version(&$request)
{
$version = $request->get_parameter("oauth_version");
if (!$version) {
// Service Providers MUST assume the protocol version to be 1.0 if this parameter is not present.
@ -584,7 +630,8 @@ class OAuthServer {
/**
* figure out the signature with some defaults
*/
private function get_signature_method(&$request) {
private function get_signature_method(&$request)
{
$signature_method =
@$request->get_parameter("oauth_signature_method");
@ -594,8 +641,10 @@ class OAuthServer {
throw new OAuthException('No signature method parameter. This parameter is required');
}
if (!in_array($signature_method,
array_keys($this->signature_methods))) {
if (!in_array(
$signature_method,
array_keys($this->signature_methods)
)) {
throw new OAuthException(
"Signature method '$signature_method' not supported " .
"try one of the following: " .
@ -608,7 +657,8 @@ class OAuthServer {
/**
* try to find the consumer for the provided request's consumer key
*/
private function get_consumer(&$request) {
private function get_consumer(&$request)
{
$consumer_key = @$request->get_parameter("oauth_consumer_key");
if (!$consumer_key) {
throw new OAuthException("Invalid consumer key");
@ -625,10 +675,13 @@ class OAuthServer {
/**
* try to find the token for the provided request's token key
*/
private function get_token(&$request, $consumer, $token_type="access") {
private function get_token(&$request, $consumer, $token_type = "access")
{
$token_field = @$request->get_parameter('oauth_token');
$token = $this->data_store->lookup_token(
$consumer, $token_type, $token_field
$consumer,
$token_type,
$token_field
);
if (!$token) {
throw new OAuthException("Invalid $token_type token: $token_field");
@ -640,7 +693,8 @@ class OAuthServer {
* all-in-one function to check the signature on a request
* should guess the signature method appropriately
*/
private function check_signature(&$request, $consumer, $token) {
private function check_signature(&$request, $consumer, $token)
{
// this should probably be in a different method
$timestamp = @$request->get_parameter('oauth_timestamp');
$nonce = @$request->get_parameter('oauth_nonce');
@ -667,7 +721,8 @@ class OAuthServer {
/**
* check that the timestamp is new enough
*/
private function check_timestamp($timestamp) {
private function check_timestamp($timestamp)
{
if (!$timestamp)
throw new OAuthException(
'Missing timestamp parameter. The parameter is required'
@ -685,7 +740,8 @@ class OAuthServer {
/**
* check that the nonce is not repeated
*/
private function check_nonce($consumer, $token, $nonce, $timestamp) {
private function check_nonce($consumer, $token, $nonce, $timestamp)
{
if (!$nonce)
throw new OAuthException(
'Missing nonce parameter. The parameter is required'
@ -702,39 +758,45 @@ class OAuthServer {
throw new OAuthException("Nonce already used: $nonce");
}
}
}
class OAuthDataStore {
function lookup_consumer($consumer_key) {
class OAuthDataStore
{
function lookup_consumer($consumer_key)
{
// implement me
}
function lookup_token($consumer, $token_type, $token) {
function lookup_token($consumer, $token_type, $token)
{
// implement me
}
function lookup_nonce($consumer, $token, $nonce, $timestamp) {
function lookup_nonce($consumer, $token, $nonce, $timestamp)
{
// implement me
}
function new_request_token($consumer, $callback = null) {
function new_request_token($consumer, $callback = null)
{
// return a new token attached to this consumer
}
function new_access_token($token, $consumer, $verifier = null) {
function new_access_token($token, $consumer, $verifier = null)
{
// return a new access token attached to this consumer
// for the user associated with this token if the request token
// is authorized
// should also invalidate the request token
}
}
class OAuthUtil {
public static function urlencode_rfc3986($input) {
class OAuthUtil
{
public static function urlencode_rfc3986($input)
{
if (is_array($input)) {
return array_map(array('OAuthUtil', 'urlencode_rfc3986'), $input);
return array_map(['OAuthUtil', 'urlencode_rfc3986'], $input);
} else if (is_scalar($input)) {
return str_replace(
'+',
@ -750,17 +812,19 @@ class OAuthUtil {
// This decode function isn't taking into consideration the above
// modifications to the encoding process. However, this method doesn't
// seem to be used anywhere so leaving it as is.
public static function urldecode_rfc3986($string) {
public static function urldecode_rfc3986($string)
{
return urldecode($string);
}
// Utility function for turning the Authorization: header into
// parameters, has to do some unescaping
// Can filter out any non-oauth parameters if needed (default behaviour)
public static function split_header($header, $only_allow_oauth_parameters = true) {
public static function split_header($header, $only_allow_oauth_parameters = true)
{
$pattern = '/(([-_a-z]*)=("([^"]*)"|([^,]*)),?)/';
$offset = 0;
$params = array();
$params = [];
while (preg_match($pattern, $header, $matches, PREG_OFFSET_CAPTURE, $offset) > 0) {
$match = $matches[0];
$header_name = $matches[2][0];
@ -779,7 +843,8 @@ class OAuthUtil {
}
// helper to try to sort out headers for people who aren't running apache
public static function get_headers() {
public static function get_headers()
{
if (function_exists('apache_request_headers')) {
// we need this to get the actual Authorization: header
// because apache tends to tell us it doesn't exist
@ -789,8 +854,8 @@ class OAuthUtil {
// we always want the keys to be Cased-Like-This and arh()
// returns the headers in the same case as they are in the
// request
$out = array();
foreach( $headers AS $key => $value ) {
$out = [];
foreach ($headers as $key => $value) {
$key = str_replace(
" ",
"-",
@ -801,7 +866,7 @@ class OAuthUtil {
} else {
// otherwise we don't have apache and are just going to have to hope
// that $_SERVER actually contains what we need
$out = array();
$out = [];
if (isset($_SERVER['CONTENT_TYPE']))
$out['Content-Type'] = $_SERVER['CONTENT_TYPE'];
if (isset($_ENV['CONTENT_TYPE']))
@ -827,12 +892,13 @@ class OAuthUtil {
// This function takes a input like a=b&a=c&d=e and returns the parsed
// parameters like this
// array('a' => array('b','c'), 'd' => 'e')
public static function parse_parameters( $input ) {
public static function parse_parameters($input)
{
if (!isset($input) || !$input) return array();
$pairs = explode('&', $input);
$parsed_parameters = array();
$parsed_parameters = [];
foreach ($pairs as $pair) {
$split = explode('=', $pair, 2);
$parameter = OAuthUtil::urldecode_rfc3986($split[0]);
@ -845,7 +911,7 @@ class OAuthUtil {
if (is_scalar($parsed_parameters[$parameter])) {
// This is the first duplicate, so transform scalar (string) into an array
// so we can add the duplicates
$parsed_parameters[$parameter] = array($parsed_parameters[$parameter]);
$parsed_parameters[$parameter] = [$parsed_parameters[$parameter]];
}
$parsed_parameters[$parameter][] = $value;
@ -856,7 +922,8 @@ class OAuthUtil {
return $parsed_parameters;
}
public static function build_http_query($params) {
public static function build_http_query($params)
{
if (!$params) return '';
// Urlencode both keys and values
@ -868,7 +935,7 @@ class OAuthUtil {
// Ref: Spec: 9.1.1 (1)
uksort($params, 'strcmp');
$pairs = array();
$pairs = [];
foreach ($params as $parameter => $value) {
if (is_array($value)) {
// If two or more parameters share the same name, they are sorted by their value
@ -886,5 +953,3 @@ class OAuthUtil {
return implode('&', $pairs);
}
}
?>

View file

@ -1,316 +0,0 @@
<?php
/* ACL selector json backend */
use Friendica\App;
use Friendica\Content\Widget;
use Friendica\Core\ACL;
use Friendica\Core\Hook;
use Friendica\Core\Logger;
use Friendica\Core\Protocol;
use Friendica\Database\DBA;
use Friendica\Model\Contact;
use Friendica\Model\Item;
use Friendica\Util\Proxy as ProxyUtils;
use Friendica\Util\Strings;
function acl_content(App $a)
{
if (!local_user()) {
return '';
}
$start = defaults($_REQUEST, 'start' , 0);
$count = defaults($_REQUEST, 'count' , 100);
$search = defaults($_REQUEST, 'search' , '');
$type = defaults($_REQUEST, 'type' , '');
$conv_id = defaults($_REQUEST, 'conversation', null);
// For use with jquery.textcomplete for private mail completion
if (!empty($_REQUEST['query'])) {
if (!$type) {
$type = 'm';
}
$search = $_REQUEST['query'];
}
Logger::info('ACL {action} - {subaction}', ['module' => 'acl', 'action' => 'content', 'subaction' => 'search', 'search' => $search, 'type' => $type, 'conversation' => $conv_id]);
if ($search != '') {
$sql_extra = "AND `name` LIKE '%%" . DBA::escape($search) . "%%'";
$sql_extra2 = "AND (`attag` LIKE '%%" . DBA::escape($search) . "%%' OR `name` LIKE '%%" . DBA::escape($search) . "%%' OR `nick` LIKE '%%" . DBA::escape($search) . "%%')";
} else {
/// @TODO Avoid these needless else blocks by putting variable-initialization atop of if()
$sql_extra = $sql_extra2 = '';
}
// count groups and contacts
$group_count = 0;
if ($type == '' || $type == 'g') {
$r = q("SELECT COUNT(*) AS g FROM `group` WHERE NOT `deleted` AND `uid` = %d $sql_extra",
intval(local_user())
);
$group_count = (int) $r[0]['g'];
}
$sql_extra2 .= ' ' . Widget::unavailableNetworks();
$contact_count = 0;
if ($type == '' || $type == 'c') {
// autocomplete for editor mentions
$r = q("SELECT COUNT(*) AS c FROM `contact`
WHERE `uid` = %d AND NOT `self` AND NOT `deleted`
AND NOT `blocked` AND NOT `pending` AND NOT `archive`
AND `notify` != '' $sql_extra2",
intval(local_user())
);
$contact_count = (int) $r[0]['c'];
} elseif ($type == 'f') {
// autocomplete for editor mentions of forums
$r = q("SELECT COUNT(*) AS c FROM `contact`
WHERE `uid` = %d AND NOT `self` AND NOT `deleted`
AND NOT `blocked` AND NOT `pending` AND NOT `archive`
AND (`forum` OR `prv`)
AND `notify` != '' $sql_extra2",
intval(local_user())
);
$contact_count = (int) $r[0]['c'];
} elseif ($type == 'm') {
// autocomplete for Private Messages
$r = q("SELECT COUNT(*) AS c FROM `contact`
WHERE `uid` = %d AND NOT `self` AND NOT `deleted`
AND NOT `blocked` AND NOT `pending` AND NOT `archive`
AND `network` IN ('%s', '%s', '%s') $sql_extra2",
intval(local_user()),
DBA::escape(Protocol::ACTIVITYPUB),
DBA::escape(Protocol::DFRN),
DBA::escape(Protocol::DIASPORA)
);
$contact_count = (int) $r[0]['c'];
} elseif ($type == 'a') {
// autocomplete for Contacts
$r = q("SELECT COUNT(*) AS c FROM `contact`
WHERE `uid` = %d AND NOT `self`
AND NOT `pending` AND NOT `deleted` $sql_extra2",
intval(local_user())
);
$contact_count = (int) $r[0]['c'];
}
$tot = $group_count + $contact_count;
$groups = [];
$contacts = [];
if ($type == '' || $type == 'g') {
/// @todo We should cache this query.
// This can be done when we can delete cache entries via wildcard
$r = q("SELECT `group`.`id`, `group`.`name`, GROUP_CONCAT(DISTINCT `group_member`.`contact-id` SEPARATOR ',') AS uids
FROM `group`
INNER JOIN `group_member` ON `group_member`.`gid`=`group`.`id`
WHERE NOT `group`.`deleted` AND `group`.`uid` = %d
$sql_extra
GROUP BY `group`.`name`, `group`.`id`
ORDER BY `group`.`name`
LIMIT %d,%d",
intval(local_user()),
intval($start),
intval($count)
);
foreach ($r as $g) {
$groups[] = [
'type' => 'g',
'photo' => 'images/twopeople.png',
'name' => htmlspecialchars($g['name']),
'id' => intval($g['id']),
'uids' => array_map('intval', explode(',', $g['uids'])),
'link' => '',
'forum' => '0'
];
}
if ((count($groups) > 0) && ($search == '')) {
$groups[] = ['separator' => true];
}
}
$r = [];
if ($type == '') {
$r = q("SELECT `id`, `name`, `nick`, `micro`, `network`, `url`, `attag`, `addr`, `forum`, `prv`, (`prv` OR `forum`) AS `frm` FROM `contact`
WHERE `uid` = %d AND NOT `self` AND NOT `deleted` AND NOT `blocked` AND NOT `pending` AND NOT `archive` AND `notify` != ''
AND NOT (`network` IN ('%s', '%s'))
$sql_extra2
ORDER BY `name` ASC ",
intval(local_user()),
DBA::escape(Protocol::OSTATUS),
DBA::escape(Protocol::STATUSNET)
);
} elseif ($type == 'c') {
$r = q("SELECT `id`, `name`, `nick`, `micro`, `network`, `url`, `attag`, `addr`, `forum`, `prv` FROM `contact`
WHERE `uid` = %d AND NOT `self` AND NOT `deleted` AND NOT `blocked` AND NOT `pending` AND NOT `archive` AND `notify` != ''
AND NOT (`network` IN ('%s'))
$sql_extra2
ORDER BY `name` ASC ",
intval(local_user()),
DBA::escape(Protocol::STATUSNET)
);
} elseif ($type == 'f') {
$r = q("SELECT `id`, `name`, `nick`, `micro`, `network`, `url`, `attag`, `addr`, `forum`, `prv` FROM `contact`
WHERE `uid` = %d AND NOT `self` AND NOT `deleted` AND NOT `blocked` AND NOT `pending` AND NOT `archive` AND `notify` != ''
AND NOT (`network` IN ('%s'))
AND (`forum` OR `prv`)
$sql_extra2
ORDER BY `name` ASC ",
intval(local_user()),
DBA::escape(Protocol::STATUSNET)
);
} elseif ($type == 'm') {
$r = q("SELECT `id`, `name`, `nick`, `micro`, `network`, `url`, `attag`, `addr` FROM `contact`
WHERE `uid` = %d AND NOT `self` AND NOT `deleted` AND NOT `blocked` AND NOT `pending` AND NOT `archive`
AND `network` IN ('%s', '%s', '%s')
$sql_extra2
ORDER BY `name` ASC ",
intval(local_user()),
DBA::escape(Protocol::ACTIVITYPUB),
DBA::escape(Protocol::DFRN),
DBA::escape(Protocol::DIASPORA)
);
} elseif ($type == 'a') {
$r = q("SELECT `id`, `name`, `nick`, `micro`, `network`, `url`, `attag`, `addr`, `forum`, `prv` FROM `contact`
WHERE `uid` = %d AND NOT `deleted` AND NOT `pending` AND NOT `archive`
$sql_extra2
ORDER BY `name` ASC ",
intval(local_user())
);
} elseif ($type == 'x') {
// autocomplete for global contact search (e.g. navbar search)
$search = Strings::escapeTags(trim($_REQUEST['search']));
$mode = $_REQUEST['smode'];
$r = ACL::contactAutocomplete($search, $mode);
$contacts = [];
foreach ($r as $g) {
$contacts[] = [
'photo' => ProxyUtils::proxifyUrl($g['photo'], false, ProxyUtils::SIZE_MICRO),
'name' => htmlspecialchars($g['name']),
'nick' => defaults($g, 'addr', $g['url']),
'network' => $g['network'],
'link' => $g['url'],
'forum' => !empty($g['community']) ? 1 : 0,
];
}
$o = [
'start' => $start,
'count' => $count,
'items' => $contacts,
];
echo json_encode($o);
exit;
}
if (DBA::isResult($r)) {
$forums = [];
foreach ($r as $g) {
$entry = [
'type' => 'c',
'photo' => ProxyUtils::proxifyUrl($g['micro'], false, ProxyUtils::SIZE_MICRO),
'name' => htmlspecialchars($g['name']),
'id' => intval($g['id']),
'network' => $g['network'],
'link' => $g['url'],
'nick' => htmlentities(defaults($g, 'attag', $g['nick'])),
'addr' => htmlentities(defaults($g, 'addr', $g['url'])),
'forum' => !empty($g['forum']) || !empty($g['prv']) ? 1 : 0,
];
if ($entry['forum']) {
$forums[] = $entry;
} else {
$contacts[] = $entry;
}
}
if (count($forums) > 0) {
if ($search == '') {
$forums[] = ['separator' => true];
}
$contacts = array_merge($forums, $contacts);
}
}
$items = array_merge($groups, $contacts);
if ($conv_id) {
// In multi threaded posts the conv_id is not the parent of the whole thread
$parent_item = Item::selectFirst(['parent'], ['id' => $conv_id]);
if (DBA::isResult($parent_item)) {
$conv_id = $parent_item['parent'];
}
/*
* if $conv_id is set, get unknown contacts in thread
* but first get known contacts url to filter them out
*/
$known_contacts = array_map(function ($i) {
return $i['link'];
}, $contacts);
$unknown_contacts = [];
$condition = ["`parent` = ?", $conv_id];
$params = ['order' => ['author-name' => true]];
$authors = Item::selectForUser(local_user(), ['author-link'], $condition, $params);
$item_authors = [];
while ($author = Item::fetch($authors)) {
$item_authors[$author['author-link']] = $author['author-link'];
}
DBA::close($authors);
foreach ($item_authors as $author) {
if (in_array($author, $known_contacts)) {
continue;
}
$contact = Contact::getDetailsByURL($author);
if (count($contact) > 0) {
$unknown_contacts[] = [
'type' => 'c',
'photo' => ProxyUtils::proxifyUrl($contact['micro'], false, ProxyUtils::SIZE_MICRO),
'name' => htmlspecialchars($contact['name']),
'id' => intval($contact['cid']),
'network' => $contact['network'],
'link' => $contact['url'],
'nick' => htmlentities(defaults($contact, 'nick', $contact['addr'])),
'addr' => htmlentities(defaults($contact, 'addr', $contact['url'])),
'forum' => $contact['forum']
];
}
}
$items = array_merge($items, $unknown_contacts);
$tot += count($unknown_contacts);
}
$results = [
'tot' => $tot,
'start' => $start,
'count' => $count,
'groups' => $groups,
'contacts' => $contacts,
'items' => $items,
'type' => $type,
'search' => $search,
];
Hook::callAll('acl_lookup_end', $results);
$o = [
'tot' => $results['tot'],
'start' => $results['start'],
'count' => $results['count'],
'items' => $results['items'],
];
echo json_encode($o);
exit;
}

View file

@ -2,6 +2,7 @@
/**
* @file mod/api.php
*/
use Friendica\App;
use Friendica\Core\Config;
use Friendica\Core\L10n;
@ -9,7 +10,7 @@ use Friendica\Core\Renderer;
use Friendica\Database\DBA;
use Friendica\Module\Login;
require_once 'include/api.php';
require_once __DIR__ . '/../include/api.php';
function oauth_get_client(OAuthRequest $request)
{

View file

@ -14,6 +14,7 @@ use Friendica\Core\Config;
use Friendica\Core\L10n;
use Friendica\Core\Renderer;
use Friendica\Core\System;
use Friendica\Core\Session;
use Friendica\Database\DBA;
use Friendica\Model\Contact;
use Friendica\Model\Event;
@ -26,11 +27,7 @@ use Friendica\Util\Temporal;
function cal_init(App $a)
{
if ($a->argc > 1) {
DFRN::autoRedir($a, $a->argv[1]);
}
if (Config::get('system', 'block_public') && !local_user() && !remote_user()) {
if (Config::get('system', 'block_public') && !Session::isAuthenticated()) {
throw new \Friendica\Network\HTTPException\ForbiddenException(L10n::t('Access denied.'));
}
@ -113,18 +110,11 @@ function cal_content(App $a)
$owner_uid = intval($a->data['user']['uid']);
$nick = $a->data['user']['nickname'];
if (!empty($_SESSION['remote']) && is_array($_SESSION['remote'])) {
foreach ($_SESSION['remote'] as $v) {
if ($v['uid'] == $a->profile['profile_uid']) {
$contact_id = $v['cid'];
break;
}
}
if (!empty(Session::getRemoteContactID($a->profile['profile_uid']))) {
$contact_id = Session::getRemoteContactID($a->profile['profile_uid']);
}
$groups = [];
if ($contact_id) {
$groups = Group::getIdsByContactId($contact_id);
$r = q("SELECT * FROM `contact` WHERE `id` = %d AND `uid` = %d LIMIT 1",
intval($contact_id),
intval($a->profile['profile_uid'])
@ -142,7 +132,7 @@ function cal_content(App $a)
}
// get the permissions
$sql_perms = Item::getPermissionsSQLByUserId($owner_uid, $remote_contact, $groups);
$sql_perms = Item::getPermissionsSQLByUserId($owner_uid);
// we only want to have the events of the profile owner
$sql_extra = " AND `event`.`cid` = 0 " . $sql_perms;
@ -210,7 +200,7 @@ function cal_content(App $a)
// put the event parametes in an array so we can better transmit them
$event_params = [
'event_id' => intval(defaults($_GET, 'id', 0)),
'event_id' => intval($_GET['id'] ?? 0),
'start' => $start,
'finish' => $finish,
'adjust_start' => $adjust_start,

View file

@ -118,7 +118,7 @@ function common_content(App $a)
$entry = [
'url' => Model\Contact::magicLink($common_friend['url']),
'itemurl' => defaults($contact_details, 'addr', $common_friend['url']),
'itemurl' => ($contact_details['addr'] ?? '') ?: $common_friend['url'],
'name' => $contact_details['name'],
'thumb' => ProxyUtils::proxifyUrl($contact_details['thumb'], false, ProxyUtils::SIZE_THUMB),
'img_hover' => $contact_details['name'],

View file

@ -17,19 +17,11 @@ use Friendica\Database\DBA;
use Friendica\Model\Item;
use Friendica\Model\User;
function community_init(App $a)
{
if (!local_user()) {
unset($_SESSION['theme']);
unset($_SESSION['mobile-theme']);
}
}
function community_content(App $a, $update = 0)
{
$o = '';
if (Config::get('system', 'block_public') && !local_user() && !remote_user()) {
if (Config::get('system', 'block_public') && !Session::isAuthenticated()) {
notice(L10n::t('Public access denied.') . EOL);
return;
}
@ -227,6 +219,7 @@ function community_getitems($start, $itemspage, $content, $accounttype)
$values = [$start, $itemspage];
}
/// @todo Use "unsearchable" here as well (instead of "hidewall")
$r = DBA::p("SELECT `item`.`uri`, `author`.`url` AS `author-link` FROM `thread`
STRAIGHT_JOIN `user` ON `user`.`uid` = `thread`.`uid` AND NOT `user`.`hidewall`
STRAIGHT_JOIN `item` ON `item`.`id` = `thread`.`iid`
@ -237,9 +230,9 @@ function community_getitems($start, $itemspage, $content, $accounttype)
return DBA::toArray($r);
} elseif ($content == 'global') {
if (!is_null($accounttype)) {
$condition = ["`uid` = ? AND `owner`.`contact-type` = ?", 0, $accounttype];
$condition = ["`uid` = ? AND NOT `author`.`unsearchable` AND NOT `owner`.`unsearchable` AND `owner`.`contact-type` = ?", 0, $accounttype];
} else {
$condition = ['uid' => 0];
$condition = ["`uid` = ? AND NOT `author`.`unsearchable` AND NOT `owner`.`unsearchable`", 0];
}
$r = Item::selectThreadForUser(0, ['uri'], $condition, ['order' => ['commented' => true], 'limit' => [$start, $itemspage]]);

View file

@ -38,17 +38,17 @@ function crepair_post(App $a)
return;
}
$name = defaults($_POST, 'name' , $contact['name']);
$nick = defaults($_POST, 'nick' , '');
$url = defaults($_POST, 'url' , '');
$alias = defaults($_POST, 'alias' , '');
$request = defaults($_POST, 'request' , '');
$confirm = defaults($_POST, 'confirm' , '');
$notify = defaults($_POST, 'notify' , '');
$poll = defaults($_POST, 'poll' , '');
$attag = defaults($_POST, 'attag' , '');
$photo = defaults($_POST, 'photo' , '');
$remote_self = defaults($_POST, 'remote_self', false);
$name = ($_POST['name'] ?? '') ?: $contact['name'];
$nick = $_POST['nick'] ?? '';
$url = $_POST['url'] ?? '';
$alias = $_POST['alias'] ?? '';
$request = $_POST['request'] ?? '';
$confirm = $_POST['confirm'] ?? '';
$notify = $_POST['notify'] ?? '';
$poll = $_POST['poll'] ?? '';
$attag = $_POST['attag'] ?? '';
$photo = $_POST['photo'] ?? '';
$remote_self = $_POST['remote_self'] ?? false;
$nurl = Strings::normaliseLink($url);
$r = DBA::update(

View file

@ -1,191 +0,0 @@
<?php
/**
* @file mod/delegate.php
*/
use Friendica\App;
use Friendica\BaseModule;
use Friendica\Core\L10n;
use Friendica\Core\Protocol;
use Friendica\Core\Renderer;
use Friendica\Core\System;
use Friendica\Database\DBA;
use Friendica\Model\User;
use Friendica\Util\Strings;
require_once 'mod/settings.php';
function delegate_init(App $a)
{
settings_init($a);
}
function delegate_post(App $a)
{
if (!local_user()) {
return;
}
if (count($a->user) && !empty($a->user['uid']) && $a->user['uid'] != local_user()) {
notice(L10n::t('Permission denied.') . EOL);
return;
}
BaseModule::checkFormSecurityTokenRedirectOnError('/delegate', 'delegate');
$parent_uid = defaults($_POST, 'parent_user', 0);
$parent_password = defaults($_POST, 'parent_password', '');
if ($parent_uid != 0) {
$user = DBA::selectFirst('user', ['nickname'], ['uid' => $parent_uid]);
if (!DBA::isResult($user)) {
notice(L10n::t('Parent user not found.') . EOL);
return;
}
$success = User::authenticate($user['nickname'], trim($parent_password));
if (!$success) {
notice(L10n::t('Permission denied.') . EOL);
return;
}
}
DBA::update('user', ['parent-uid' => $parent_uid], ['uid' => local_user()]);
}
function delegate_content(App $a)
{
if (!local_user()) {
notice(L10n::t('Permission denied.') . EOL);
return;
}
if ($a->argc > 2 && $a->argv[1] === 'add' && intval($a->argv[2])) {
// delegated admins can view but not change delegation permissions
if (!empty($_SESSION['submanage'])) {
$a->internalRedirect('delegate');
}
$user_id = $a->argv[2];
$user = DBA::selectFirst('user', ['nickname'], ['uid' => $user_id]);
if (DBA::isResult($user)) {
$condition = [
'uid' => local_user(),
'nurl' => Strings::normaliseLink(System::baseUrl() . '/profile/' . $user['nickname'])
];
if (DBA::exists('contact', $condition)) {
DBA::insert('manage', ['uid' => $user_id, 'mid' => local_user()]);
}
}
$a->internalRedirect('delegate');
}
if ($a->argc > 2 && $a->argv[1] === 'remove' && intval($a->argv[2])) {
// delegated admins can view but not change delegation permissions
if (!empty($_SESSION['submanage'])) {
$a->internalRedirect('delegate');
}
DBA::delete('manage', ['uid' => $a->argv[2], 'mid' => local_user()]);
$a->internalRedirect('delegate');
}
// find everybody that currently has delegated management to this account/page
$delegates = [];
$r = q("SELECT * FROM `user` WHERE `uid` IN (SELECT `uid` FROM `manage` WHERE `mid` = %d)",
intval(local_user())
);
if (DBA::isResult($r)) {
$delegates = $r;
}
$uids = [];
foreach ($delegates as $rr) {
$uids[] = $rr['uid'];
}
// find every contact who might be a candidate for delegation
$potentials = [];
$r = q("SELECT `nurl`
FROM `contact`
WHERE `self` = 0
AND SUBSTRING_INDEX(`nurl`, '/', 3) = '%s'
AND `uid` = %d
AND `network` = '%s' ",
DBA::escape(Strings::normaliseLink(System::baseUrl())),
intval(local_user()),
DBA::escape(Protocol::DFRN)
);
if (DBA::isResult($r)) {
$nicknames = [];
foreach ($r as $rr) {
$nicknames[] = "'" . DBA::escape(basename($rr['nurl'])) . "'";
}
$nicks = implode(',', $nicknames);
// get user records for all potential page delegates who are not already delegates or managers
$r = q("SELECT `uid`, `username`, `nickname` FROM `user` WHERE `nickname` IN ($nicks)");
if (DBA::isResult($r)) {
foreach ($r as $rr) {
if (!in_array($rr['uid'], $uids)) {
$potentials[] = $rr;
}
}
}
}
settings_init($a);
$user = DBA::selectFirst('user', ['parent-uid', 'email'], ['uid' => local_user()]);
$parent_user = null;
if (DBA::isResult($user)) {
if (!DBA::exists('user', ['parent-uid' => local_user()])) {
$parent_uid = $user['parent-uid'];
$parents = [0 => L10n::t('No parent user')];
$fields = ['uid', 'username', 'nickname'];
$condition = ['email' => $user['email'], 'verified' => true, 'blocked' => false, 'parent-uid' => 0];
$parent_users = DBA::select('user', $fields, $condition);
while ($parent = DBA::fetch($parent_users)) {
if ($parent['uid'] != local_user()) {
$parents[$parent['uid']] = sprintf('%s (%s)', $parent['username'], $parent['nickname']);
}
}
$parent_user = ['parent_user', '', $parent_uid, '', $parents];
}
}
if (!is_null($parent_user)) {
$parent_password = ['parent_password', L10n::t('Parent Password:'), '', L10n::t('Please enter the password of the parent account to legitimize your request.')];
} else {
$parent_password = '';
}
$o = Renderer::replaceMacros(Renderer::getMarkupTemplate('delegate.tpl'), [
'$form_security_token' => BaseModule::getFormSecurityToken('delegate'),
'$parent_header' => L10n::t('Parent User'),
'$parent_user' => $parent_user,
'$parent_password' => $parent_password,
'$parent_desc' => L10n::t('Parent users have total control about this account, including the account settings. Please double check whom you give this access.'),
'$submit' => L10n::t('Save Settings'),
'$header' => L10n::t('Delegate Page Management'),
'$delegates_header' => L10n::t('Delegates'),
'$base' => System::baseUrl(),
'$desc' => L10n::t('Delegates are able to manage all aspects of this account/page except for basic account settings. Please do not delegate your personal account to anybody that you do not trust completely.'),
'$head_delegates' => L10n::t('Existing Page Delegates'),
'$delegates' => $delegates,
'$head_potentials' => L10n::t('Potential Delegates'),
'$potentials' => $potentials,
'$remove' => L10n::t('Remove'),
'$add' => L10n::t('Add'),
'$none' => L10n::t('No entries.')
]);
return $o;
}

View file

@ -59,7 +59,7 @@ function dfrn_confirm_post(App $a, $handsfree = null)
* since we are operating on behalf of our registered user to approve a friendship.
*/
if (empty($_POST['source_url'])) {
$uid = defaults($handsfree, 'uid', local_user());
$uid = ($handsfree['uid'] ?? 0) ?: local_user();
if (!$uid) {
notice(L10n::t('Permission denied.') . EOL);
return;
@ -78,13 +78,13 @@ function dfrn_confirm_post(App $a, $handsfree = null)
$intro_id = $handsfree['intro_id'];
$duplex = $handsfree['duplex'];
$cid = 0;
$hidden = intval(defaults($handsfree, 'hidden' , 0));
$hidden = intval($handsfree['hidden'] ?? 0);
} else {
$dfrn_id = Strings::escapeTags(trim(defaults($_POST, 'dfrn_id' , '')));
$intro_id = intval(defaults($_POST, 'intro_id' , 0));
$duplex = intval(defaults($_POST, 'duplex' , 0));
$cid = intval(defaults($_POST, 'contact_id', 0));
$hidden = intval(defaults($_POST, 'hidden' , 0));
$dfrn_id = Strings::escapeTags(trim($_POST['dfrn_id'] ?? ''));
$intro_id = intval($_POST['intro_id'] ?? 0);
$duplex = intval($_POST['duplex'] ?? 0);
$cid = intval($_POST['contact_id'] ?? 0);
$hidden = intval($_POST['hidden'] ?? 0);
}
/*
@ -347,12 +347,12 @@ function dfrn_confirm_post(App $a, $handsfree = null)
*/
if (!empty($_POST['source_url'])) {
// We are processing an external confirmation to an introduction created by our user.
$public_key = defaults($_POST, 'public_key', '');
$dfrn_id = hex2bin(defaults($_POST, 'dfrn_id' , ''));
$source_url = hex2bin(defaults($_POST, 'source_url', ''));
$aes_key = defaults($_POST, 'aes_key' , '');
$duplex = intval(defaults($_POST, 'duplex' , 0));
$page = intval(defaults($_POST, 'page' , 0));
$public_key = $_POST['public_key'] ?? '';
$dfrn_id = hex2bin($_POST['dfrn_id'] ?? '');
$source_url = hex2bin($_POST['source_url'] ?? '');
$aes_key = $_POST['aes_key'] ?? '';
$duplex = intval($_POST['duplex'] ?? 0);
$page = intval($_POST['page'] ?? 0);
$forum = (($page == 1) ? 1 : 0);
$prv = (($page == 2) ? 1 : 0);

View file

@ -26,7 +26,7 @@ function dfrn_notify_post(App $a) {
if (empty($_POST) || !empty($postdata)) {
$data = json_decode($postdata);
if (is_object($data)) {
$nick = defaults($a->argv, 1, '');
$nick = $a->argv[1] ?? '';
$user = DBA::selectFirst('user', [], ['nickname' => $nick, 'account_expired' => false, 'account_removed' => false]);
if (!DBA::isResult($user)) {
@ -42,8 +42,8 @@ function dfrn_notify_post(App $a) {
$dfrn_id = (!empty($_POST['dfrn_id']) ? Strings::escapeTags(trim($_POST['dfrn_id'])) : '');
$dfrn_version = (!empty($_POST['dfrn_version']) ? (float) $_POST['dfrn_version'] : 2.0);
$challenge = (!empty($_POST['challenge']) ? Strings::escapeTags(trim($_POST['challenge'])) : '');
$data = defaults($_POST, 'data', '');
$key = defaults($_POST, 'key', '');
$data = $_POST['data'] ?? '';
$key = $_POST['key'] ?? '';
$rino_remote = (!empty($_POST['rino']) ? intval($_POST['rino']) : 0);
$dissolve = (!empty($_POST['dissolve']) ? intval($_POST['dissolve']) : 0);
$perm = (!empty($_POST['perm']) ? Strings::escapeTags(trim($_POST['perm'])) : 'r');

View file

@ -9,6 +9,7 @@ use Friendica\Core\Config;
use Friendica\Core\L10n;
use Friendica\Core\Logger;
use Friendica\Core\System;
use Friendica\Core\Session;
use Friendica\Database\DBA;
use Friendica\Module\Login;
use Friendica\Protocol\DFRN;
@ -21,17 +22,17 @@ function dfrn_poll_init(App $a)
{
Login::sessionAuth();
$dfrn_id = defaults($_GET, 'dfrn_id' , '');
$type = defaults($_GET, 'type' , 'data');
$last_update = defaults($_GET, 'last_update' , '');
$destination_url = defaults($_GET, 'destination_url', '');
$challenge = defaults($_GET, 'challenge' , '');
$sec = defaults($_GET, 'sec' , '');
$dfrn_version = (float) defaults($_GET, 'dfrn_version' , 2.0);
$dfrn_id = $_GET['dfrn_id'] ?? '';
$type = ($_GET['type'] ?? '') ?: 'data';
$last_update = $_GET['last_update'] ?? '';
$destination_url = $_GET['destination_url'] ?? '';
$challenge = $_GET['challenge'] ?? '';
$sec = $_GET['sec'] ?? '';
$dfrn_version = floatval(($_GET['dfrn_version'] ?? 0.0) ?: 2.0);
$quiet = !empty($_GET['quiet']);
// Possibly it is an OStatus compatible server that requests a user feed
$user_agent = defaults($_SERVER, 'HTTP_USER_AGENT', '');
$user_agent = $_SERVER['HTTP_USER_AGENT'] ?? '';
if (($a->argc > 1) && ($dfrn_id == '') && !strstr($user_agent, 'Friendica')) {
$nickname = $a->argv[1];
header("Content-type: application/atom+xml");
@ -49,7 +50,7 @@ function dfrn_poll_init(App $a)
$hidewall = false;
if (($dfrn_id === '') && empty($_POST['dfrn_id'])) {
if (Config::get('system', 'block_public') && !local_user() && !remote_user()) {
if (Config::get('system', 'block_public') && !Session::isAuthenticated()) {
throw new \Friendica\Network\HTTPException\ForbiddenException();
}
@ -110,17 +111,14 @@ function dfrn_poll_init(App $a)
if ((int)$xml->status === 1) {
$_SESSION['authenticated'] = 1;
if (empty($_SESSION['remote'])) {
$_SESSION['remote'] = [];
}
$_SESSION['remote'][] = ['cid' => $r[0]['id'], 'uid' => $r[0]['uid'], 'url' => $r[0]['url']];
$_SESSION['visitor_id'] = $r[0]['id'];
$_SESSION['visitor_home'] = $r[0]['url'];
$_SESSION['visitor_handle'] = $r[0]['addr'];
$_SESSION['visitor_visiting'] = $r[0]['uid'];
$_SESSION['my_url'] = $r[0]['url'];
Session::setVisitorsContacts();
if (!$quiet) {
info(L10n::t('%1$s welcomes %2$s', $r[0]['username'], $r[0]['name']) . EOL);
}
@ -227,13 +225,13 @@ function dfrn_poll_init(App $a)
function dfrn_poll_post(App $a)
{
$dfrn_id = defaults($_POST, 'dfrn_id' , '');
$challenge = defaults($_POST, 'challenge', '');
$url = defaults($_POST, 'url' , '');
$sec = defaults($_POST, 'sec' , '');
$ptype = defaults($_POST, 'type' , '');
$perm = defaults($_POST, 'perm' , 'r');
$dfrn_version = !empty($_POST['dfrn_version']) ? (float) $_POST['dfrn_version'] : 2.0;
$dfrn_id = $_POST['dfrn_id'] ?? '';
$challenge = $_POST['challenge'] ?? '';
$url = $_POST['url'] ?? '';
$sec = $_POST['sec'] ?? '';
$ptype = $_POST['type'] ?? '';
$perm = ($_POST['perm'] ?? '') ?: 'r';
$dfrn_version = floatval(($_GET['dfrn_version'] ?? 0.0) ?: 2.0);
if ($ptype === 'profile-check') {
if (strlen($challenge) && strlen($sec)) {
@ -393,12 +391,12 @@ function dfrn_poll_post(App $a)
function dfrn_poll_content(App $a)
{
$dfrn_id = defaults($_GET, 'dfrn_id' , '');
$type = defaults($_GET, 'type' , 'data');
$last_update = defaults($_GET, 'last_update' , '');
$destination_url = defaults($_GET, 'destination_url', '');
$sec = defaults($_GET, 'sec' , '');
$dfrn_version = !empty($_GET['dfrn_version']) ? (float) $_GET['dfrn_version'] : 2.0;
$dfrn_id = $_GET['dfrn_id'] ?? '';
$type = ($_GET['type'] ?? '') ?: 'data';
$last_update = $_GET['last_update'] ?? '';
$destination_url = $_GET['destination_url'] ?? '';
$sec = $_GET['sec'] ?? '';
$dfrn_version = floatval(($_GET['dfrn_version'] ?? 0.0) ?: 2.0);
$quiet = !empty($_GET['quiet']);
$direction = -1;
@ -517,15 +515,13 @@ function dfrn_poll_content(App $a)
if (((int) $xml->status == 0) && ($xml->challenge == $hash) && ($xml->sec == $sec)) {
$_SESSION['authenticated'] = 1;
if (empty($_SESSION['remote'])) {
$_SESSION['remote'] = [];
}
$_SESSION['remote'][] = ['cid' => $r[0]['id'], 'uid' => $r[0]['uid'], 'url' => $r[0]['url']];
$_SESSION['visitor_id'] = $r[0]['id'];
$_SESSION['visitor_home'] = $r[0]['url'];
$_SESSION['visitor_visiting'] = $r[0]['uid'];
$_SESSION['my_url'] = $r[0]['url'];
Session::setVisitorsContacts();
if (!$quiet) {
info(L10n::t('%1$s welcomes %2$s', $r[0]['username'], $r[0]['name']) . EOL);
}

View file

@ -19,6 +19,7 @@ use Friendica\Core\Logger;
use Friendica\Core\Protocol;
use Friendica\Core\Renderer;
use Friendica\Core\System;
use Friendica\Core\Session;
use Friendica\Database\DBA;
use Friendica\Model\Contact;
use Friendica\Model\Group;
@ -79,7 +80,7 @@ function dfrn_request_post(App $a)
if (local_user() && ($a->user['nickname'] == $a->argv[1]) && !empty($_POST['dfrn_url'])) {
$dfrn_url = Strings::escapeTags(trim($_POST['dfrn_url']));
$aes_allow = !empty($_POST['aes_allow']);
$confirm_key = defaults($_POST, 'confirm_key', "");
$confirm_key = $_POST['confirm_key'] ?? '';
$hidden = (!empty($_POST['hidden-contact']) ? intval($_POST['hidden-contact']) : 0);
$contact_record = null;
$blocked = 1;
@ -168,7 +169,7 @@ function dfrn_request_post(App $a)
$r = q("SELECT `id`, `network` FROM `contact` WHERE `uid` = %d AND `url` = '%s' AND `site-pubkey` = '%s' LIMIT 1",
intval(local_user()),
DBA::escape($dfrn_url),
defaults($parms, 'key', '') // Potentially missing
$parms['key'] ?? '' // Potentially missing
);
if (DBA::isResult($r)) {
Group::addMember(User::getDefaultGroup(local_user(), $r[0]["network"]), $r[0]['id']);
@ -422,7 +423,7 @@ function dfrn_request_post(App $a)
intval($uid),
intval($contact_record['id']),
intval(!empty($_POST['knowyou'])),
DBA::escape(Strings::escapeTags(trim(defaults($_POST, 'dfrn-request-message', '')))),
DBA::escape(Strings::escapeTags(trim($_POST['dfrn-request-message'] ?? ''))),
DBA::escape($hash),
DBA::escape(DateTimeFormat::utcNow())
);
@ -498,7 +499,7 @@ function dfrn_request_content(App $a)
$dfrn_url = Strings::escapeTags(trim(hex2bin($_GET['dfrn_url'])));
$aes_allow = !empty($_GET['aes_allow']);
$confirm_key = defaults($_GET, 'confirm_key', "");
$confirm_key = $_GET['confirm_key'] ?? '';
// Checking fastlane for validity
if (!empty($_SESSION['fastlane']) && (Strings::normaliseLink($_SESSION["fastlane"]) == Strings::normaliseLink($dfrn_url))) {
@ -592,7 +593,7 @@ function dfrn_request_content(App $a)
exit();
} else {
// Normal web request. Display our user's introduction form.
if ((Config::get('system', 'block_public')) && (!local_user()) && (!remote_user())) {
if (Config::get('system', 'block_public') && !Session::isAuthenticated()) {
if (!Config::get('system', 'local_block')) {
notice(L10n::t('Public access denied.') . EOL);
return;

View file

@ -14,6 +14,7 @@ use Friendica\Core\Logger;
use Friendica\Core\Protocol;
use Friendica\Core\Renderer;
use Friendica\Core\System;
use Friendica\Core\Session;
use Friendica\Database\DBA;
use Friendica\Model\Contact;
use Friendica\Model\Group;
@ -31,7 +32,7 @@ function display_init(App $a)
Objects::rawContent();
}
if (Config::get('system', 'block_public') && !local_user() && !remote_user()) {
if (Config::get('system', 'block_public') && !Session::isAuthenticated()) {
return;
}
@ -52,9 +53,11 @@ function display_init(App $a)
if (DBA::isResult($item)) {
$nick = $a->user["nickname"];
}
}
// Is this item private but could be visible to the remove visitor?
} elseif (remote_user()) {
$item = Item::selectFirst($fields, ['guid' => $a->argv[1], 'private' => 1]);
if (!DBA::isResult($item) && remote_user()) {
$item = Item::selectFirst($fields, ['guid' => $a->argv[1], 'private' => 1, 'origin' => true]);
if (DBA::isResult($item)) {
if (!Contact::isFollower(remote_user(), $item['uid'])) {
$item = null;
@ -84,10 +87,6 @@ function display_init(App $a)
displayShowFeed($item['id'], $a->argc > 3 && $a->argv[3] == 'conversation.atom');
}
if ($a->argc >= 3 && $nick == 'feed-item') {
displayShowFeed($item['id'], $a->argc > 3 && $a->argv[3] == 'conversation.atom');
}
if (!empty($_SERVER['HTTP_ACCEPT']) && strstr($_SERVER['HTTP_ACCEPT'], 'application/atom+xml')) {
Logger::log('Directly serving XML for id '.$item["id"], Logger::DEBUG);
displayShowFeed($item["id"], false);
@ -102,7 +101,7 @@ function display_init(App $a)
if (strstr(Strings::normaliseLink($profiledata["url"]), Strings::normaliseLink(System::baseUrl()))) {
$nickname = str_replace(Strings::normaliseLink(System::baseUrl())."/profile/", "", Strings::normaliseLink($profiledata["url"]));
if (($nickname != $a->user["nickname"])) {
if ($nickname != $a->user["nickname"]) {
$profile = DBA::fetchFirst("SELECT `profile`.`uid` AS `profile_uid`, `profile`.* , `contact`.`avatar-date` AS picdate, `user`.* FROM `profile`
INNER JOIN `contact` on `contact`.`uid` = `profile`.`uid` INNER JOIN `user` ON `profile`.`uid` = `user`.`uid`
WHERE `user`.`nickname` = ? AND `profile`.`is-default` AND `contact`.`self` LIMIT 1",
@ -188,14 +187,16 @@ function display_fetchauthor($a, $item)
$profiledata = Contact::getDetailsByURL($profiledata["url"], local_user(), $profiledata);
if (!empty($profiledata["photo"])) {
$profiledata["photo"] = System::removedBaseUrl($profiledata["photo"]);
}
return $profiledata;
}
function display_content(App $a, $update = false, $update_uid = 0)
{
if (Config::get('system','block_public') && !local_user() && !remote_user()) {
if (Config::get('system','block_public') && !Session::isAuthenticated()) {
throw new HTTPException\ForbiddenException(L10n::t('Public access denied.'));
}
@ -227,8 +228,10 @@ function display_content(App $a, $update = false, $update_uid = 0)
$item_parent = $item["parent"];
$item_parent_uri = $item['parent-uri'];
}
} elseif (remote_user()) {
$item = Item::selectFirst($fields, ['guid' => $a->argv[1], 'private' => 1]);
}
if (($item_parent == 0) && remote_user()) {
$item = Item::selectFirst($fields, ['guid' => $a->argv[1], 'private' => 1, 'origin' => true]);
if (DBA::isResult($item) && Contact::isFollower(remote_user(), $item['uid'])) {
$item_id = $item["id"];
$item_parent = $item["parent"];
@ -267,34 +270,26 @@ function display_content(App $a, $update = false, $update_uid = 0)
['$alternate' => $alternate,
'$conversation' => $conversation]);
$groups = [];
$remote_cid = null;
$is_remote_contact = false;
$item_uid = local_user();
if (isset($item_parent_uri)) {
$parent = Item::selectFirst(['uid'], ['uri' => $item_parent_uri, 'wall' => true]);
if (DBA::isResult($parent)) {
$a->profile['uid'] = defaults($a->profile, 'uid', $parent['uid']);
$a->profile['profile_uid'] = defaults($a->profile, 'profile_uid', $parent['uid']);
$is_remote_contact = Contact::isFollower(remote_user(), $a->profile['profile_uid']);
$a->profile['uid'] = ($a->profile['uid'] ?? 0) ?: $parent['uid'];
$a->profile['profile_uid'] = ($a->profile['profile_uid'] ?? 0) ?: $parent['uid'];
$is_remote_contact = Session::getRemoteContactID($a->profile['profile_uid']);
if ($is_remote_contact) {
$cdata = Contact::getPublicAndUserContacID(remote_user(), $a->profile['profile_uid']);
if (!empty($cdata['user'])) {
$groups = Group::getIdsByContactId($cdata['user']);
$remote_cid = $cdata['user'];
$item_uid = $parent['uid'];
}
}
}
}
$page_contact = DBA::selectFirst('contact', [], ['self' => true, 'uid' => $a->profile['uid']]);
if (DBA::isResult($page_contact)) {
$a->page_contact = $page_contact;
}
$is_owner = (local_user() && (in_array($a->profile['profile_uid'], [local_user(), 0])) ? true : false);
if (!empty($a->profile['hidewall']) && !$is_owner && !$is_remote_contact) {
@ -316,7 +311,7 @@ function display_content(App $a, $update = false, $update_uid = 0)
];
$o .= status_editor($a, $x, 0, true);
}
$sql_extra = Item::getPermissionsSQLByUserId($a->profile['profile_uid'], $is_remote_contact, $groups, $remote_cid);
$sql_extra = Item::getPermissionsSQLByUserId($a->profile['profile_uid']);
if (local_user() && (local_user() == $a->profile['profile_uid'])) {
$condition = ['parent-uri' => $item_parent_uri, 'uid' => local_user(), 'unseen' => true];
@ -330,8 +325,8 @@ function display_content(App $a, $update = false, $update_uid = 0)
}
$condition = ["`id` = ? AND `item`.`uid` IN (0, ?) " . $sql_extra, $item_id, $item_uid];
$fields = ['parent-uri', 'body', 'title', 'author-name', 'author-avatar', 'plink'];
$item = Item::selectFirstForUser(local_user(), $fields, $condition);
$fields = ['parent-uri', 'body', 'title', 'author-name', 'author-avatar', 'plink', 'author-id', 'owner-id', 'contact-id'];
$item = Item::selectFirstForUser($a->profile['profile_uid'], $fields, $condition);
if (!DBA::isResult($item)) {
throw new HTTPException\NotFoundException(L10n::t('The requested item doesn\'t exist or has been deleted.'));
@ -370,7 +365,10 @@ function display_content(App $a, $update = false, $update_uid = 0)
$title = htmlspecialchars($title, ENT_COMPAT, 'UTF-8', true); // allow double encoding here
$author_name = htmlspecialchars($author_name, ENT_COMPAT, 'UTF-8', true); // allow double encoding here
//<meta name="keywords" content="">
if (DBA::exists('contact', ['unsearchable' => true, 'id' => [$item['contact-id'], $item['author-id'], $item['owner-id']]])) {
$a->page['htmlhead'] .= '<meta content="noindex, noarchive" name="robots" />' . "\n";
}
$a->page['htmlhead'] .= '<meta name="author" content="'.$author_name.'" />'."\n";
$a->page['htmlhead'] .= '<meta name="title" content="'.$title.'" />'."\n";
$a->page['htmlhead'] .= '<meta name="fulltitle" content="'.$title.'" />'."\n";

View file

@ -59,11 +59,11 @@ function events_post(App $a)
$cid = !empty($_POST['cid']) ? intval($_POST['cid']) : 0;
$uid = local_user();
$start_text = Strings::escapeHtml(defaults($_REQUEST, 'start_text', ''));
$finish_text = Strings::escapeHtml(defaults($_REQUEST, 'finish_text', ''));
$start_text = Strings::escapeHtml($_REQUEST['start_text'] ?? '');
$finish_text = Strings::escapeHtml($_REQUEST['finish_text'] ?? '');
$adjust = intval(defaults($_POST, 'adjust', 0));
$nofinish = intval(defaults($_POST, 'nofinish', 0));
$adjust = intval($_POST['adjust'] ?? 0);
$nofinish = intval($_POST['nofinish'] ?? 0);
// The default setting for the `private` field in event_store() is false, so mirror that
$private_event = false;
@ -96,9 +96,9 @@ function events_post(App $a)
// and we'll waste a bunch of time responding to it. Time that
// could've been spent doing something else.
$summary = trim(defaults($_POST, 'summary' , ''));
$desc = trim(defaults($_POST, 'desc' , ''));
$location = trim(defaults($_POST, 'location', ''));
$summary = trim($_POST['summary'] ?? '');
$desc = trim($_POST['desc'] ?? '');
$location = trim($_POST['location'] ?? '');
$type = 'event';
$params = [
@ -132,7 +132,7 @@ function events_post(App $a)
$a->internalRedirect($onerror_path);
}
$share = intval(defaults($_POST, 'share', 0));
$share = intval($_POST['share'] ?? 0);
$c = q("SELECT `id` FROM `contact` WHERE `uid` = %d AND `self` LIMIT 1",
intval(local_user())
@ -146,10 +146,10 @@ function events_post(App $a)
if ($share) {
$str_group_allow = perms2str(defaults($_POST, 'group_allow' , ''));
$str_contact_allow = perms2str(defaults($_POST, 'contact_allow', ''));
$str_group_deny = perms2str(defaults($_POST, 'group_deny' , ''));
$str_contact_deny = perms2str(defaults($_POST, 'contact_deny' , ''));
$str_group_allow = perms2str($_POST['group_allow'] ?? '');
$str_contact_allow = perms2str($_POST['contact_allow'] ?? '');
$str_group_deny = perms2str($_POST['group_deny'] ?? '');
$str_contact_deny = perms2str($_POST['contact_deny'] ?? '');
// Undo the pseudo-contact of self, since there are real contacts now
if (strpos($str_contact_allow, '<' . $self . '>') !== false) {
@ -321,7 +321,7 @@ function events_content(App $a)
// put the event parametes in an array so we can better transmit them
$event_params = [
'event_id' => intval(defaults($_GET, 'id', 0)),
'event_id' => intval($_GET['id'] ?? 0),
'start' => $start,
'finish' => $finish,
'adjust_start' => $adjust_start,

View file

@ -29,7 +29,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(defaults($_GET, 'theme', null));
$theme = Strings::sanitizeFilePathItem($_GET['theme'] ?? null);
if ($theme && is_file("view/theme/$theme/config.php")) {
$a->setCurrentTheme($theme);
}

View file

@ -62,7 +62,7 @@ function follow_content(App $a)
$uid = local_user();
// Issue 4815: Silently removing a prefixing @
$url = ltrim(Strings::escapeTags(trim(defaults($_REQUEST, 'url', ''))), '@!');
$url = ltrim(Strings::escapeTags(trim($_REQUEST['url'] ?? '')), '@!');
// Issue 6874: Allow remote following from Peertube
if (strpos($url, 'acct:') === 0) {

View file

@ -45,7 +45,7 @@ function fsuggest_post(App $a)
return;
}
$note = Strings::escapeHtml(trim(defaults($_POST, 'note', '')));
$note = Strings::escapeHtml(trim($_POST['note'] ?? ''));
$fields = ['uid' => local_user(),'cid' => $contact_id, 'name' => $contact['name'],
'url' => $contact['url'], 'request' => $contact['request'],

View file

@ -6,13 +6,14 @@ use Friendica\App;
use Friendica\Core\Config;
use Friendica\Core\L10n;
use Friendica\Core\System;
use Friendica\Core\Session;
use Friendica\Model\Contact;
use Friendica\Model\Profile;
use Friendica\Model\User;
function hcard_init(App $a)
{
$blocked = Config::get('system', 'block_public') && !local_user() && !remote_user();
$blocked = Config::get('system', 'block_public') && !Session::isAuthenticated();
if ($a->argc > 1) {
$which = $a->argv[1];
@ -40,7 +41,7 @@ function hcard_init(App $a)
}
if (!$blocked) {
$keywords = defaults($a->profile, 'pub_keywords', '');
$keywords = $a->profile['pub_keywords'] ?? '';
$keywords = str_replace([',',' ',',,'], [' ',',',','], $keywords);
if (strlen($keywords)) {
$a->page['htmlhead'] .= '<meta name="keywords" content="' . $keywords . '" />' . "\r\n";

View file

@ -26,8 +26,8 @@ function hovercard_init(App $a)
function hovercard_content()
{
$profileurl = defaults($_REQUEST, 'profileurl', '');
$datatype = defaults($_REQUEST, 'datatype' , 'json');
$profileurl = $_REQUEST['profileurl'] ?? '';
$datatype = ($_REQUEST['datatype'] ?? '') ?: 'json';
// Get out if the system doesn't have public access allowed
if (intval(Config::get('system', 'block_public'))) {
@ -50,7 +50,7 @@ function hovercard_content()
if (strpos($profileurl, 'redir/') === 0) {
$cid = intval(substr($profileurl, 6));
$remote_contact = DBA::selectFirst('contact', ['nurl'], ['id' => $cid]);
$profileurl = defaults($remote_contact, 'nurl', '');
$profileurl = $remote_contact['nurl'] ?? '';
}
$contact = [];
@ -97,7 +97,7 @@ function hovercard_content()
$profile = [
'name' => $contact['name'],
'nick' => $contact['nick'],
'addr' => defaults($contact, 'addr', $contact['url']),
'addr' => ($contact['addr'] ?? '') ?: $contact['url'],
'thumb' => ProxyUtils::proxifyUrl($contact['thumb'], false, ProxyUtils::SIZE_THUMB),
'url' => Contact::magicLink($contact['url']),
'nurl' => $contact['nurl'], // We additionally store the nurl as identifier

View file

@ -33,7 +33,7 @@ function ignored_init(App $a)
}
// See if we've been passed a return path to redirect to
$return_path = defaults($_REQUEST, 'return', '');
$return_path = $_REQUEST['return'] ?? '';
if ($return_path) {
$rand = '_=' . time();
if (strpos($return_path, '?')) {

View file

@ -25,6 +25,7 @@ use Friendica\Core\L10n;
use Friendica\Core\Logger;
use Friendica\Core\Protocol;
use Friendica\Core\System;
use Friendica\Core\Session;
use Friendica\Core\Worker;
use Friendica\Database\DBA;
use Friendica\Model\Attach;
@ -42,10 +43,10 @@ use Friendica\Util\Security;
use Friendica\Util\Strings;
use Friendica\Worker\Delivery;
require_once 'include/items.php';
require_once __DIR__ . '/../include/items.php';
function item_post(App $a) {
if (!local_user() && !remote_user()) {
if (!Session::isAuthenticated()) {
return 0;
}
@ -63,12 +64,12 @@ function item_post(App $a) {
Logger::log('postvars ' . print_r($_REQUEST, true), Logger::DATA);
$api_source = defaults($_REQUEST, 'api_source', false);
$api_source = $_REQUEST['api_source'] ?? false;
$message_id = ((!empty($_REQUEST['message_id']) && $api_source) ? strip_tags($_REQUEST['message_id']) : '');
$return_path = defaults($_REQUEST, 'return', '');
$preview = intval(defaults($_REQUEST, 'preview', 0));
$return_path = $_REQUEST['return'] ?? '';
$preview = intval($_REQUEST['preview'] ?? 0);
/*
* Check for doubly-submitted posts, and reject duplicates
@ -85,8 +86,8 @@ function item_post(App $a) {
}
// Is this a reply to something?
$toplevel_item_id = intval(defaults($_REQUEST, 'parent', 0));
$thr_parent_uri = trim(defaults($_REQUEST, 'parent_uri', ''));
$toplevel_item_id = intval($_REQUEST['parent'] ?? 0);
$thr_parent_uri = trim($_REQUEST['parent_uri'] ?? '');
$thread_parent_id = 0;
$thread_parent_contact = null;
@ -97,8 +98,8 @@ function item_post(App $a) {
$parent_contact = null;
$objecttype = null;
$profile_uid = defaults($_REQUEST, 'profile_uid', local_user());
$posttype = defaults($_REQUEST, 'post_type', Item::PT_ARTICLE);
$profile_uid = ($_REQUEST['profile_uid'] ?? 0) ?: local_user();
$posttype = ($_REQUEST['post_type'] ?? '') ?: Item::PT_ARTICLE;
if ($toplevel_item_id || $thr_parent_uri) {
if ($toplevel_item_id) {
@ -137,10 +138,10 @@ function item_post(App $a) {
Logger::info('mod_item: item_post parent=' . $toplevel_item_id);
}
$post_id = intval(defaults($_REQUEST, 'post_id', 0));
$app = strip_tags(defaults($_REQUEST, 'source', ''));
$extid = strip_tags(defaults($_REQUEST, 'extid', ''));
$object = defaults($_REQUEST, 'object', '');
$post_id = intval($_REQUEST['post_id'] ?? 0);
$app = strip_tags($_REQUEST['source'] ?? '');
$extid = strip_tags($_REQUEST['extid'] ?? '');
$object = $_REQUEST['object'] ?? '';
// Don't use "defaults" here. It would turn 0 to 1
if (!isset($_REQUEST['wall'])) {
@ -193,20 +194,20 @@ function item_post(App $a) {
$categories = '';
$postopts = '';
$emailcc = '';
$body = defaults($_REQUEST, 'body', '');
$has_attachment = defaults($_REQUEST, 'has_attachment', 0);
$body = $_REQUEST['body'] ?? '';
$has_attachment = $_REQUEST['has_attachment'] ?? 0;
// If we have a speparate attachment, we need to add it to the body.
if (!empty($has_attachment)) {
$attachment_type = defaults($_REQUEST, 'attachment_type', '');
$attachment_title = defaults($_REQUEST, 'attachment_title', '');
$attachment_text = defaults($_REQUEST, 'attachment_text', '');
$attachment_type = $_REQUEST['attachment_type'] ?? '';
$attachment_title = $_REQUEST['attachment_title'] ?? '';
$attachment_text = $_REQUEST['attachment_text'] ?? '';
$attachment_url = hex2bin(defaults($_REQUEST, 'attachment_url', ''));
$attachment_img_src = hex2bin(defaults($_REQUEST, 'attachment_img_src', ''));
$attachment_url = hex2bin($_REQUEST['attachment_url'] ?? '');
$attachment_img_src = hex2bin($_REQUEST['attachment_img_src'] ?? '');
$attachment_img_width = defaults($_REQUEST, 'attachment_img_width', 0);
$attachment_img_height = defaults($_REQUEST, 'attachment_img_height', 0);
$attachment_img_width = $_REQUEST['attachment_img_width'] ?? 0;
$attachment_img_height = $_REQUEST['attachment_img_height'] ?? 0;
$attachment = [
'type' => $attachment_type,
'title' => $attachment_title,
@ -228,6 +229,9 @@ function item_post(App $a) {
$body .= $att_bbcode;
}
// Convert links with empty descriptions to links without an explicit description
$body = preg_replace('#\[url=([^\]]*?)\]\[/url\]#ism', '[url]$1[/url]', $body);
if (!empty($orig_post)) {
$str_group_allow = $orig_post['allow_gid'];
$str_contact_allow = $orig_post['allow_cid'];
@ -265,29 +269,25 @@ function item_post(App $a) {
$str_contact_deny = $user['deny_cid'];
} else {
// use the posted permissions
$str_group_allow = perms2str(defaults($_REQUEST, 'group_allow', ''));
$str_contact_allow = perms2str(defaults($_REQUEST, 'contact_allow', ''));
$str_group_deny = perms2str(defaults($_REQUEST, 'group_deny', ''));
$str_contact_deny = perms2str(defaults($_REQUEST, 'contact_deny', ''));
$str_group_allow = perms2str($_REQUEST['group_allow'] ?? '');
$str_contact_allow = perms2str($_REQUEST['contact_allow'] ?? '');
$str_group_deny = perms2str($_REQUEST['group_deny'] ?? '');
$str_contact_deny = perms2str($_REQUEST['contact_deny'] ?? '');
}
$title = Strings::escapeTags(trim(defaults($_REQUEST, 'title' , '')));
$location = Strings::escapeTags(trim(defaults($_REQUEST, 'location', '')));
$coord = Strings::escapeTags(trim(defaults($_REQUEST, 'coord' , '')));
$verb = Strings::escapeTags(trim(defaults($_REQUEST, 'verb' , '')));
$emailcc = Strings::escapeTags(trim(defaults($_REQUEST, 'emailcc' , '')));
$title = Strings::escapeTags(trim($_REQUEST['title'] ?? ''));
$location = Strings::escapeTags(trim($_REQUEST['location'] ?? ''));
$coord = Strings::escapeTags(trim($_REQUEST['coord'] ?? ''));
$verb = Strings::escapeTags(trim($_REQUEST['verb'] ?? ''));
$emailcc = Strings::escapeTags(trim($_REQUEST['emailcc'] ?? ''));
$body = Strings::escapeHtml(trim($body));
$network = Strings::escapeTags(trim(defaults($_REQUEST, 'network' , Protocol::DFRN)));
$network = Strings::escapeTags(trim(($_REQUEST['network'] ?? '') ?: Protocol::DFRN));
$guid = System::createUUID();
$postopts = defaults($_REQUEST, 'postopts', '');
$postopts = $_REQUEST['postopts'] ?? '';
$private = ((strlen($str_group_allow) || strlen($str_contact_allow) || strlen($str_group_deny) || strlen($str_contact_deny)) ? 1 : 0);
if ($user['hidewall']) {
$private = 2;
}
// If this is a comment, set the permissions from the parent.
if ($toplevel_item) {
@ -307,7 +307,7 @@ function item_post(App $a) {
$wall = $toplevel_item['wall'];
}
$pubmail_enabled = defaults($_REQUEST, 'pubmail_enable', false) && !$private;
$pubmail_enabled = ($_REQUEST['pubmail_enable'] ?? false) && !$private;
// if using the API, we won't see pubmail_enable - figure out if it should be set
if ($api_source && $profile_uid && $profile_uid == local_user() && !$private) {
@ -335,7 +335,7 @@ function item_post(App $a) {
// save old and new categories, so we can determine what needs to be deleted from pconfig
$categories_old = $categories;
$categories = FileTag::listToFile(trim(defaults($_REQUEST, 'category', '')), 'category');
$categories = FileTag::listToFile(trim($_REQUEST['category'] ?? ''), 'category');
$categories_new = $categories;
if (!empty($filedas) && is_array($filedas)) {
@ -352,18 +352,8 @@ function item_post(App $a) {
if (local_user() && ((local_user() == $profile_uid) || $allow_comment)) {
$self = true;
$author = DBA::selectFirst('contact', [], ['uid' => local_user(), 'self' => true]);
} elseif (remote_user()) {
if (!empty($_SESSION['remote']) && is_array($_SESSION['remote'])) {
foreach ($_SESSION['remote'] as $v) {
if ($v['uid'] == $profile_uid) {
$contact_id = $v['cid'];
break;
}
}
}
if ($contact_id) {
$author = DBA::selectFirst('contact', [], ['id' => $contact_id]);
}
} elseif (!empty(Session::getRemoteContactID($profile_uid))) {
$author = DBA::selectFirst('contact', [], ['id' => Session::getRemoteContactID($profile_uid)]);
}
if (DBA::isResult($author)) {
@ -874,7 +864,7 @@ function item_post_return($baseurl, $api_source, $return_path)
function item_content(App $a)
{
if (!local_user() && !remote_user()) {
if (!Session::isAuthenticated()) {
return;
}
@ -1025,7 +1015,7 @@ function handle_tag(&$body, &$inform, &$str_tags, $profile_uid, $tag, $network =
$profile = $contact["url"];
$alias = $contact["alias"];
$newname = defaults($contact, "name", $contact["nick"]);
$newname = ($contact["name"] ?? '') ?: $contact["nick"];
}
//if there is an url for this persons profile

View file

@ -1,4 +1,5 @@
<?php
/**
* @file mod/lostpass.php
*/
@ -27,7 +28,7 @@ function lostpass_post(App $a)
$a->internalRedirect();
}
$pwdreset_token = Strings::getRandomName(12) . mt_rand(1000, 9999);
$pwdreset_token = Strings::getRandomName(12) . random_int(1000, 9999);
$fields = [
'pwdreset' => $pwdreset_token,

View file

@ -1,188 +0,0 @@
<?php
/**
* @file mod/manage.php
*/
use Friendica\App;
use Friendica\Core\Hook;
use Friendica\Core\L10n;
use Friendica\Core\Renderer;
use Friendica\Core\Session;
use Friendica\Database\DBA;
function manage_post(App $a) {
if (! local_user()) {
return;
}
$uid = local_user();
$orig_record = $a->user;
if(!empty($_SESSION['submanage'])) {
$r = q("select * from user where uid = %d limit 1",
intval($_SESSION['submanage'])
);
if (DBA::isResult($r)) {
$uid = intval($r[0]['uid']);
$orig_record = $r[0];
}
}
$r = q("SELECT * FROM `manage` WHERE `uid` = %d",
intval($uid)
);
$submanage = $r;
$identity = (!empty($_POST['identity']) ? intval($_POST['identity']) : 0);
if (!$identity) {
return;
}
$limited_id = 0;
$original_id = $uid;
if (DBA::isResult($submanage)) {
foreach ($submanage as $m) {
if ($identity == $m['mid']) {
$limited_id = $m['mid'];
break;
}
}
}
if ($limited_id) {
$r = q("SELECT * FROM `user` WHERE `uid` = %d LIMIT 1",
intval($limited_id)
);
} else {
// Check if the target user is one of our children
$r = q("SELECT * FROM `user` WHERE `uid` = %d AND `parent-uid` = %d LIMIT 1",
intval($identity),
DBA::escape($orig_record['uid'])
);
// Check if the target user is one of our siblings
if (!DBA::isResult($r) && ($orig_record['parent-uid'] != 0)) {
$r = q("SELECT * FROM `user` WHERE `uid` = %d AND `parent-uid` = %d LIMIT 1",
intval($identity),
DBA::escape($orig_record['parent-uid'])
);
}
// Check if it's our parent
if (!DBA::isResult($r) && ($orig_record['parent-uid'] != 0) && ($orig_record['parent-uid'] == $identity)) {
$r = q("SELECT * FROM `user` WHERE `uid` = %d LIMIT 1",
intval($identity)
);
}
// Finally check if it's out own user
if (!DBA::isResult($r) && ($orig_record['uid'] != 0) && ($orig_record['uid'] == $identity)) {
$r = q("SELECT * FROM `user` WHERE `uid` = %d LIMIT 1",
intval($identity)
);
}
}
if (!DBA::isResult($r)) {
return;
}
unset($_SESSION['authenticated']);
unset($_SESSION['uid']);
unset($_SESSION['visitor_id']);
unset($_SESSION['administrator']);
unset($_SESSION['cid']);
unset($_SESSION['theme']);
unset($_SESSION['mobile-theme']);
unset($_SESSION['page_flags']);
unset($_SESSION['return_path']);
if (!empty($_SESSION['submanage'])) {
unset($_SESSION['submanage']);
}
if (!empty($_SESSION['sysmsg'])) {
unset($_SESSION['sysmsg']);
}
if (!empty($_SESSION['sysmsg_info'])) {
unset($_SESSION['sysmsg_info']);
}
Session::setAuthenticatedForUser($a, $r[0], true, true);
if ($limited_id) {
$_SESSION['submanage'] = $original_id;
}
$ret = [];
Hook::callAll('home_init',$ret);
$a->internalRedirect('profile/' . $a->user['nickname'] );
// NOTREACHED
}
function manage_content(App $a) {
if (! local_user()) {
notice(L10n::t('Permission denied.') . EOL);
return;
}
if (!empty($_GET['identity'])) {
$_POST['identity'] = $_GET['identity'];
manage_post($a);
return;
}
$identities = $a->identities;
//getting additinal information for each identity
foreach ($identities as $key=>$id) {
$thumb = q("SELECT `thumb` FROM `contact` WHERE `uid` = '%s' AND `self` = 1",
DBA::escape($id['uid'])
);
$identities[$key]['thumb'] = $thumb[0]['thumb'];
$identities[$key]['selected'] = ($id['nickname'] === $a->user['nickname']);
$notifications = 0;
$r = q("SELECT DISTINCT(`parent`) FROM `notify` WHERE `uid` = %d AND NOT `seen` AND NOT (`type` IN (%d, %d))",
intval($id['uid']), intval(NOTIFY_INTRO), intval(NOTIFY_MAIL));
if (DBA::isResult($r)) {
$notifications = sizeof($r);
}
$r = q("SELECT DISTINCT(`convid`) FROM `mail` WHERE `uid` = %d AND NOT `seen`",
intval($id['uid']));
if (DBA::isResult($r)) {
$notifications = $notifications + sizeof($r);
}
$r = q("SELECT COUNT(*) AS `introductions` FROM `intro` WHERE NOT `blocked` AND NOT `ignore` AND `uid` = %d",
intval($id['uid']));
if (DBA::isResult($r)) {
$notifications = $notifications + $r[0]["introductions"];
}
$identities[$key]['notifications'] = $notifications;
}
$o = Renderer::replaceMacros(Renderer::getMarkupTemplate('manage.tpl'), [
'$title' => L10n::t('Manage Identities and/or Pages'),
'$desc' => L10n::t('Toggle between different identities or community/group pages which share your account details or which you have been granted "manage" permissions'),
'$choose' => L10n::t('Select an identity to manage: '),
'$identities' => $identities,
'$submit' => L10n::t('Submit'),
]);
return $o;
}

View file

@ -66,7 +66,7 @@ function match_content(App $a)
$msearch = json_decode($msearch_json);
$start = defaults($_GET, 'start', 0);
$start = $_GET['start'] ?? 0;
$entries = [];
$paginate = '';
@ -92,11 +92,11 @@ function match_content(App $a)
$entry = [
'url' => Contact::magicLink($profile->url),
'itemurl' => defaults($contact_details, 'addr', $profile->url),
'itemurl' => $contact_details['addr'] ?? $profile->url,
'name' => $profile->name,
'details' => defaults($contact_details, 'location', ''),
'tags' => defaults($contact_details, 'keywords', ''),
'about' => defaults($contact_details, 'about', ''),
'details' => $contact_details['location'] ?? '',
'tags' => $contact_details['keywords'] ?? '',
'about' => $contact_details['about'] ?? '',
'account_type' => Contact::getAccountType($contact_details),
'thumb' => ProxyUtils::proxifyUrl($profile->photo, false, ProxyUtils::SIZE_THUMB),
'conntxt' => L10n::t('Connect'),

View file

@ -249,8 +249,8 @@ function message_content(App $a)
'$prefill' => $prefill,
'$preid' => $preid,
'$subject' => L10n::t('Subject:'),
'$subjtxt' => defaults($_REQUEST, 'subject', ''),
'$text' => defaults($_REQUEST, 'body', ''),
'$subjtxt' => $_REQUEST['subject'] ?? '',
'$text' => $_REQUEST['body'] ?? '',
'$readonly' => '',
'$yourmessage'=> L10n::t('Your message:'),
'$select' => $select,
@ -530,7 +530,7 @@ function render_messages(array $msg, $t)
'$id' => $rr['id'],
'$from_name' => $participants,
'$from_url' => Contact::magicLink($rr['url']),
'$from_addr' => defaults($contact, 'addr', ''),
'$from_addr' => $contact['addr'] ?? '',
'$sparkle' => ' sparkle',
'$from_photo' => ProxyUtils::proxifyUrl($from_photo, false, ProxyUtils::SIZE_THUMB),
'$subject' => $rr['title'],

View file

@ -6,9 +6,9 @@ use Friendica\Database\DBA;
function msearch_post(App $a)
{
$search = defaults($_POST, 's', '');
$perpage = intval(defaults($_POST, 'n', 80));
$page = intval(defaults($_POST, 'p', 1));
$search = $_POST['s'] ?? '';
$perpage = intval(($_POST['n'] ?? 0) ?: 80);
$page = intval(($_POST['p'] ?? 0) ?: 1);
$startrec = ($page - 1) * $perpage;
$total = 0;

View file

@ -40,22 +40,6 @@ function network_init(App $a)
Hook::add('head', __FILE__, 'network_infinite_scroll_head');
$search = (!empty($_GET['search']) ? Strings::escapeHtml($_GET['search']) : '');
if (($search != '') && !empty($_GET['submit'])) {
$a->internalRedirect('search?search=' . urlencode($search));
}
if (!empty($_GET['save'])) {
$exists = DBA::exists('search', ['uid' => local_user(), 'term' => $search]);
if (!$exists) {
DBA::insert('search', ['uid' => local_user(), 'term' => $search]);
}
}
if (!empty($_GET['remove'])) {
DBA::delete('search', ['uid' => local_user(), 'term' => $search]);
}
$is_a_date_query = false;
$group_id = (($a->argc > 1 && is_numeric($a->argv[1])) ? intval($a->argv[1]) : 0);
@ -82,7 +66,7 @@ function network_init(App $a)
// fetch last used network view and redirect if needed
if (!$is_a_date_query) {
$sel_nets = defaults($_GET, 'nets', '');
$sel_nets = $_GET['nets'] ?? '';
$sel_tabs = network_query_get_sel_tab($a);
$sel_groups = network_query_get_sel_group($a);
$last_sel_tabs = PConfig::get(local_user(), 'network.view', 'tab.selected');
@ -154,46 +138,9 @@ function network_init(App $a)
$a->page['aside'] .= Group::sidebarWidget('network/0', 'network', 'standard', $group_id);
$a->page['aside'] .= ForumManager::widget(local_user(), $cid);
$a->page['aside'] .= Widget::postedByYear('network', local_user(), false);
$a->page['aside'] .= Widget::networks('network', defaults($_GET, 'nets', '') );
$a->page['aside'] .= saved_searches($search);
$a->page['aside'] .= Widget::fileAs('network', defaults($_GET, 'file', '') );
}
function saved_searches($search)
{
$srchurl = '/network?f='
. (!empty($_GET['cid']) ? '&cid=' . rawurlencode($_GET['cid']) : '')
. (!empty($_GET['star']) ? '&star=' . rawurlencode($_GET['star']) : '')
. (!empty($_GET['bmark']) ? '&bmark=' . rawurlencode($_GET['bmark']) : '')
. (!empty($_GET['conv']) ? '&conv=' . rawurlencode($_GET['conv']) : '')
. (!empty($_GET['nets']) ? '&nets=' . rawurlencode($_GET['nets']) : '')
. (!empty($_GET['cmin']) ? '&cmin=' . rawurlencode($_GET['cmin']) : '')
. (!empty($_GET['cmax']) ? '&cmax=' . rawurlencode($_GET['cmax']) : '')
. (!empty($_GET['file']) ? '&file=' . rawurlencode($_GET['file']) : '');
;
$terms = DBA::select('search', ['id', 'term'], ['uid' => local_user()]);
$saved = [];
while ($rr = DBA::fetch($terms)) {
$saved[] = [
'id' => $rr['id'],
'term' => $rr['term'],
'encodedterm' => urlencode($rr['term']),
'delete' => L10n::t('Remove term'),
'selected' => ($search == $rr['term']),
];
}
$tpl = Renderer::getMarkupTemplate('saved_searches_aside.tpl');
$o = Renderer::replaceMacros($tpl, [
'$title' => L10n::t('Saved Searches'),
'$add' => L10n::t('add'),
'$searchbox' => HTML::search($search, 'netsearch-box', $srchurl),
'$saved' => $saved,
]);
return $o;
$a->page['aside'] .= Widget::networks('network', $_GET['nets'] ?? '');
$a->page['aside'] .= Widget\SavedSearches::getHTML($a->query_string);
$a->page['aside'] .= Widget::fileAs('network', $_GET['file'] ?? '');
}
/**
@ -409,7 +356,7 @@ function networkFlatView(App $a, $update = 0)
$o = '';
$file = defaults($_GET, 'file', '');
$file = $_GET['file'] ?? '';
if (!$update && !$rawmode) {
$tabs = network_tabs($a);
@ -532,12 +479,12 @@ function networkThreadedView(App $a, $update, $parent)
$o = '';
$cid = intval(defaults($_GET, 'cid' , 0));
$star = intval(defaults($_GET, 'star' , 0));
$bmark = intval(defaults($_GET, 'bmark', 0));
$conv = intval(defaults($_GET, 'conv' , 0));
$order = Strings::escapeTags(defaults($_GET, 'order', 'comment'));
$nets = defaults($_GET, 'nets' , '');
$cid = intval($_GET['cid'] ?? 0);
$star = intval($_GET['star'] ?? 0);
$bmark = intval($_GET['bmark'] ?? 0);
$conv = intval($_GET['conv'] ?? 0);
$order = Strings::escapeTags(($_GET['order'] ?? '') ?: 'comment');
$nets = $_GET['nets'] ?? '';
$allowedCids = [];
if ($cid) {
@ -676,7 +623,7 @@ function networkThreadedView(App $a, $update, $parent)
$entries[0] = [
'id' => 'network',
'name' => $contact['name'],
'itemurl' => defaults($contact, 'addr', $contact['nurl']),
'itemurl' => ($contact['addr'] ?? '') ?: $contact['nurl'],
'thumb' => ProxyUtils::proxifyUrl($contact['thumb'], false, ProxyUtils::SIZE_THUMB),
'details' => $contact['location'],
];
@ -1066,7 +1013,7 @@ function network_infinite_scroll_head(App $a, &$htmlhead)
global $pager;
if (PConfig::get(local_user(), 'system', 'infinite_scroll')
&& defaults($_GET, 'mode', '') != 'minimal'
&& ($_GET['mode'] ?? '') != 'minimal'
) {
$tpl = Renderer::getMarkupTemplate('infinite_scroll_head.tpl');
$htmlhead .= Renderer::replaceMacros($tpl, [

View file

@ -49,7 +49,7 @@ function noscrape_init(App $a)
exit;
}
$keywords = defaults($a->profile, 'pub_keywords', '');
$keywords = $a->profile['pub_keywords'] ?? '';
$keywords = str_replace(['#',',',' ',',,'], ['',' ',',',','], $keywords);
$keywords = explode(',', $keywords);

View file

@ -12,9 +12,11 @@ use Friendica\Core\L10n;
use Friendica\Core\NotificationsManager;
use Friendica\Core\Protocol;
use Friendica\Core\Renderer;
use Friendica\Core\Logger;
use Friendica\Core\System;
use Friendica\Database\DBA;
use Friendica\Module\Login;
use Friendica\Model\Contact;
function notifications_post(App $a)
{
@ -46,13 +48,18 @@ function notifications_post(App $a)
if ($_POST['submit'] == L10n::t('Discard')) {
DBA::delete('intro', ['id' => $intro_id]);
if (!$fid) {
// The check for blocked and pending is in case the friendship was already approved
// and we just want to get rid of the now pointless notification
// When the contact entry had been created just for that intro, we want to get rid of it now
$condition = ['id' => $contact_id, 'uid' => local_user(),
'self' => false, 'blocked' => true, 'pending' => true];
DBA::delete('contact', $condition);
'self' => false, 'pending' => true, 'rel' => [0, Contact::FOLLOWER]];
$contact_pending = DBA::exists('contact', $condition);
// Remove the "pending" to stop the reappearing in any case
DBA::update('contact', ['pending' => false], ['id' => $contact_id]);
if ($contact_pending) {
Contact::remove($contact_id);
}
}
$a->internalRedirect('notifications/intros');
}
@ -71,8 +78,8 @@ function notifications_content(App $a)
return Login::form();
}
$page = defaults($_REQUEST, 'page', 1);
$show = defaults($_REQUEST, 'show', 0);
$page = ($_REQUEST['page'] ?? 0) ?: 1;
$show = $_REQUEST['show'] ?? 0;
Nav::setSelected('notifications');
@ -98,9 +105,14 @@ function notifications_content(App $a)
if ((($a->argc > 1) && ($a->argv[1] == 'intros')) || (($a->argc == 1))) {
Nav::setSelected('introductions');
$id = 0;
if (!empty($a->argv[2]) && intval($a->argv[2]) != 0) {
$id = (int)$a->argv[2];
}
$all = (($a->argc > 2) && ($a->argv[2] == 'all'));
$notifs = $nm->introNotifs($all, $startrec, $perpage);
$notifs = $nm->introNotifs($all, $startrec, $perpage, $id);
// Get the network notifications
} elseif (($a->argc > 1) && ($a->argv[1] == 'network')) {
@ -146,7 +158,7 @@ function notifications_content(App $a)
];
// Process the data for template creation
if (defaults($notifs, 'ident', '') === 'introductions') {
if (($notifs['ident'] ?? '') == 'introductions') {
$sugg = Renderer::getMarkupTemplate('suggestions.tpl');
$tpl = Renderer::getMarkupTemplate('intros.tpl');

View file

@ -13,9 +13,9 @@ use Friendica\Util\Strings;
function openid_content(App $a) {
$noid = Config::get('system','no_openid');
if($noid)
if (Config::get('system','no_openid')) {
$a->internalRedirect();
}
Logger::log('mod_openid ' . print_r($_REQUEST,true), Logger::DATA);
@ -24,10 +24,9 @@ function openid_content(App $a) {
$openid = new LightOpenID($a->getHostName());
if ($openid->validate()) {
$authid = $openid->identity;
$authid = $_REQUEST['openid_identity'];
if(! strlen($authid)) {
if (empty($authid)) {
Logger::log(L10n::t('OpenID protocol error. No ID returned.') . EOL);
$a->internalRedirect();
}
@ -37,22 +36,16 @@ function openid_content(App $a) {
// mod/settings.php in 8367cad so it might have left mixed
// records in the user table
//
$r = q("SELECT *
FROM `user`
WHERE ( `openid` = '%s' OR `openid` = '%s' )
AND `blocked` = 0 AND `account_expired` = 0
AND `account_removed` = 0 AND `verified` = 1
LIMIT 1",
DBA::escape($authid), DBA::escape(Strings::normaliseOpenID($authid))
);
if (DBA::isResult($r)) {
$condition = ['blocked' => false, 'account_expired' => false, 'account_removed' => false, 'verified' => true,
'openid' => [$authid, Strings::normaliseOpenID($authid)]];
$user = DBA::selectFirst('user', [], $condition);
if (DBA::isResult($user)) {
// successful OpenID login
unset($_SESSION['openid']);
Session::setAuthenticatedForUser($a, $r[0],true,true);
Session::setAuthenticatedForUser($a, $user, true, true);
// just in case there was no return url set
// and we fell through
@ -95,15 +88,13 @@ function openid_content(App $a) {
}
if (!empty($nick)) {
$args .= '&nickname=' . urlencode($nick);
}
elseif (!empty($first)) {
} elseif (!empty($first)) {
$args .= '&nickname=' . urlencode($first);
}
if (!empty($photosq)) {
$args .= '&photo=' . urlencode($photosq);
}
elseif (!empty($photo)) {
} elseif (!empty($photo)) {
$args .= '&photo=' . urlencode($photo);
}

View file

@ -15,6 +15,7 @@ use Friendica\Core\L10n;
use Friendica\Core\Logger;
use Friendica\Core\Renderer;
use Friendica\Core\System;
use Friendica\Core\Session;
use Friendica\Database\DBA;
use Friendica\Model\Contact;
use Friendica\Model\Group;
@ -35,11 +36,7 @@ use Friendica\Util\XML;
function photos_init(App $a) {
if ($a->argc > 1) {
DFRN::autoRedir($a, $a->argv[1]);
}
if (Config::get('system', 'block_public') && !local_user() && !remote_user()) {
if (Config::get('system', 'block_public') && !Session::isAuthenticated()) {
return;
}
@ -66,14 +63,14 @@ function photos_init(App $a) {
$vcard_widget = Renderer::replaceMacros($tpl, [
'$name' => $profile['name'],
'$photo' => $profile['photo'],
'$addr' => defaults($profile, 'addr', ''),
'$addr' => $profile['addr'] ?? '',
'$account_type' => $account_type,
'$pdesc' => defaults($profile, 'pdesc', ''),
'$pdesc' => $profile['pdesc'] ?? '',
]);
$albums = Photo::getAlbums($a->data['user']['uid']);
$albums_visible = ((intval($a->data['user']['hidewall']) && !local_user() && !remote_user()) ? false : true);
$albums_visible = ((intval($a->data['user']['hidewall']) && !Session::isAuthenticated()) ? false : true);
// add various encodings to the array so we can just loop through and pick them out in a template
$ret = ['success' => false];
@ -88,7 +85,7 @@ function photos_init(App $a) {
$ret['albums'] = [];
foreach ($albums as $k => $album) {
//hide profile photos to others
if (!$is_owner && !remote_user() && ($album['album'] == L10n::t('Profile Photos')))
if (!$is_owner && !Session::getRemoteContactID($a->profile_uid) && ($album['album'] == L10n::t('Profile Photos')))
continue;
$entry = [
'text' => $album['album'],
@ -154,25 +151,11 @@ function photos_post(App $a)
if (local_user() && (local_user() == $page_owner_uid)) {
$can_post = true;
} elseif ($community_page && remote_user()) {
$contact_id = 0;
if (!empty($_SESSION['remote']) && is_array($_SESSION['remote'])) {
foreach ($_SESSION['remote'] as $v) {
if ($v['uid'] == $page_owner_uid) {
$contact_id = $v['cid'];
break;
}
}
}
if ($contact_id > 0) {
if (DBA::exists('contact', ['id' => $contact_id, 'uid' => $page_owner_uid, 'blocked' => false, 'pending' => false])) {
} elseif ($community_page && !empty(Session::getRemoteContactID($page_owner_uid))) {
$contact_id = Session::getRemoteContactID($page_owner_uid);
$can_post = true;
$visitor = $contact_id;
}
}
}
if (!$can_post) {
notice(L10n::t('Permission denied.') . EOL);
@ -647,10 +630,10 @@ function photos_post(App $a)
$visible = 0;
}
$group_allow = defaults($_REQUEST, 'group_allow' , []);
$contact_allow = defaults($_REQUEST, 'contact_allow', []);
$group_deny = defaults($_REQUEST, 'group_deny' , []);
$contact_deny = defaults($_REQUEST, 'contact_deny' , []);
$group_allow = $_REQUEST['group_allow'] ?? [];
$contact_allow = $_REQUEST['contact_allow'] ?? [];
$group_deny = $_REQUEST['group_deny'] ?? [];
$contact_deny = $_REQUEST['contact_deny'] ?? [];
$str_group_allow = perms2str(is_array($group_allow) ? $group_allow : explode(',', $group_allow));
$str_contact_allow = perms2str(is_array($contact_allow) ? $contact_allow : explode(',', $contact_allow));
@ -683,7 +666,7 @@ function photos_post(App $a)
notice(L10n::t('Image exceeds size limit of %s', ini_get('upload_max_filesize')) . EOL);
break;
case UPLOAD_ERR_FORM_SIZE:
notice(L10n::t('Image exceeds size limit of %s', Strings::formatBytes(defaults($_REQUEST, 'MAX_FILE_SIZE', 0))) . EOL);
notice(L10n::t('Image exceeds size limit of %s', Strings::formatBytes($_REQUEST['MAX_FILE_SIZE'] ?? 0)) . EOL);
break;
case UPLOAD_ERR_PARTIAL:
notice(L10n::t('Image upload didn\'t complete, please try again') . EOL);
@ -846,7 +829,7 @@ function photos_content(App $a)
// photos/name/image/xxxxx/edit
// photos/name/image/xxxxx/drop
if (Config::get('system', 'block_public') && !local_user() && !remote_user()) {
if (Config::get('system', 'block_public') && !Session::isAuthenticated()) {
notice(L10n::t('Public access denied.') . EOL);
return;
}
@ -892,18 +875,8 @@ function photos_content(App $a)
if (local_user() && (local_user() == $owner_uid)) {
$can_post = true;
} else {
if ($community_page && remote_user()) {
if (is_array($_SESSION['remote'])) {
foreach ($_SESSION['remote'] as $v) {
if ($v['uid'] == $owner_uid) {
$contact_id = $v['cid'];
break;
}
}
}
if ($contact_id) {
} elseif ($community_page && !empty(Session::getRemoteContactID($owner_uid))) {
$contact_id = Session::getRemoteContactID($owner_uid);
$contact = DBA::selectFirst('contact', [], ['id' => $contact_id, 'uid' => $owner_uid, 'blocked' => false, 'pending' => false]);
if (DBA::isResult($contact)) {
@ -912,31 +885,15 @@ function photos_content(App $a)
$visitor = $contact_id;
}
}
}
}
$groups = [];
// perhaps they're visiting - but not a community page, so they wouldn't have write access
if (remote_user() && !$visitor) {
$contact_id = 0;
if (is_array($_SESSION['remote'])) {
foreach ($_SESSION['remote'] as $v) {
if ($v['uid'] == $owner_uid) {
$contact_id = $v['cid'];
break;
}
}
}
if ($contact_id) {
$groups = Group::getIdsByContactId($contact_id);
if (!empty(Session::getRemoteContactID($owner_uid)) && !$visitor) {
$contact_id = Session::getRemoteContactID($owner_uid);
$contact = DBA::selectFirst('contact', [], ['id' => $contact_id, 'uid' => $owner_uid, 'blocked' => false, 'pending' => false]);
$remote_contact = DBA::isResult($contact);
}
}
if (!$remote_contact && local_user()) {
$contact_id = $_SESSION['cid'];
@ -948,7 +905,7 @@ function photos_content(App $a)
return;
}
$sql_extra = Security::getPermissionsSQLByUserId($owner_uid, $remote_contact, $groups);
$sql_extra = Security::getPermissionsSQLByUserId($owner_uid);
$o = "";
@ -1049,7 +1006,7 @@ function photos_content(App $a)
$pager = new Pager($a->query_string, 20);
/// @TODO I have seen this many times, maybe generalize it script-wide and encapsulate it?
$order_field = defaults($_GET, 'order', '');
$order_field = $_GET['order'] ?? '';
if ($order_field === 'posted') {
$order = 'ASC';
} else {
@ -1201,7 +1158,7 @@ function photos_content(App $a)
* By now we hide it if someone wants to.
*/
if ($cmd === 'view' && !Config::get('system', 'no_count', false)) {
$order_field = defaults($_GET, 'order', '');
$order_field = $_GET['order'] ?? '';
if ($order_field === 'posted') {
$order = 'ASC';
@ -1607,7 +1564,7 @@ function photos_content(App $a)
$twist = false;
foreach ($r as $rr) {
//hide profile photos to others
if (!$is_owner && !remote_user() && ($rr['album'] == L10n::t('Profile Photos'))) {
if (!$is_owner && !Session::getRemoteContactID($owner_uid) && ($rr['album'] == L10n::t('Profile Photos'))) {
continue;
}

View file

@ -36,7 +36,7 @@ function poco_init(App $a) {
$system_mode = true;
}
$format = defaults($_GET, 'format', 'json');
$format = ($_GET['format'] ?? '') ?: 'json';
$justme = false;
$global = false;

View file

@ -594,7 +594,7 @@ function profiles_content(App $a) {
'$default' => (($is_default) ? '<p id="profile-edit-default-desc">' . L10n::t('This is your <strong>public</strong> profile.<br />It <strong>may</strong> be visible to anybody using the internet.') . '</p>' : ""),
'$name' => ['name', L10n::t('Your Full Name:'), $r[0]['name']],
'$pdesc' => ['pdesc', L10n::t('Title/Description:'), $r[0]['pdesc']],
'$dob' => Temporal::getDateofBirthField($r[0]['dob']),
'$dob' => Temporal::getDateofBirthField($r[0]['dob'], $a->user['timezone']),
'$hide_friends' => $hide_friends,
'$address' => ['address', L10n::t('Street Address:'), $r[0]['address']],
'$locality' => ['locality', L10n::t('Locality/City:'), $r[0]['locality']],

View file

@ -33,10 +33,10 @@ function pubsub_init(App $a)
$contact_id = (($a->argc > 2) ? intval($a->argv[2]) : 0 );
if ($_SERVER['REQUEST_METHOD'] === 'GET') {
$hub_mode = Strings::escapeTags(trim(defaults($_GET, 'hub_mode', '')));
$hub_topic = Strings::escapeTags(trim(defaults($_GET, 'hub_topic', '')));
$hub_challenge = Strings::escapeTags(trim(defaults($_GET, 'hub_challenge', '')));
$hub_verify = Strings::escapeTags(trim(defaults($_GET, 'hub_verify_token', '')));
$hub_mode = Strings::escapeTags(trim($_GET['hub_mode'] ?? ''));
$hub_topic = Strings::escapeTags(trim($_GET['hub_topic'] ?? ''));
$hub_challenge = Strings::escapeTags(trim($_GET['hub_challenge'] ?? ''));
$hub_verify = Strings::escapeTags(trim($_GET['hub_verify_token'] ?? ''));
Logger::log('Subscription from ' . $_SERVER['REMOTE_ADDR'] . ' Mode: ' . $hub_mode . ' Nick: ' . $nick);
Logger::log('Data: ' . print_r($_GET,true), Logger::DATA);

View file

@ -13,18 +13,18 @@ use Friendica\Util\Strings;
function redir_init(App $a) {
$url = defaults($_GET, 'url', '');
$url = $_GET['url'] ?? '';
$quiet = !empty($_GET['quiet']) ? '&quiet=1' : '';
$con_url = defaults($_GET, 'conurl', '');
if ($a->argc > 1 && intval($a->argv[1])) {
$cid = intval($a->argv[1]);
} elseif (local_user() && !empty($con_url)) {
$cid = Contact::getIdForURL($con_url, local_user());
} else {
$cid = 0;
}
// Try magic auth before the legacy stuff
redir_magic($a, $cid, $url);
if (!empty($cid)) {
$fields = ['id', 'uid', 'nurl', 'url', 'addr', 'name', 'network', 'poll', 'issued-id', 'dfrn-id', 'duplex', 'pending'];
$contact = DBA::selectFirst('contact', $fields, ['id' => $cid, 'uid' => [0, local_user()]]);
@ -35,10 +35,10 @@ function redir_init(App $a) {
$contact_url = $contact['url'];
if ((!local_user() && !remote_user()) // Visitors (not logged in or not remotes) can't authenticate.
if (!Session::isAuthenticated() // Visitors (not logged in or not remotes) can't authenticate.
|| (!empty($a->contact['id']) && $a->contact['id'] == $cid)) // Local user is already authenticated.
{
$a->redirect(defaults($url, $contact_url));
$a->redirect($url ?: $contact_url);
}
if ($contact['uid'] == 0 && local_user()) {
@ -52,7 +52,7 @@ function redir_init(App $a) {
if (!empty($a->contact['id']) && $a->contact['id'] == $cid) {
// Local user is already authenticated.
$target_url = defaults($url, $contact_url);
$target_url = $url ?: $contact_url;
Logger::log($contact['name'] . " is already authenticated. Redirecting to " . $target_url, Logger::DEBUG);
$a->redirect($target_url);
}
@ -66,34 +66,16 @@ function redir_init(App $a) {
// with the local contact. Otherwise the local user would ask the local contact
// for authentification everytime he/she is visiting a profile page of the local
// contact.
if ($host == $remotehost
&& !empty($_SESSION['remote'])
&& is_array($_SESSION['remote']))
{
foreach ($_SESSION['remote'] as $v) {
if (!empty($v['uid']) && !empty($v['cid']) &&
$v['uid'] == Session::get('visitor_visiting') &&
$v['cid'] == Session::get('visitor_id')) {
if (($host == $remotehost) && (Session::getRemoteContactID(Session::get('visitor_visiting')) == Session::get('visitor_id'))) {
// Remote user is already authenticated.
$target_url = defaults($url, $contact_url);
$target_url = $url ?: $contact_url;
Logger::log($contact['name'] . " is already authenticated. Redirecting to " . $target_url, Logger::DEBUG);
$a->redirect($target_url);
}
}
}
}
// When the remote page does support OWA, then we enforce the use of it
$basepath = Contact::getBasepath($contact_url);
if (Strings::compareLink($basepath, System::baseUrl())) {
$use_magic = true;
} else {
$serverret = Network::curl($basepath . '/magic');
$use_magic = $serverret->isSuccess();
}
// Doing remote auth with dfrn.
if (local_user() && !$use_magic && (!empty($contact['dfrn-id']) || !empty($contact['issued-id'])) && empty($contact['pending'])) {
if (local_user() && (!empty($contact['dfrn-id']) || !empty($contact['issued-id'])) && empty($contact['pending'])) {
$dfrn_id = $orig_id = (($contact['issued-id']) ? $contact['issued-id'] : $contact['dfrn-id']);
if ($contact['duplex'] && $contact['issued-id']) {
@ -119,7 +101,7 @@ function redir_init(App $a) {
. '&dfrn_version=' . DFRN_PROTOCOL_VERSION . '&type=profile&sec=' . $sec . $dest . $quiet);
}
$url = defaults($url, $contact_url);
$url = $url ?: $contact_url;
}
// If we don't have a connected contact, redirect with
@ -140,3 +122,46 @@ function redir_init(App $a) {
notice(L10n::t('Contact not found.'));
$a->internalRedirect();
}
function redir_magic($a, $cid, $url)
{
$visitor = Profile::getMyURL();
if (!empty($visitor)) {
Logger::info('Got my url', ['visitor' => $visitor]);
}
$contact = DBA::selectFirst('contact', ['url'], ['id' => $cid]);
if (!DBA::isResult($contact)) {
Logger::info('Contact not found', ['id' => $cid]);
// Shouldn't happen under normal conditions
notice(L10n::t('Contact not found.'));
if (!empty($url)) {
$a->redirect($url);
} else {
$a->internalRedirect();
}
} else {
$contact_url = $contact['url'];
$target_url = $url ?: $contact_url;
}
$basepath = Contact::getBasepath($contact_url);
// We don't use magic auth when there is no visitor, we are on the same system or we visit our own stuff
if (empty($visitor) || Strings::compareLink($basepath, System::baseUrl()) || Strings::compareLink($contact_url, $visitor)) {
Logger::info('Redirecting without magic', ['target' => $target_url, 'visitor' => $visitor, 'contact' => $contact_url]);
$a->redirect($target_url);
}
// Test for magic auth on the target system
$serverret = Network::curl($basepath . '/magic');
if ($serverret->isSuccess()) {
$separator = strpos($target_url, '?') ? '&' : '?';
$target_url .= $separator . 'zrl=' . urlencode($visitor) . '&addr=' . urlencode($contact_url);
Logger::info('Redirecting with magic', ['target' => $target_url, 'visitor' => $visitor, 'contact' => $contact_url]);
$a->redirect($target_url);
} else {
Logger::info('No magic for contact', ['contact' => $contact_url]);
}
}

View file

@ -44,7 +44,7 @@ function user_allow($hash)
$user,
Config::get('config', 'sitename'),
$a->getBaseUrl(),
defaults($register, 'password', 'Sent in a previous email')
($register['password'] ?? '') ?: 'Sent in a previous email'
);
L10n::popLang();

View file

@ -1,245 +0,0 @@
<?php
/**
* @file mod/search.php
*/
use Friendica\App;
use Friendica\Content\Nav;
use Friendica\Content\Pager;
use Friendica\Content\Text\HTML;
use Friendica\Core\Cache;
use Friendica\Core\Config;
use Friendica\Core\L10n;
use Friendica\Core\Logger;
use Friendica\Core\Renderer;
use Friendica\Database\DBA;
use Friendica\Model\Item;
use Friendica\Module\BaseSearchModule;
use Friendica\Util\Strings;
function search_saved_searches() {
$o = '';
$search = (!empty($_GET['search']) ? Strings::escapeTags(trim(rawurldecode($_GET['search']))) : '');
$r = q("SELECT `id`,`term` FROM `search` WHERE `uid` = %d",
intval(local_user())
);
if (DBA::isResult($r)) {
$saved = [];
foreach ($r as $rr) {
$saved[] = [
'id' => $rr['id'],
'term' => $rr['term'],
'encodedterm' => urlencode($rr['term']),
'delete' => L10n::t('Remove term'),
'selected' => ($search==$rr['term']),
];
}
$tpl = Renderer::getMarkupTemplate("saved_searches_aside.tpl");
$o .= Renderer::replaceMacros($tpl, [
'$title' => L10n::t('Saved Searches'),
'$add' => '',
'$searchbox' => '',
'$saved' => $saved,
]);
}
return $o;
}
function search_init(App $a) {
$search = (!empty($_GET['search']) ? Strings::escapeTags(trim(rawurldecode($_GET['search']))) : '');
if (local_user()) {
if (!empty($_GET['save']) && $search) {
$r = q("SELECT * FROM `search` WHERE `uid` = %d AND `term` = '%s' LIMIT 1",
intval(local_user()),
DBA::escape($search)
);
if (!DBA::isResult($r)) {
DBA::insert('search', ['uid' => local_user(), 'term' => $search]);
}
}
if (!empty($_GET['remove']) && $search) {
DBA::delete('search', ['uid' => local_user(), 'term' => $search]);
}
/// @todo Check if there is a case at all that "aside" is prefilled here
if (!isset($a->page['aside'])) {
$a->page['aside'] = '';
}
$a->page['aside'] .= search_saved_searches();
} else {
unset($_SESSION['theme']);
unset($_SESSION['mobile-theme']);
}
}
function search_content(App $a) {
if (Config::get('system','block_public') && !local_user() && !remote_user()) {
notice(L10n::t('Public access denied.') . EOL);
return;
}
if (Config::get('system','local_search') && !local_user() && !remote_user()) {
$e = new \Friendica\Network\HTTPException\ForbiddenException(L10n::t("Only logged in users are permitted to perform a search."));
$e->httpdesc = L10n::t("Public access denied.");
throw $e;
}
if (Config::get('system','permit_crawling') && !local_user() && !remote_user()) {
// Default values:
// 10 requests are "free", after the 11th only a call per minute is allowed
$free_crawls = intval(Config::get('system','free_crawls'));
if ($free_crawls == 0)
$free_crawls = 10;
$crawl_permit_period = intval(Config::get('system','crawl_permit_period'));
if ($crawl_permit_period == 0)
$crawl_permit_period = 10;
$remote = $_SERVER["REMOTE_ADDR"];
$result = Cache::get("remote_search:".$remote);
if (!is_null($result)) {
$resultdata = json_decode($result);
if (($resultdata->time > (time() - $crawl_permit_period)) && ($resultdata->accesses > $free_crawls)) {
throw new \Friendica\Network\HTTPException\TooManyRequestsException(L10n::t("Only one search per minute is permitted for not logged in users."));
}
Cache::set("remote_search:".$remote, json_encode(["time" => time(), "accesses" => $resultdata->accesses + 1]), Cache::HOUR);
} else
Cache::set("remote_search:".$remote, json_encode(["time" => time(), "accesses" => 1]), Cache::HOUR);
}
Nav::setSelected('search');
$search = (!empty($_REQUEST['search']) ? Strings::escapeTags(trim(rawurldecode($_REQUEST['search']))) : '');
$tag = false;
if (!empty($_GET['tag'])) {
$tag = true;
$search = (!empty($_GET['tag']) ? '#' . Strings::escapeTags(trim(rawurldecode($_GET['tag']))) : '');
}
// contruct a wrapper for the search header
$o = Renderer::replaceMacros(Renderer::getMarkupTemplate("content_wrapper.tpl"),[
'name' => "search-header",
'$title' => L10n::t("Search"),
'$title_size' => 3,
'$content' => HTML::search($search,'search-box','search', false)
]);
if (strpos($search,'#') === 0) {
$tag = true;
$search = substr($search,1);
}
if (strpos($search,'@') === 0) {
return BaseSearchModule::performSearch();
}
if (strpos($search,'!') === 0) {
return BaseSearchModule::performSearch();
}
if (parse_url($search, PHP_URL_SCHEME) != '') {
$id = Item::fetchByLink($search);
if (!empty($id)) {
$item = Item::selectFirst(['guid'], ['id' => $id]);
if (DBA::isResult($item)) {
$a->internalRedirect('display/' . $item['guid']);
}
}
}
if (!empty($_GET['search-option']))
switch($_GET['search-option']) {
case 'fulltext':
break;
case 'tags':
$tag = true;
break;
case 'contacts':
return BaseSearchModule::performSearch('@');
case 'forums':
return BaseSearchModule::performSearch('!');
}
if (!$search)
return $o;
if (Config::get('system','only_tag_search'))
$tag = true;
// Here is the way permissions work in the search module...
// Only public posts can be shown
// OR your own posts if you are a logged in member
// No items will be shown if the member has a blocked profile wall.
$pager = new Pager($a->query_string);
if ($tag) {
Logger::log("Start tag search for '".$search."'", Logger::DEBUG);
$condition = ["(`uid` = 0 OR (`uid` = ? AND NOT `global`))
AND `otype` = ? AND `type` = ? AND `term` = ?",
local_user(), TERM_OBJ_POST, TERM_HASHTAG, $search];
$params = ['order' => ['received' => true],
'limit' => [$pager->getStart(), $pager->getItemsPerPage()]];
$terms = DBA::select('term', ['oid'], $condition, $params);
$itemids = [];
while ($term = DBA::fetch($terms)) {
$itemids[] = $term['oid'];
}
DBA::close($terms);
if (!empty($itemids)) {
$params = ['order' => ['id' => true]];
$items = Item::selectForUser(local_user(), [], ['id' => $itemids], $params);
$r = Item::inArray($items);
} else {
$r = [];
}
} else {
Logger::log("Start fulltext search for '".$search."'", Logger::DEBUG);
$condition = ["(`uid` = 0 OR (`uid` = ? AND NOT `global`))
AND `body` LIKE CONCAT('%',?,'%')",
local_user(), $search];
$params = ['order' => ['id' => true],
'limit' => [$pager->getStart(), $pager->getItemsPerPage()]];
$items = Item::selectForUser(local_user(), [], $condition, $params);
$r = Item::inArray($items);
}
if (!DBA::isResult($r)) {
info(L10n::t('No results.') . EOL);
return $o;
}
if ($tag) {
$title = L10n::t('Items tagged with: %s', $search);
} else {
$title = L10n::t('Results for: %s', $search);
}
$o .= Renderer::replaceMacros(Renderer::getMarkupTemplate("section_title.tpl"),[
'$title' => $title
]);
Logger::log("Start Conversation for '".$search."'", Logger::DEBUG);
$o .= conversation($a, $r, $pager, 'search', false, false, 'commented', local_user());
$o .= $pager->renderMinimal(count($r));
Logger::log("Done '".$search."'", Logger::DEBUG);
return $o;
}

View file

@ -35,7 +35,7 @@ function get_theme_config_file($theme)
$theme = Strings::sanitizeFilePathItem($theme);
$a = \get_app();
$base_theme = defaults($a->theme_info, 'extends');
$base_theme = $a->theme_info['extends'] ?? '';
if (file_exists("view/theme/$theme/config.php")) {
return "view/theme/$theme/config.php";
@ -115,8 +115,8 @@ function settings_init(App $a)
$tabs[] = [
'label' => L10n::t('Delegations'),
'url' => 'delegate',
'selected' => (($a->argc == 1) && ($a->argv[0] === 'delegate')?'active':''),
'url' => 'settings/delegation',
'selected' => (($a->argc > 1) && ($a->argv[1] === 'delegation')?'active':''),
'accesskey' => 'd',
];
@ -180,11 +180,11 @@ function settings_post(App $a)
if (($a->argc > 2) && ($a->argv[1] === 'oauth') && ($a->argv[2] === 'edit'||($a->argv[2] === 'add')) && !empty($_POST['submit'])) {
BaseModule::checkFormSecurityTokenRedirectOnError('/settings/oauth', 'settings_oauth');
$name = defaults($_POST, 'name' , '');
$key = defaults($_POST, 'key' , '');
$secret = defaults($_POST, 'secret' , '');
$redirect = defaults($_POST, 'redirect', '');
$icon = defaults($_POST, 'icon' , '');
$name = $_POST['name'] ?? '';
$key = $_POST['key'] ?? '';
$secret = $_POST['secret'] ?? '';
$redirect = $_POST['redirect'] ?? '';
$icon = $_POST['icon'] ?? '';
if ($name == "" || $key == "" || $secret == "") {
notice(L10n::t("Missing some important data!"));
@ -241,24 +241,21 @@ function settings_post(App $a)
PConfig::set(local_user(), 'ostatus', 'default_group', $_POST['group-selection']);
PConfig::set(local_user(), 'ostatus', 'legacy_contact', $_POST['legacy_contact']);
} elseif (!empty($_POST['imap-submit'])) {
$mail_server = $_POST['mail_server'] ?? '';
$mail_port = $_POST['mail_port'] ?? '';
$mail_ssl = strtolower(trim($_POST['mail_ssl'] ?? ''));
$mail_user = $_POST['mail_user'] ?? '';
$mail_pass = trim($_POST['mail_pass'] ?? '');
$mail_action = trim($_POST['mail_action'] ?? '');
$mail_movetofolder = trim($_POST['mail_movetofolder'] ?? '');
$mail_replyto = $_POST['mail_replyto'] ?? '';
$mail_pubmail = $_POST['mail_pubmail'] ?? '';
$mail_server = defaults($_POST, 'mail_server', '');
$mail_port = defaults($_POST, 'mail_port', '');
$mail_ssl = (!empty($_POST['mail_ssl']) ? strtolower(trim($_POST['mail_ssl'])) : '');
$mail_user = defaults($_POST, 'mail_user', '');
$mail_pass = (!empty($_POST['mail_pass']) ? trim($_POST['mail_pass']) : '');
$mail_action = (!empty($_POST['mail_action']) ? trim($_POST['mail_action']) : '');
$mail_movetofolder = (!empty($_POST['mail_movetofolder']) ? trim($_POST['mail_movetofolder']) : '');
$mail_replyto = defaults($_POST, 'mail_replyto', '');
$mail_pubmail = defaults($_POST, 'mail_pubmail', '');
$mail_disabled = ((function_exists('imap_open') && (!Config::get('system', 'imap_disabled'))) ? 0 : 1);
if (Config::get('system', 'dfrn_only')) {
$mail_disabled = 1;
}
if (!$mail_disabled) {
if (
!Config::get('system', 'dfrn_only')
&& function_exists('imap_open')
&& !Config::get('system', 'imap_disabled')
) {
$failed = false;
$r = q("SELECT * FROM `mailacct` WHERE `uid` = %d LIMIT 1",
intval(local_user())
@ -1092,7 +1089,7 @@ function settings_content(App $a)
if (strlen(Config::get('system', 'directory'))) {
$profile_in_net_dir = Renderer::replaceMacros($opt_tpl, [
'$field' => ['profile_in_netdirectory', L10n::t('Publish your default profile in the global social directory?'), $profile['net-publish'], L10n::t('Your profile will be published in the global friendica directories (e.g. <a href="%s">%s</a>). Your profile will be visible in public.', Config::get('system', 'directory'), Config::get('system', 'directory')), [L10n::t('No'), L10n::t('Yes')]]
'$field' => ['profile_in_netdirectory', L10n::t('Publish your default profile in the global social directory?'), $profile['net-publish'], L10n::t('Your profile will be published in the global friendica directories (e.g. <a href="%s">%s</a>). Your profile will be visible in public.', Config::get('system', 'directory'), Config::get('system', 'directory')) . " " . L10n::t("This setting also determines whether Friendica will inform search engines that your profile should be indexed or not. Third-party search engines may or may not respect this setting."), [L10n::t('No'), L10n::t('Yes')]]
]);
} else {
$profile_in_net_dir = '';

View file

@ -6,6 +6,7 @@ use Friendica\App;
use Friendica\Core\Hook;
use Friendica\Core\L10n;
use Friendica\Core\Logger;
use Friendica\Core\Session;
use Friendica\Core\System;
use Friendica\Database\DBA;
use Friendica\Model\Item;
@ -15,7 +16,7 @@ use Friendica\Util\XML;
function subthread_content(App $a) {
if (!local_user() && !remote_user()) {
if (!Session::isAuthenticated()) {
return;
}

View file

@ -7,6 +7,7 @@ use Friendica\Core\Hook;
use Friendica\Core\L10n;
use Friendica\Core\Logger;
use Friendica\Core\System;
use Friendica\Core\Session;
use Friendica\Core\Worker;
use Friendica\Database\DBA;
use Friendica\Model\Item;
@ -16,7 +17,7 @@ use Friendica\Worker\Delivery;
function tagger_content(App $a) {
if (!local_user() && !remote_user()) {
if (!Session::isAuthenticated()) {
return;
}

View file

@ -22,11 +22,11 @@ function tagrm_post(App $a)
}
$tags = [];
foreach (defaults($_POST, 'tag', []) as $tag) {
foreach ($_POST['tag'] ?? [] as $tag) {
$tags[] = hex2bin(Strings::escapeTags(trim($tag)));
}
$item_id = defaults($_POST,'item', 0);
$item_id = $_POST['item'] ?? 0;
update_tags($item_id, $tags);
info(L10n::t('Tag(s) removed') . EOL);

View file

@ -41,14 +41,6 @@ function uimport_content(App $a)
}
}
if (!empty($_SESSION['theme'])) {
unset($_SESSION['theme']);
}
if (!empty($_SESSION['mobile-theme'])) {
unset($_SESSION['mobile-theme']);
}
$tpl = Renderer::getMarkupTemplate("uimport.tpl");
return Renderer::replaceMacros($tpl, [
'$regbutt' => L10n::t('Import'),

View file

@ -25,7 +25,7 @@ function unfollow_post(App $a)
}
$uid = local_user();
$url = Strings::escapeTags(trim(defaults($_REQUEST, 'url', '')));
$url = Strings::escapeTags(trim($_REQUEST['url'] ?? ''));
$condition = ["`uid` = ? AND (`rel` = ? OR `rel` = ?) AND (`nurl` = ? OR `alias` = ? OR `alias` = ?)",
$uid, Contact::SHARING, Contact::FRIEND, Strings::normaliseLink($url),

View file

@ -10,6 +10,7 @@ use Friendica\Core\Config;
use Friendica\Core\L10n;
use Friendica\Core\Renderer;
use Friendica\Core\System;
use Friendica\Core\Session;
use Friendica\Database\DBA;
use Friendica\Model\Attach;
use Friendica\Model\Contact;
@ -22,11 +23,7 @@ use Friendica\Util\Security;
function videos_init(App $a)
{
if ($a->argc > 1) {
DFRN::autoRedir($a, $a->argv[1]);
}
if ((Config::get('system', 'block_public')) && (!local_user()) && (!remote_user())) {
if (Config::get('system', 'block_public') && !Session::isAuthenticated()) {
return;
}
@ -54,9 +51,9 @@ function videos_init(App $a)
$vcard_widget = Renderer::replaceMacros($tpl, [
'$name' => $profile['name'],
'$photo' => $profile['photo'],
'$addr' => defaults($profile, 'addr', ''),
'$addr' => $profile['addr'] ?? '',
'$account_type' => $account_type,
'$pdesc' => defaults($profile, 'pdesc', ''),
'$pdesc' => $profile['pdesc'] ?? '',
]);
// If not there, create 'aside' empty
@ -114,7 +111,7 @@ function videos_content(App $a)
// videos/name/video/xxxxx/edit
if ((Config::get('system', 'block_public')) && (!local_user()) && (!remote_user())) {
if (Config::get('system', 'block_public') && !Session::isAuthenticated()) {
notice(L10n::t('Public access denied.') . EOL);
return;
}
@ -154,64 +151,25 @@ function videos_content(App $a)
if ((local_user()) && (local_user() == $owner_uid)) {
$can_post = true;
} elseif ($community_page && remote_user()) {
if (!empty($_SESSION['remote'])) {
foreach ($_SESSION['remote'] as $v) {
if ($v['uid'] == $owner_uid) {
$contact_id = $v['cid'];
break;
}
}
}
if ($contact_id > 0) {
$r = q("SELECT `uid` FROM `contact` WHERE `blocked` = 0 AND `pending` = 0 AND `id` = %d AND `uid` = %d LIMIT 1",
intval($contact_id),
intval($owner_uid)
);
if (DBA::isResult($r)) {
} elseif ($community_page && !empty(Session::getRemoteContactID($owner_uid))) {
$contact_id = Session::getRemoteContactID($owner_uid);
$can_post = true;
$remote_contact = true;
$visitor = $contact_id;
}
}
}
$groups = [];
// perhaps they're visiting - but not a community page, so they wouldn't have write access
if (remote_user() && (!$visitor)) {
$contact_id = 0;
if (!empty($_SESSION['remote'])) {
foreach($_SESSION['remote'] as $v) {
if($v['uid'] == $owner_uid) {
$contact_id = $v['cid'];
break;
}
}
}
if ($contact_id > 0) {
$groups = Group::getIdsByContactId($contact_id);
$r = q("SELECT * FROM `contact` WHERE `blocked` = 0 AND `pending` = 0 AND `id` = %d AND `uid` = %d LIMIT 1",
intval($contact_id),
intval($owner_uid)
);
if (DBA::isResult($r)) {
if (!empty(Session::getRemoteContactID($owner_uid)) && !$visitor) {
$contact_id = Session::getRemoteContactID($owner_uid);
$remote_contact = true;
}
}
}
if ($a->data['user']['hidewall'] && (local_user() != $owner_uid) && (!$remote_contact)) {
if ($a->data['user']['hidewall'] && (local_user() != $owner_uid) && !$remote_contact) {
notice(L10n::t('Access to this item is restricted.') . EOL);
return;
}
$sql_extra = Security::getPermissionsSQLByUserId($owner_uid, $remote_contact, $groups);
$sql_extra = Security::getPermissionsSQLByUserId($owner_uid);
$o = "";

View file

@ -6,6 +6,7 @@
use Friendica\App;
use Friendica\Core\Config;
use Friendica\Core\L10n;
use Friendica\Core\Session;
use Friendica\Database\DBA;
use Friendica\Model\Attach;
use Friendica\Model\User;
@ -43,22 +44,10 @@ function wall_attach_post(App $a) {
$page_owner_cid = $r[0]['id'];
$community_page = (($r[0]['page-flags'] == User::PAGE_FLAGS_COMMUNITY) ? true : false);
if ((local_user()) && (local_user() == $page_owner_uid)) {
if (local_user() && (local_user() == $page_owner_uid)) {
$can_post = true;
} else {
if ($community_page && remote_user()) {
$contact_id = 0;
if (is_array($_SESSION['remote'])) {
foreach ($_SESSION['remote'] as $v) {
if ($v['uid'] == $page_owner_uid) {
$contact_id = $v['cid'];
break;
}
}
}
if ($contact_id > 0) {
} elseif ($community_page && !empty(Session::getRemoteContactID($page_owner_uid))) {
$contact_id = Session::getRemoteContactID($page_owner_uid);
$r = q("SELECT `uid` FROM `contact` WHERE `blocked` = 0 AND `pending` = 0 AND `id` = %d AND `uid` = %d LIMIT 1",
intval($contact_id),
intval($page_owner_uid)
@ -68,8 +57,6 @@ function wall_attach_post(App $a) {
$can_post = true;
}
}
}
}
if (!$can_post) {
if ($r_json) {

View file

@ -12,6 +12,7 @@ use Friendica\App;
use Friendica\Core\L10n;
use Friendica\Core\Logger;
use Friendica\Core\System;
use Friendica\Core\Session;
use Friendica\Core\Config;
use Friendica\Database\DBA;
use Friendica\Model\Contact;
@ -74,19 +75,9 @@ function wall_upload_post(App $a, $desktopmode = true)
if ((local_user()) && (local_user() == $page_owner_uid)) {
$can_post = true;
} else {
if ($community_page && remote_user()) {
$contact_id = 0;
if (is_array($_SESSION['remote'])) {
foreach ($_SESSION['remote'] as $v) {
if ($v['uid'] == $page_owner_uid) {
$contact_id = $v['cid'];
break;
}
}
}
} elseif ($community_page && !empty(Session::getRemoteContactID($page_owner_uid))) {
$contact_id = Session::getRemoteContactID($page_owner_uid);
if ($contact_id) {
$r = q("SELECT `uid` FROM `contact`
WHERE `blocked` = 0 AND `pending` = 0
AND `id` = %d AND `uid` = %d LIMIT 1",
@ -98,9 +89,6 @@ function wall_upload_post(App $a, $desktopmode = true)
$visitor = $contact_id;
}
}
}
}
if (!$can_post) {
if ($r_json) {

View file

@ -131,8 +131,8 @@ function wallmessage_content(App $a) {
'$subject' => L10n::t('Subject:'),
'$recipname' => $user['username'],
'$nickname' => $user['nickname'],
'$subjtxt' => defaults($_REQUEST, 'subject', ''),
'$text' => defaults($_REQUEST, 'body', ''),
'$subjtxt' => $_REQUEST['subject'] ?? '',
'$text' => $_REQUEST['body'] ?? '',
'$readonly' => '',
'$yourmessage'=> L10n::t('Your message:'),
'$parent' => '',

View file

@ -102,8 +102,8 @@ $HTTP["scheme"] == "https" {
# Got the following 'Drupal Clean URL'after Mike suggested trying
# something along those lines, from http://drupal.org/node/1414950
url.rewrite-if-not-file = (
"^\/([^\?]*)\?(.*)$" => "/index.php?q=$1&$2",
"^\/(.*)$" => "/index.php?q=$1"
"^\/([^\?]*)\?(.*)$" => "/index.php?pagename=$1&$2",
"^\/(.*)$" => "/index.php?pagename=$1"
)
}
else $HTTP["host"] !~ "(friendica.example.com|wordpress.example.com)" {

View file

@ -92,10 +92,10 @@ class App
*/
private $baseURL;
/**
* @var string The name of the current theme
*/
/** @var string The name of the current theme */
private $currentTheme;
/** @var string The name of the current mobile theme */
private $currentMobileTheme;
/**
* @var Configuration The config
@ -450,10 +450,10 @@ class App
}
/**
* Returns the current theme name.
* Returns the current theme name. May be overriden by the mobile theme name.
*
* @return string the name of the current theme
* @throws HTTPException\InternalServerErrorException
* @return string
* @throws Exception
*/
public function getCurrentTheme()
{
@ -461,6 +461,16 @@ class App
return '';
}
// Specific mobile theme override
if (($this->mode->isMobile() || $this->mode->isTablet()) && Core\Session::get('show-mobile', true)) {
$user_mobile_theme = $this->getCurrentMobileTheme();
// --- means same mobile theme as desktop
if (!empty($user_mobile_theme) && $user_mobile_theme !== '---') {
return $user_mobile_theme;
}
}
if (!$this->currentTheme) {
$this->computeCurrentTheme();
}
@ -468,13 +478,37 @@ class App
return $this->currentTheme;
}
/**
* Returns the current mobile theme name.
*
* @return string
* @throws Exception
*/
public function getCurrentMobileTheme()
{
if ($this->mode->isInstall()) {
return '';
}
if (is_null($this->currentMobileTheme)) {
$this->computeCurrentMobileTheme();
}
return $this->currentMobileTheme;
}
public function setCurrentTheme($theme)
{
$this->currentTheme = $theme;
}
public function setCurrentMobileTheme($theme)
{
$this->currentMobileTheme = $theme;
}
/**
* Computes the current theme name based on the node settings, the user settings and the device type
* Computes the current theme name based on the node settings, the page owner settings and the user settings
*
* @throws Exception
*/
@ -486,7 +520,7 @@ class App
}
// Sane default
$this->currentTheme = $system_theme;
$this->setCurrentTheme($system_theme);
$page_theme = null;
// Find the theme that belongs to the user whose stuff we are looking at
@ -499,24 +533,7 @@ class App
}
}
$user_theme = Core\Session::get('theme', $system_theme);
// Specific mobile theme override
if (($this->is_mobile || $this->is_tablet) && Core\Session::get('show-mobile', true)) {
$system_mobile_theme = $this->config->get('system', 'mobile-theme');
$user_mobile_theme = Core\Session::get('mobile-theme', $system_mobile_theme);
// --- means same mobile theme as desktop
if (!empty($user_mobile_theme) && $user_mobile_theme !== '---') {
$user_theme = $user_mobile_theme;
}
}
if ($page_theme) {
$theme_name = $page_theme;
} else {
$theme_name = $user_theme;
}
$theme_name = $page_theme ?: Core\Session::get('theme', $system_theme);
$theme_name = Strings::sanitizeFilePathItem($theme_name);
if ($theme_name
@ -524,7 +541,40 @@ class App
&& (file_exists('view/theme/' . $theme_name . '/style.css')
|| file_exists('view/theme/' . $theme_name . '/style.php'))
) {
$this->currentTheme = $theme_name;
$this->setCurrentTheme($theme_name);
}
}
/**
* Computes the current mobile theme name based on the node settings, the page owner settings and the user settings
*/
private function computeCurrentMobileTheme()
{
$system_mobile_theme = $this->config->get('system', 'mobile-theme', '');
// Sane default
$this->setCurrentMobileTheme($system_mobile_theme);
$page_mobile_theme = null;
// Find the theme that belongs to the user whose stuff we are looking at
if ($this->profile_uid && ($this->profile_uid != local_user())) {
// Allow folks to override user themes and always use their own on their own site.
// This works only if the user is on the same server
if (!Core\PConfig::get(local_user(), 'system', 'always_my_theme')) {
$page_mobile_theme = Core\PConfig::get($this->profile_uid, 'system', 'mobile-theme');
}
}
$mobile_theme_name = $page_mobile_theme ?: Core\Session::get('mobile-theme', $system_mobile_theme);
$mobile_theme_name = Strings::sanitizeFilePathItem($mobile_theme_name);
if ($mobile_theme_name == '---'
||
in_array($mobile_theme_name, Theme::getAllowedList())
&& (file_exists('view/theme/' . $mobile_theme_name . '/style.css')
|| file_exists('view/theme/' . $mobile_theme_name . '/style.php'))
) {
$this->setCurrentMobileTheme($mobile_theme_name);
}
}
@ -534,7 +584,7 @@ class App
* Provide a sane default if nothing is chosen or the specified theme does not exist.
*
* @return string
* @throws HTTPException\InternalServerErrorException
* @throws Exception
*/
public function getCurrentThemeStylesheetPath()
{
@ -588,6 +638,10 @@ class App
* This probably should change to limit the size of this monster method.
*
* @param App\Module $module The determined module
* @param App\Router $router
* @param PConfiguration $pconfig
* @throws HTTPException\InternalServerErrorException
* @throws \ImagickException
*/
public function runFrontend(App\Module $module, App\Router $router, PConfiguration $pconfig)
{
@ -733,8 +787,7 @@ class App
$module = $module->determineClass($this->args, $router, $this->config);
// Let the module run it's internal process (init, get, post, ...)
$module->run($this->l10n, $this, $this->logger, $this->getCurrentTheme(), $_SERVER, $_POST);
$module->run($this->l10n, $this, $this->logger, $_SERVER, $_POST);
} catch (HTTPException $e) {
ModuleHTTPException::rawContent($e);
}

View file

@ -70,7 +70,7 @@ class Arguments
/**
* Returns the value of a argv key
* @todo there are a lot of $a->argv usages in combination with defaults() which can be replaced with this method
* @todo there are a lot of $a->argv usages in combination with ?? which can be replaced with this method
*
* @param int $position the position of the argument
* @param mixed $default the default value if not found

View file

@ -338,12 +338,12 @@ class BaseURL
/* Relative script path to the web server root
* Not all of those $_SERVER properties can be present, so we do by inverse priority order
*/
$relative_script_path = '';
$relative_script_path = defaults($this->server, 'REDIRECT_URL', $relative_script_path);
$relative_script_path = defaults($this->server, 'REDIRECT_URI', $relative_script_path);
$relative_script_path = defaults($this->server, 'REDIRECT_SCRIPT_URL', $relative_script_path);
$relative_script_path = defaults($this->server, 'SCRIPT_URL', $relative_script_path);
$relative_script_path = defaults($this->server, 'REQUEST_URI', $relative_script_path);
$relative_script_path =
($this->server['REDIRECT_URL'] ?? '') ?:
($this->server['REDIRECT_URI'] ?? '') ?:
($this->server['REDIRECT_SCRIPT_URL'] ?? '') ?:
($this->server['SCRIPT_URL'] ?? '') ?:
$this->server['REQUEST_URI'] ?? '';
/* $relative_script_path gives /relative/path/to/friendica/module/parameter
* QUERY_STRING gives pagename=module/parameter

View file

@ -106,15 +106,16 @@ class Mode
/**
* Checks if the site is called via a backend process
*
* @param bool $isBackend True, if the call is from a backend script (daemon, worker, ...)
* @param Module $module The pre-loaded module (just name, not class!)
* @param array $server The $_SERVER variable
* @param MobileDetect $mobileDetect The mobile detection library
*
* @return Mode returns the determined mode
*/
public function determineRunMode(Module $module, array $server, MobileDetect $mobileDetect)
public function determineRunMode(bool $isBackend, Module $module, array $server, MobileDetect $mobileDetect)
{
$isBackend = basename(($server['PHP_SELF'] ?? ''), '.php') !== 'index' ||
$isBackend = $isBackend ||
$module->isBackend();
$isMobile = $mobileDetect->isMobile();
$isTablet = $mobileDetect->isTablet();

View file

@ -7,7 +7,10 @@ use Friendica\BaseObject;
use Friendica\Core;
use Friendica\LegacyModule;
use Friendica\Module\Home;
use Friendica\Module\PageNotFound;
use Friendica\Module\HTTPException\MethodNotAllowed;
use Friendica\Module\HTTPException\PageNotFound;
use Friendica\Network\HTTPException\MethodNotAllowedException;
use Friendica\Network\HTTPException\NotFoundException;
use Psr\Log\LoggerInterface;
/**
@ -138,29 +141,26 @@ class Module
*
* @return Module The determined module of this call
*
* @throws \Friendica\Network\HTTPException\InternalServerErrorException
* @throws \Exception
*/
public function determineClass(Arguments $args, Router $router, Core\Config\Configuration $config)
{
$printNotAllowedAddon = false;
$module_class = null;
/**
* ROUTING
*
* From the request URL, routing consists of obtaining the name of a BaseModule-extending class of which the
* post() and/or content() static methods can be respectively called to produce a data change or an output.
**/
// First we try explicit routes defined in App\Router
$router->collectRoutes();
$data = $router->getRouteCollector();
Core\Hook::callAll('route_collection', $data);
try {
$module_class = $router->getModuleClass($args->getCommand());
} catch (MethodNotAllowedException $e) {
$module_class = MethodNotAllowed::class;
} catch (NotFoundException $e) {
// Then we try addon-provided modules that we wrap in the LegacyModule class
if (!$module_class && Core\Addon::isEnabled($this->module) && file_exists("addon/{$this->module}/{$this->module}.php")) {
if (Core\Addon::isEnabled($this->module) && file_exists("addon/{$this->module}/{$this->module}.php")) {
//Check if module is an app and if public access to apps is allowed or not
$privateapps = $config->get('config', 'private_addons', false);
if ((!local_user()) && Core\Hook::isAddonApp($this->module) && $privateapps) {
@ -182,7 +182,8 @@ class Module
$module_class = LegacyModule::class;
}
$module_class = !isset($module_class) ? PageNotFound::class : $module_class;
$module_class = $module_class ?: PageNotFound::class;
}
return new Module($this->module, $module_class, $this->isBackend, $printNotAllowedAddon);
}
@ -193,13 +194,12 @@ class Module
* @param Core\L10n\L10n $l10n The L10n instance
* @param App $app The whole Friendica app (for method arguments)
* @param LoggerInterface $logger The Friendica logger
* @param string $currentTheme The chosen theme
* @param array $server The $_SERVER variable
* @param array $post The $_POST variables
*
* @throws \Friendica\Network\HTTPException\InternalServerErrorException
*/
public function run(Core\L10n\L10n $l10n, App $app, LoggerInterface $logger, string $currentTheme, array $server, array $post)
public function run(Core\L10n\L10n $l10n, App $app, LoggerInterface $logger, array $server, array $post)
{
if ($this->printNotAllowedAddon) {
info($l10n->t("You must be logged in to use addons. "));
@ -239,17 +239,6 @@ class Module
// This endpoint doesn't need any theme initialization or other comparable stuff.
call_user_func([$this->module_class, 'rawContent']);
// Load current theme info after module has been initialized as theme could have been set in module
$theme_info_file = 'view/theme/' . $currentTheme . '/theme.php';
if (file_exists($theme_info_file)) {
require_once $theme_info_file;
}
if (function_exists(str_replace('-', '_', $currentTheme) . '_init')) {
$func = str_replace('-', '_', $currentTheme) . '_init';
$func($app);
}
if ($server['REQUEST_METHOD'] === 'POST') {
Core\Hook::callAll($this->module . '_mod_post', $post);
call_user_func([$this->module_class, 'post']);

View file

@ -364,6 +364,18 @@ class Page implements ArrayAccess
*/
$this->initContent($module, $mode);
// Load current theme info after module has been initialized as theme could have been set in module
$currentTheme = $app->getCurrentTheme();
$theme_info_file = 'view/theme/' . $currentTheme . '/theme.php';
if (file_exists($theme_info_file)) {
require_once $theme_info_file;
}
if (function_exists(str_replace('-', '_', $currentTheme) . '_init')) {
$func = str_replace('-', '_', $currentTheme) . '_init';
$func($app);
}
/* Create the page head after setting the language
* and getting any auth credentials.
*

View file

@ -7,7 +7,9 @@ use FastRoute\DataGenerator\GroupCountBased;
use FastRoute\Dispatcher;
use FastRoute\RouteCollector;
use FastRoute\RouteParser\Std;
use Friendica\Module;
use Friendica\Core\Hook;
use Friendica\Core\L10n;
use Friendica\Network\HTTPException;
/**
* Wrapper for FastRoute\Router
@ -21,212 +23,129 @@ use Friendica\Module;
*/
class Router
{
const POST = 'POST';
const GET = 'GET';
const ALLOWED_METHODS = [
self::POST,
self::GET,
];
/** @var RouteCollector */
protected $routeCollector;
/**
* Static declaration of Friendica routes.
*
* Supports:
* - Route groups
* - Variable parts
* Disregards:
* - HTTP method other than GET
* - Named parameters
*
* Handler must be the name of a class extending Friendica\BaseModule.
*
* @brief Static declaration of Friendica routes.
* @var string The HTTP method
*/
public function collectRoutes()
private $httpMethod;
/**
* @param array $server The $_SERVER variable
* @param RouteCollector|null $routeCollector Optional the loaded Route collector
*/
public function __construct(array $server, RouteCollector $routeCollector = null)
{
$this->routeCollector->addRoute(['GET'], '[/]', Module\Home::class);
$this->routeCollector->addGroup('/.well-known', function (RouteCollector $collector) {
$collector->addRoute(['GET'], '/host-meta' , Module\WellKnown\HostMeta::class);
$collector->addRoute(['GET'], '/nodeinfo[/1.0]' , Module\NodeInfo::class);
$collector->addRoute(['GET'], '/webfinger' , Module\Xrd::class);
$collector->addRoute(['GET'], '/x-social-relay' , Module\WellKnown\XSocialRelay::class);
});
$this->routeCollector->addGroup('/2fa', function (RouteCollector $collector) {
$collector->addRoute(['GET', 'POST'], '[/]' , Module\TwoFactor\Verify::class);
$collector->addRoute(['GET', 'POST'], '/recovery' , Module\TwoFactor\Recovery::class);
});
$this->routeCollector->addGroup('/admin', function (RouteCollector $collector) {
$collector->addRoute(['GET'] , '[/]' , Module\Admin\Summary::class);
$httpMethod = $server['REQUEST_METHOD'] ?? self::GET;
$this->httpMethod = in_array($httpMethod, self::ALLOWED_METHODS) ? $httpMethod : self::GET;
$collector->addRoute(['GET', 'POST'], '/addons' , Module\Admin\Addons\Index::class);
$collector->addRoute(['GET', 'POST'], '/addons/{addon}' , Module\Admin\Addons\Details::class);
$collector->addRoute(['GET', 'POST'], '/blocklist/contact' , Module\Admin\Blocklist\Contact::class);
$collector->addRoute(['GET', 'POST'], '/blocklist/server' , Module\Admin\Blocklist\Server::class);
$collector->addRoute(['GET'] , '/dbsync[/check]' , Module\Admin\DBSync::class);
$collector->addRoute(['GET'] , '/dbsync/{update:\d+}' , Module\Admin\DBSync::class);
$collector->addRoute(['GET'] , '/dbsync/mark/{update:\d+}', Module\Admin\DBSync::class);
$collector->addRoute(['GET', 'POST'], '/features' , Module\Admin\Features::class);
$collector->addRoute(['GET'] , '/federation' , Module\Admin\Federation::class);
$collector->addRoute(['GET', 'POST'], '/item/delete' , Module\Admin\Item\Delete::class);
$collector->addRoute(['GET', 'POST'], '/item/source[/{guid}]' , Module\Admin\Item\Source::class);
$collector->addRoute(['GET'] , '/logs/view' , Module\Admin\Logs\View::class);
$collector->addRoute(['GET', 'POST'], '/logs' , Module\Admin\Logs\Settings::class);
$collector->addRoute(['GET'] , '/phpinfo' , Module\Admin\PhpInfo::class);
$collector->addRoute(['GET'] , '/queue[/deferred]' , Module\Admin\Queue::class);
$collector->addRoute(['GET', 'POST'], '/site' , Module\Admin\Site::class);
$collector->addRoute(['GET', 'POST'], '/themes' , Module\Admin\Themes\Index::class);
$collector->addRoute(['GET', 'POST'], '/themes/{theme}' , Module\Admin\Themes\Details::class);
$collector->addRoute(['GET', 'POST'], '/themes/{theme}/embed' , Module\Admin\Themes\Embed::class);
$collector->addRoute(['GET', 'POST'], '/tos' , Module\Admin\Tos::class);
$collector->addRoute(['GET', 'POST'], '/users[/{action}/{uid}]' , Module\Admin\Users::class);
});
$this->routeCollector->addRoute(['GET'], '/amcd', Module\AccountManagementControlDocument::class);
$this->routeCollector->addRoute(['GET'], '/acctlink', Module\Acctlink::class);
$this->routeCollector->addRoute(['GET'], '/allfriends/{id:\d+}', Module\AllFriends::class);
$this->routeCollector->addRoute(['GET'], '/apps', Module\Apps::class);
$this->routeCollector->addRoute(['GET'], '/attach/{item:\d+}', Module\Attach::class);
$this->routeCollector->addRoute(['GET'], '/babel', Module\Debug\Babel::class);
$this->routeCollector->addRoute(['GET'], '/bookmarklet', Module\Bookmarklet::class);
$this->routeCollector->addRoute(['GET', 'POST'], '/compose[/{type}]', Module\Item\Compose::class);
$this->routeCollector->addGroup('/contact', function (RouteCollector $collector) {
$collector->addRoute(['GET'], '[/]', Module\Contact::class);
$collector->addRoute(['GET', 'POST'], '/{id:\d+}[/]', Module\Contact::class);
$collector->addRoute(['GET'], '/{id:\d+}/archive', Module\Contact::class);
$collector->addRoute(['GET'], '/{id:\d+}/block', Module\Contact::class);
$collector->addRoute(['GET'], '/{id:\d+}/conversations', Module\Contact::class);
$collector->addRoute(['GET'], '/{id:\d+}/drop', Module\Contact::class);
$collector->addRoute(['GET'], '/{id:\d+}/ignore', Module\Contact::class);
$collector->addRoute(['GET'], '/{id:\d+}/posts', Module\Contact::class);
$collector->addRoute(['GET'], '/{id:\d+}/update', Module\Contact::class);
$collector->addRoute(['GET'], '/{id:\d+}/updateprofile', Module\Contact::class);
$collector->addRoute(['GET'], '/archived', Module\Contact::class);
$collector->addRoute(['GET', 'POST'], '/batch', Module\Contact::class);
$collector->addRoute(['GET'], '/blocked', Module\Contact::class);
$collector->addRoute(['GET'], '/hidden', Module\Contact::class);
$collector->addRoute(['GET'], '/ignored', Module\Contact::class);
});
$this->routeCollector->addRoute(['GET'], '/credits', Module\Credits::class);
$this->routeCollector->addRoute(['GET'], '/dirfind', Module\Search\Directory::class);
$this->routeCollector->addRoute(['GET'], '/directory', Module\Directory::class);
$this->routeCollector->addGroup('/feed', function (RouteCollector $collector) {
$collector->addRoute(['GET'], '/{nickname}', Module\Feed::class);
$collector->addRoute(['GET'], '/{nickname}/posts', Module\Feed::class);
$collector->addRoute(['GET'], '/{nickname}/comments', Module\Feed::class);
$collector->addRoute(['GET'], '/{nickname}/replies', Module\Feed::class);
$collector->addRoute(['GET'], '/{nickname}/activity', Module\Feed::class);
});
$this->routeCollector->addRoute(['GET'], '/feedtest', Module\Debug\Feed::class);
$this->routeCollector->addGroup('/fetch', function (RouteCollector $collector) {
$collector->addRoute(['GET'], '/post/{guid}', Module\Diaspora\Fetch::class);
$collector->addRoute(['GET'], '/status_message/{guid}', Module\Diaspora\Fetch::class);
$collector->addRoute(['GET'], '/reshare/{guid}', Module\Diaspora\Fetch::class);
});
$this->routeCollector->addRoute(['GET'], '/filer[/{id:\d+}]', Module\Filer\SaveTag::class);
$this->routeCollector->addRoute(['GET'], '/filerm/{id:\d+}', Module\Filer\RemoveTag::class);
$this->routeCollector->addRoute(['GET', 'POST'], '/follow_confirm', Module\FollowConfirm::class);
$this->routeCollector->addRoute(['GET'], '/followers/{owner}', Module\Followers::class);
$this->routeCollector->addRoute(['GET'], '/following/{owner}', Module\Following::class);
$this->routeCollector->addRoute(['GET'], '/friendica[/json]', Module\Friendica::class);
$this->routeCollector->addGroup('/group', function (RouteCollector $collector) {
$collector->addRoute(['GET', 'POST'], '[/]', Module\Group::class);
$collector->addRoute(['GET', 'POST'], '/{group:\d+}', Module\Group::class);
$collector->addRoute(['GET', 'POST'], '/none', Module\Group::class);
$collector->addRoute(['GET', 'POST'], '/new', Module\Group::class);
$collector->addRoute(['GET', 'POST'], '/drop/{group:\d+}', Module\Group::class);
$collector->addRoute(['GET', 'POST'], '/{group:\d+}/{contact:\d+}', Module\Group::class);
$collector->addRoute(['GET', 'POST'], '/{group:\d+}/add/{contact:\d+}', Module\Group::class);
$collector->addRoute(['GET', 'POST'], '/{group:\d+}/remove/{contact:\d+}', Module\Group::class);
});
$this->routeCollector->addRoute(['GET'], '/hashtag', Module\Hashtag::class);
$this->routeCollector->addRoute(['GET'], '/home', Module\Home::class);
$this->routeCollector->addRoute(['GET'], '/help[/{doc:.+}]', Module\Help::class);
$this->routeCollector->addRoute(['GET'], '/inbox[/{nickname}]', Module\Inbox::class);
$this->routeCollector->addRoute(['GET', 'POST'], '/invite', Module\Invite::class);
$this->routeCollector->addGroup('/install', function (RouteCollector $collector) {
$collector->addRoute(['GET', 'POST'], '[/]', Module\Install::class);
$collector->addRoute(['GET'], '/testrewrite', Module\Install::class);
});
$this->routeCollector->addRoute(['GET'], '/like/{item:\d+}', Module\Like::class);
$this->routeCollector->addRoute(['GET', 'POST'], '/localtime', Module\Debug\Localtime::class);
$this->routeCollector->addRoute(['GET', 'POST'], '/login', Module\Login::class);
$this->routeCollector->addRoute(['GET', 'POST'], '/logout', Module\Logout::class);
$this->routeCollector->addRoute(['GET'], '/magic', Module\Magic::class);
$this->routeCollector->addRoute(['GET'], '/maintenance', Module\Maintenance::class);
$this->routeCollector->addRoute(['GET'], '/manifest', Module\Manifest::class);
$this->routeCollector->addRoute(['GET'], '/modexp/{nick}', Module\PublicRSAKey::class);
$this->routeCollector->addRoute(['GET'], '/newmember', Module\Welcome::class);
$this->routeCollector->addRoute(['GET'], '/nodeinfo/1.0', Module\NodeInfo::class);
$this->routeCollector->addRoute(['GET'], '/nogroup', Module\Group::class);
$this->routeCollector->addGroup('/notify', function (RouteCollector $collector) {
$collector->addRoute(['GET'], '[/]', Module\Notifications\Notify::class);
$collector->addRoute(['GET'], '/view/{id:\d+}', Module\Notifications\Notify::class);
$collector->addRoute(['GET'], '/mark/all', Module\Notifications\Notify::class);
});
$this->routeCollector->addRoute(['GET'], '/objects/{guid}', Module\Objects::class);
$this->routeCollector->addGroup('/oembed', function (RouteCollector $collector) {
$collector->addRoute(['GET'], '/b2h', Module\Oembed::class);
$collector->addRoute(['GET'], '/h2b', Module\Oembed::class);
$collector->addRoute(['GET'], '/{hash}', Module\Oembed::class);
});
$this->routeCollector->addRoute(['GET'], '/outbox/{owner}', Module\Outbox::class);
$this->routeCollector->addRoute(['GET'], '/owa', Module\Owa::class);
$this->routeCollector->addRoute(['GET'], '/opensearch', Module\OpenSearch::class);
$this->routeCollector->addGroup('/photo', function (RouteCollector $collector) {
$collector->addRoute(['GET'], '/{name}', Module\Photo::class);
$collector->addRoute(['GET'], '/{type}/{name}', Module\Photo::class);
$collector->addRoute(['GET'], '/{type}/{customize}/{name}', Module\Photo::class);
});
$this->routeCollector->addRoute(['GET'], '/pretheme', Module\ThemeDetails::class);
$this->routeCollector->addRoute(['GET'], '/probe', Module\Debug\Probe::class);
$this->routeCollector->addGroup('/profile', function (RouteCollector $collector) {
$collector->addRoute(['GET'], '/{nickname}', Module\Profile::class);
$collector->addRoute(['GET'], '/{nickname}/{to:\d{4}-\d{2}-\d{2}}/{from:\d{4}-\d{2}-\d{2}}', Module\Profile::class);
$collector->addRoute(['GET'], '/{nickname}/contacts[/{type}]', Module\Profile\Contacts::class);
$collector->addRoute(['GET'], '/{profile:\d+}/view', Module\Profile::class);
});
$this->routeCollector->addGroup('/proxy', function (RouteCollector $collector) {
$collector->addRoute(['GET'], '[/]' , Module\Proxy::class);
$collector->addRoute(['GET'], '/{url}' , Module\Proxy::class);
$collector->addRoute(['GET'], '/{sub1}/{url}' , Module\Proxy::class);
$collector->addRoute(['GET'], '/{sub1}/{sub2}/{url}' , Module\Proxy::class);
});
$this->routeCollector->addGroup('/settings', function (RouteCollector $collector) {
$collector->addGroup('/2fa', function (RouteCollector $collector) {
$collector->addRoute(['GET', 'POST'], '[/]' , Module\Settings\TwoFactor\Index::class);
$collector->addRoute(['GET', 'POST'], '/recovery' , Module\Settings\TwoFactor\Recovery::class);
$collector->addRoute(['GET', 'POST'], '/app_specific' , Module\Settings\TwoFactor\AppSpecific::class);
$collector->addRoute(['GET', 'POST'], '/verify' , Module\Settings\TwoFactor\Verify::class);
});
});
$this->routeCollector->addRoute(['GET'], '/randprof', Module\RandomProfile::class);
$this->routeCollector->addRoute(['GET', 'POST'], '/register', Module\Register::class);
$this->routeCollector->addRoute(['GET'], '/robots.txt', Module\RobotsTxt::class);
$this->routeCollector->addRoute(['GET'], '/rsd.xml', Module\ReallySimpleDiscovery::class);
$this->routeCollector->addRoute(['GET'], '/smilies[/json]', Module\Smilies::class);
$this->routeCollector->addRoute(['GET'], '/statistics.json', Module\Statistics::class);
$this->routeCollector->addRoute(['GET'], '/starred/{item:\d+}', Module\Starred::class);
$this->routeCollector->addRoute(['GET'], '/toggle_mobile', Module\ToggleMobile::class);
$this->routeCollector->addRoute(['GET'], '/tos', Module\Tos::class);
$this->routeCollector->addRoute(['GET'], '/view/theme/{theme}/style.pcss', Module\Theme::class);
$this->routeCollector->addRoute(['GET'], '/viewsrc/{item:\d+}', Module\Debug\ItemBody::class);
$this->routeCollector->addRoute(['GET'], '/webfinger', Module\Debug\WebFinger::class);
$this->routeCollector->addRoute(['GET'], '/xrd', Module\Xrd::class);
$this->routeCollector = isset($routeCollector) ?
$routeCollector :
new RouteCollector(new Std(), new GroupCountBased());
}
public function __construct()
/**
* @param array $routes The routes to add to the Router
*
* @return self The router instance with the loaded routes
*
* @throws HTTPException\InternalServerErrorException In case of invalid configs
*/
public function addRoutes(array $routes)
{
$this->routeCollector = new RouteCollector(new Std(), new GroupCountBased());
$routeCollector = (isset($this->routeCollector) ?
$this->routeCollector :
new RouteCollector(new Std(), new GroupCountBased()));
foreach ($routes as $route => $config) {
if ($this->isGroup($config)) {
$this->addGroup($route, $config, $routeCollector);
} elseif ($this->isRoute($config)) {
$routeCollector->addRoute($config[1], $route, $config[0]);
} else {
throw new HTTPException\InternalServerErrorException("Wrong route config for route '" . print_r($route, true) . "'");
}
}
$this->routeCollector = $routeCollector;
return $this;
}
/**
* Adds a group of routes to a given group
*
* @param string $groupRoute The route of the group
* @param array $routes The routes of the group
* @param RouteCollector $routeCollector The route collector to add this group
*/
private function addGroup(string $groupRoute, array $routes, RouteCollector $routeCollector)
{
$routeCollector->addGroup($groupRoute, function (RouteCollector $routeCollector) use ($routes) {
foreach ($routes as $route => $config) {
if ($this->isGroup($config)) {
$this->addGroup($route, $config, $routeCollector);
} elseif ($this->isRoute($config)) {
$routeCollector->addRoute($config[1], $route, $config[0]);
}else {
throw new HTTPException\InternalServerErrorException("Wrong route config for route '" . print_r($route, true) . "'");
}
}
});
}
/**
* Returns true in case the config is a group config
*
* @param array $config
*
* @return bool
*/
private function isGroup(array $config)
{
return
is_array($config) &&
is_string(array_keys($config)[0]) &&
// This entry should NOT be a BaseModule
(substr(array_keys($config)[0], 0, strlen('Friendica\Module')) !== 'Friendica\Module') &&
// The second argument is an array (another routes)
is_array(array_values($config)[0]);
}
/**
* Returns true in case the config is a route config
*
* @param array $config
*
* @return bool
*/
private function isRoute(array $config)
{
return
// The config array should at least have one entry
!empty($config[0]) &&
// This entry should be a BaseModule
(substr($config[0], 0, strlen('Friendica\Module')) === 'Friendica\Module') &&
// Either there is no other argument
(empty($config[1]) ||
// Or the second argument is an array (HTTP-Methods)
is_array($config[1]));
}
/**
* The current route collector
*
* @return RouteCollector|null
*/
public function getRouteCollector()
{
return $this->routeCollector;
@ -236,21 +155,31 @@ class Router
* Returns the relevant module class name for the given page URI or NULL if no route rule matched.
*
* @param string $cmd The path component of the request URL without the query string
* @return string|null A Friendica\BaseModule-extending class name if a route rule matched
*
* @return string A Friendica\BaseModule-extending class name if a route rule matched
*
* @throws HTTPException\InternalServerErrorException
* @throws HTTPException\MethodNotAllowedException If a rule matched but the method didn't
* @throws HTTPException\NotFoundException If no rule matched
*/
public function getModuleClass($cmd)
{
// Add routes from addons
Hook::callAll('route_collection', $this->routeCollector);
$cmd = '/' . ltrim($cmd, '/');
$dispatcher = new \FastRoute\Dispatcher\GroupCountBased($this->routeCollector->getData());
$moduleClass = null;
// @TODO: Enable method-specific modules
$httpMethod = 'GET';
$routeInfo = $dispatcher->dispatch($httpMethod, $cmd);
$routeInfo = $dispatcher->dispatch($this->httpMethod, $cmd);
if ($routeInfo[0] === Dispatcher::FOUND) {
$moduleClass = $routeInfo[1];
} elseif ($routeInfo[0] === Dispatcher::METHOD_NOT_ALLOWED) {
throw new HTTPException\MethodNotAllowedException(L10n::t('Method not allowed for this module. Allowed method(s): %s', implode(', ', $routeInfo[1])));
} else {
throw new HTTPException\NotFoundException(L10n::t('Page not found.'));
}
return $moduleClass;

View file

@ -4,7 +4,6 @@ namespace Friendica;
use Friendica\Core\L10n;
use Friendica\Core\Logger;
use Friendica\Core\System;
/**
* All modules in Friendica should extend BaseModule, although not all modules
@ -121,7 +120,7 @@ abstract class BaseModule extends BaseObject
$a = \get_app();
$x = explode('.', $hash);
if (time() > (IntVal($x[0]) + $max_livetime)) {
if (time() > (intval($x[0]) + $max_livetime)) {
return false;
}

View file

@ -129,16 +129,13 @@ HELP;
$config_file = $this->getOption(['f', 'file']);
if (!empty($config_file)) {
if ($config_file != 'config' . DIRECTORY_SEPARATOR . 'local.config.php') {
// Copy config file
$this->out("Copying config file...\n");
if (!copy($basePathConf . DIRECTORY_SEPARATOR . $config_file, $basePathConf . DIRECTORY_SEPARATOR . 'config' . DIRECTORY_SEPARATOR . 'local.config.php')) {
throw new RuntimeException("ERROR: Saving config file failed. Please copy '$config_file' to '" . $basePathConf . "'" . DIRECTORY_SEPARATOR . "config" . DIRECTORY_SEPARATOR . "local.config.php' manually.\n");
}
if (!file_exists($config_file)) {
throw new RuntimeException("ERROR: Config file does not exist.\n");
}
//reload the config cache
$loader = new ConfigFileLoader($basePathConf);
$loader = new ConfigFileLoader($config_file);
$loader->setupCache($configCache);
} else {
@ -219,6 +216,14 @@ HELP;
throw new RuntimeException($errorMessage);
}
if (!empty($config_file) && $config_file != 'config' . DIRECTORY_SEPARATOR . 'local.config.php') {
// Copy config file
$this->out("Copying config file...\n");
if (!copy($basePathConf . DIRECTORY_SEPARATOR . $config_file, $basePathConf . DIRECTORY_SEPARATOR . 'config' . DIRECTORY_SEPARATOR . 'local.config.php')) {
throw new RuntimeException("ERROR: Saving config file failed. Please copy '$config_file' to '" . $basePathConf . "'" . DIRECTORY_SEPARATOR . "config" . DIRECTORY_SEPARATOR . "local.config.php' manually.\n");
}
}
$this->out(" Complete!\n\n");
// Install theme

View file

@ -43,7 +43,7 @@ class ForumManager
$params = ['order' => ['name']];
}
$condition_str = "`network` = ? AND `uid` = ? AND NOT `blocked` AND NOT `pending` AND NOT `archive` AND ";
$condition_str = "`network` IN (?, ?) AND `uid` = ? AND NOT `blocked` AND NOT `pending` AND NOT `archive` AND ";
if ($showprivate) {
$condition_str .= '(`forum` OR `prv`)';
@ -58,7 +58,7 @@ class ForumManager
$forumlist = [];
$fields = ['id', 'url', 'name', 'micro', 'thumb'];
$condition = [$condition_str, Protocol::DFRN, $uid];
$condition = [$condition_str, Protocol::DFRN, Protocol::ACTIVITYPUB, $uid];
$contacts = DBA::select('contact', $fields, $condition, $params);
if (!$contacts) {
return($forumlist);

View file

@ -29,7 +29,7 @@ class Nav
'directory' => null,
'settings' => null,
'contacts' => null,
'manage' => null,
'delegation'=> null,
'events' => null,
'register' => null
];
@ -149,7 +149,7 @@ class Nav
$nav['usermenu'] = [];
$userinfo = null;
if (local_user() || remote_user()) {
if (Session::isAuthenticated()) {
$nav['logout'] = ['logout', L10n::t('Logout'), '', L10n::t('End this session')];
} else {
$nav['login'] = ['login', L10n::t('Login'), ($a->module == 'login' ? 'selected' : ''), L10n::t('Sign in')];
@ -182,7 +182,7 @@ class Nav
$nav['home'] = [$homelink, L10n::t('Home'), '', L10n::t('Home Page')];
}
if (intval(Config::get('config', 'register_policy')) === \Friendica\Module\Register::OPEN && !local_user() && !remote_user()) {
if (intval(Config::get('config', 'register_policy')) === \Friendica\Module\Register::OPEN && !Session::isAuthenticated()) {
$nav['register'] = ['register', L10n::t('Register'), '', L10n::t('Create an account')];
}
@ -257,11 +257,9 @@ class Nav
$nav['messages']['new'] = ['message/new', L10n::t('New Message'), '', L10n::t('New Message')];
if (is_array($a->identities) && count($a->identities) > 1) {
$nav['manage'] = ['manage', L10n::t('Manage'), '', L10n::t('Manage other pages')];
$nav['delegation'] = ['delegation', L10n::t('Delegation'), '', L10n::t('Manage other pages')];
}
$nav['delegations'] = ['delegate', L10n::t('Delegations'), '', L10n::t('Delegate Page Management')];
$nav['settings'] = ['settings', L10n::t('Settings'), '', L10n::t('Account settings')];
if (Feature::isEnabled(local_user(), 'multi_profiles')) {

View file

@ -39,7 +39,7 @@ class Pager
{
$this->setQueryString($queryString);
$this->setItemsPerPage($itemsPerPage);
$this->setPage(defaults($_GET, 'page', 1));
$this->setPage(($_GET['page'] ?? 0) ?: 1);
}
/**

View file

@ -38,7 +38,7 @@ class BBCode extends BaseObject
*
* @param string $body Message body
* @return array
* 'type' -> Message type ("link", "video", "photo")
* 'type' -> Message type ('link', 'video', 'photo')
* 'text' -> Text before the shared message
* 'after' -> Text after the shared message
* 'image' -> Preview image of the message
@ -56,19 +56,19 @@ class BBCode extends BaseObject
if (preg_match_all("(\[class=(.*?)\](.*?)\[\/class\])ism", $body, $attached, PREG_SET_ORDER)) {
foreach ($attached as $data) {
if (!in_array($data[1], ["type-link", "type-video", "type-photo"])) {
if (!in_array($data[1], ['type-link', 'type-video', 'type-photo'])) {
continue;
}
$post["type"] = substr($data[1], 5);
$post['type'] = substr($data[1], 5);
$pos = strpos($body, $data[0]);
if ($pos > 0) {
$post["text"] = trim(substr($body, 0, $pos));
$post["after"] = trim(substr($body, $pos + strlen($data[0])));
$post['text'] = trim(substr($body, 0, $pos));
$post['after'] = trim(substr($body, $pos + strlen($data[0])));
} else {
$post["text"] = trim(str_replace($data[0], "", $body));
$post["after"] = '';
$post['text'] = trim(str_replace($data[0], '', $body));
$post['after'] = '';
}
$attacheddata = $data[2];
@ -79,25 +79,25 @@ class BBCode extends BaseObject
if ($picturedata) {
if (($picturedata[0] >= 500) && ($picturedata[0] >= $picturedata[1])) {
$post["image"] = $matches[1];
$post['image'] = $matches[1];
} else {
$post["preview"] = $matches[1];
$post['preview'] = $matches[1];
}
}
}
if (preg_match("/\[bookmark\=(.*?)\](.*?)\[\/bookmark\]/ism", $attacheddata, $matches)) {
$post["url"] = $matches[1];
$post["title"] = $matches[2];
$post['url'] = $matches[1];
$post['title'] = $matches[2];
}
if (!empty($post["url"]) && (in_array($post["type"], ["link", "video"]))
if (!empty($post['url']) && (in_array($post['type'], ['link', 'video']))
&& preg_match("/\[url\=(.*?)\](.*?)\[\/url\]/ism", $attacheddata, $matches)) {
$post["url"] = $matches[1];
$post['url'] = $matches[1];
}
// Search for description
if (preg_match("/\[quote\](.*?)\[\/quote\]/ism", $attacheddata, $matches)) {
$post["description"] = $matches[1];
$post['description'] = $matches[1];
}
}
}
@ -109,7 +109,7 @@ class BBCode extends BaseObject
*
* @param string $body Message body
* @return array
* 'type' -> Message type ("link", "video", "photo")
* 'type' -> Message type ('link', 'video', 'photo')
* 'text' -> Text before the shared message
* 'after' -> Text after the shared message
* 'image' -> Preview image of the message
@ -136,9 +136,9 @@ class BBCode extends BaseObject
$attributes = $match[2];
$data["text"] = trim($match[1]);
$data['text'] = trim($match[1]);
$type = "";
$type = '';
preg_match("/type='(.*?)'/ism", $attributes, $matches);
if (!empty($matches[1])) {
$type = strtolower($matches[1]);
@ -149,19 +149,19 @@ class BBCode extends BaseObject
$type = strtolower($matches[1]);
}
if ($type == "") {
if ($type == '') {
return [];
}
if (!in_array($type, ["link", "audio", "photo", "video"])) {
if (!in_array($type, ['link', 'audio', 'photo', 'video'])) {
return [];
}
if ($type != "") {
$data["type"] = $type;
if ($type != '') {
$data['type'] = $type;
}
$url = "";
$url = '';
preg_match("/url='(.*?)'/ism", $attributes, $matches);
if (!empty($matches[1])) {
$url = $matches[1];
@ -172,11 +172,11 @@ class BBCode extends BaseObject
$url = $matches[1];
}
if ($url != "") {
$data["url"] = html_entity_decode($url, ENT_QUOTES, 'UTF-8');
if ($url != '') {
$data['url'] = html_entity_decode($url, ENT_QUOTES, 'UTF-8');
}
$title = "";
$title = '';
preg_match("/title='(.*?)'/ism", $attributes, $matches);
if (!empty($matches[1])) {
$title = $matches[1];
@ -187,14 +187,14 @@ class BBCode extends BaseObject
$title = $matches[1];
}
if ($title != "") {
if ($title != '') {
$title = self::convert(html_entity_decode($title, ENT_QUOTES, 'UTF-8'), false, true);
$title = html_entity_decode($title, ENT_QUOTES, 'UTF-8');
$title = str_replace(["[", "]"], ["&#91;", "&#93;"], $title);
$data["title"] = $title;
$title = str_replace(['[', ']'], ['&#91;', '&#93;'], $title);
$data['title'] = $title;
}
$image = "";
$image = '';
preg_match("/image='(.*?)'/ism", $attributes, $matches);
if (!empty($matches[1])) {
$image = $matches[1];
@ -205,11 +205,11 @@ class BBCode extends BaseObject
$image = $matches[1];
}
if ($image != "") {
$data["image"] = html_entity_decode($image, ENT_QUOTES, 'UTF-8');
if ($image != '') {
$data['image'] = html_entity_decode($image, ENT_QUOTES, 'UTF-8');
}
$preview = "";
$preview = '';
preg_match("/preview='(.*?)'/ism", $attributes, $matches);
if (!empty($matches[1])) {
$preview = $matches[1];
@ -220,13 +220,13 @@ class BBCode extends BaseObject
$preview = $matches[1];
}
if ($preview != "") {
$data["preview"] = html_entity_decode($preview, ENT_QUOTES, 'UTF-8');
if ($preview != '') {
$data['preview'] = html_entity_decode($preview, ENT_QUOTES, 'UTF-8');
}
$data["description"] = trim($match[3]);
$data['description'] = trim($match[3]);
$data["after"] = trim($match[4]);
$data['after'] = trim($match[4]);
return $data;
}
@ -244,7 +244,7 @@ class BBCode extends BaseObject
*/
$has_title = !empty($item['title']);
$plink = defaults($item, 'plink', '');
$plink = $item['plink'] ?? '';
$post = self::getAttachmentData($body);
// Get all linked images with alternative image description
@ -268,11 +268,11 @@ class BBCode extends BaseObject
}
// if nothing is found, it maybe having an image.
if (!isset($post["type"])) {
if (!isset($post['type'])) {
// Simplify image codes
$body = preg_replace("/\[img\=([0-9]*)x([0-9]*)\](.*?)\[\/img\]/ism", '[img]$3[/img]', $body);
$body = preg_replace("/\[img\=(.*?)\](.*?)\[\/img\]/ism", '[img]$1[/img]', $body);
$post["text"] = $body;
$post['text'] = $body;
if (preg_match_all("(\[url=(.*?)\]\s*\[img\](.*?)\[\/img\]\s*\[\/url\])ism", $body, $pictures, PREG_SET_ORDER)) {
if ((count($pictures) == 1) && !$has_title) {
@ -288,75 +288,75 @@ class BBCode extends BaseObject
// 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], true);
}
if ($data["type"] == "photo") {
$post["type"] = "photo";
if (isset($data["images"][0])) {
$post["image"] = $data["images"][0]["src"];
$post["url"] = $data["url"];
if ($data['type'] == 'photo') {
$post['type'] = 'photo';
if (isset($data['images'][0])) {
$post['image'] = $data['images'][0]['src'];
$post['url'] = $data['url'];
} else {
$post["image"] = $data["url"];
$post['image'] = $data['url'];
}
$post["preview"] = $pictures[0][2];
$post["text"] = trim(str_replace($pictures[0][0], "", $body));
$post['preview'] = $pictures[0][2];
$post['text'] = trim(str_replace($pictures[0][0], '', $body));
} else {
$imgdata = Image::getInfoFromURL($pictures[0][1]);
if ($imgdata && substr($imgdata["mime"], 0, 6) == "image/") {
$post["type"] = "photo";
$post["image"] = $pictures[0][1];
$post["preview"] = $pictures[0][2];
$post["text"] = trim(str_replace($pictures[0][0], "", $body));
if ($imgdata && substr($imgdata['mime'], 0, 6) == 'image/') {
$post['type'] = 'photo';
$post['image'] = $pictures[0][1];
$post['preview'] = $pictures[0][2];
$post['text'] = trim(str_replace($pictures[0][0], '', $body));
}
}
} elseif (count($pictures) > 0) {
$post["type"] = "link";
$post["url"] = $plink;
$post["image"] = $pictures[0][2];
$post["text"] = $body;
$post['type'] = 'link';
$post['url'] = $plink;
$post['image'] = $pictures[0][2];
$post['text'] = $body;
foreach ($pictures as $picture) {
$post["text"] = trim(str_replace($picture[0], "", $post["text"]));
$post['text'] = trim(str_replace($picture[0], '', $post['text']));
}
}
} elseif (preg_match_all("(\[img\](.*?)\[\/img\])ism", $body, $pictures, PREG_SET_ORDER)) {
if ((count($pictures) == 1) && !$has_title) {
$post["type"] = "photo";
$post["image"] = $pictures[0][1];
$post["text"] = str_replace($pictures[0][0], "", $body);
$post['type'] = 'photo';
$post['image'] = $pictures[0][1];
$post['text'] = str_replace($pictures[0][0], '', $body);
} elseif (count($pictures) > 0) {
$post["type"] = "link";
$post["url"] = $plink;
$post["image"] = $pictures[0][1];
$post["text"] = $body;
$post['type'] = 'link';
$post['url'] = $plink;
$post['image'] = $pictures[0][1];
$post['text'] = $body;
foreach ($pictures as $picture) {
$post["text"] = trim(str_replace($picture[0], "", $post["text"]));
$post['text'] = trim(str_replace($picture[0], '', $post['text']));
}
}
}
// Test for the external links
preg_match_all("(\[url\](.*?)\[\/url\])ism", $post["text"], $links1, PREG_SET_ORDER);
preg_match_all("(\[url\=(.*?)\].*?\[\/url\])ism", $post["text"], $links2, PREG_SET_ORDER);
preg_match_all("(\[url\](.*?)\[\/url\])ism", $post['text'], $links1, PREG_SET_ORDER);
preg_match_all("(\[url\=(.*?)\].*?\[\/url\])ism", $post['text'], $links2, PREG_SET_ORDER);
$links = array_merge($links1, $links2);
// If there is only a single one, then use it.
// This should cover link posts via API.
if ((count($links) == 1) && !isset($post["preview"]) && !$has_title) {
$post["type"] = "link";
$post["url"] = $links[0][1];
if ((count($links) == 1) && !isset($post['preview']) && !$has_title) {
$post['type'] = 'link';
$post['url'] = $links[0][1];
}
// Now count the number of external media links
preg_match_all("(\[vimeo\](.*?)\[\/vimeo\])ism", $post["text"], $links1, PREG_SET_ORDER);
preg_match_all("(\[youtube\\](.*?)\[\/youtube\\])ism", $post["text"], $links2, PREG_SET_ORDER);
preg_match_all("(\[video\\](.*?)\[\/video\\])ism", $post["text"], $links3, PREG_SET_ORDER);
preg_match_all("(\[audio\\](.*?)\[\/audio\\])ism", $post["text"], $links4, PREG_SET_ORDER);
preg_match_all("(\[vimeo\](.*?)\[\/vimeo\])ism", $post['text'], $links1, PREG_SET_ORDER);
preg_match_all("(\[youtube\\](.*?)\[\/youtube\\])ism", $post['text'], $links2, PREG_SET_ORDER);
preg_match_all("(\[video\\](.*?)\[\/video\\])ism", $post['text'], $links3, PREG_SET_ORDER);
preg_match_all("(\[audio\\](.*?)\[\/audio\\])ism", $post['text'], $links4, PREG_SET_ORDER);
// Add them to the other external links
$links = array_merge($links, $links1, $links2, $links3, $links4);
@ -364,19 +364,19 @@ class BBCode extends BaseObject
// Are there more than one?
if (count($links) > 1) {
// The post will be the type "text", which means a blog post
unset($post["type"]);
$post["url"] = $plink;
unset($post['type']);
$post['url'] = $plink;
}
if (!isset($post["type"])) {
$post["type"] = "text";
$post["text"] = trim($body);
if (!isset($post['type'])) {
$post['type'] = "text";
$post['text'] = trim($body);
}
} elseif (isset($post["url"]) && ($post["type"] == "video")) {
$data = ParseUrl::getSiteinfoCached($post["url"], true);
} elseif (isset($post['url']) && ($post['type'] == 'video')) {
$data = ParseUrl::getSiteinfoCached($post['url'], true);
if (isset($data["images"][0])) {
$post["image"] = $data["images"][0]["src"];
if (isset($data['images'][0])) {
$post['image'] = $data['images'][0]['src'];
}
}
@ -581,27 +581,27 @@ class BBCode extends BaseObject
private static function convertAttachment($return, $simplehtml = false, $tryoembed = true)
{
$data = self::getAttachmentData($return);
if (empty($data) || empty($data["url"])) {
if (empty($data) || empty($data['url'])) {
return $return;
}
if (isset($data["title"])) {
$data["title"] = strip_tags($data["title"]);
$data["title"] = str_replace(["http://", "https://"], "", $data["title"]);
if (isset($data['title'])) {
$data['title'] = strip_tags($data['title']);
$data['title'] = str_replace(['http://', 'https://'], '', $data['title']);
} else {
$data["title"] = null;
$data['title'] = null;
}
if (((strpos($data["text"], "[img=") !== false) || (strpos($data["text"], "[img]") !== false) || Config::get('system', 'always_show_preview')) && !empty($data["image"])) {
$data["preview"] = $data["image"];
$data["image"] = "";
if (((strpos($data['text'], "[img=") !== false) || (strpos($data['text'], "[img]") !== false) || Config::get('system', 'always_show_preview')) && !empty($data['image'])) {
$data['preview'] = $data['image'];
$data['image'] = '';
}
$return = '';
if (in_array($simplehtml, [7, 9])) {
$return = self::convertUrlForOStatus($data["url"]);
$return = self::convertUrlForActivityPub($data['url']);
} elseif (($simplehtml != 4) && ($simplehtml != 0)) {
$return = sprintf('<a href="%s" target="_blank">%s</a><br>', $data["url"], $data["title"]);
$return = sprintf('<a href="%s" target="_blank">%s</a><br>', $data['url'], $data['title']);
} else {
try {
if ($tryoembed && OEmbed::isAllowedURL($data['url'])) {
@ -610,28 +610,28 @@ class BBCode extends BaseObject
throw new Exception('OEmbed is disabled for this attachment.');
}
} catch (Exception $e) {
$data["title"] = defaults($data, 'title', $data['url']);
$data['title'] = ($data['title'] ?? '') ?: $data['url'];
if ($simplehtml != 4) {
$return = sprintf('<div class="type-%s">', $data["type"]);
$return = sprintf('<div class="type-%s">', $data['type']);
}
if (!empty($data['title']) && !empty($data['url'])) {
if (!empty($data["image"]) && empty($data["text"]) && ($data["type"] == "photo")) {
$return .= sprintf('<a href="%s" target="_blank"><img src="%s" alt="" title="%s" class="attachment-image" /></a>', $data["url"], self::proxyUrl($data["image"], $simplehtml), $data["title"]);
if (!empty($data['image']) && empty($data['text']) && ($data['type'] == 'photo')) {
$return .= sprintf('<a href="%s" target="_blank"><img src="%s" alt="" title="%s" class="attachment-image" /></a>', $data['url'], self::proxyUrl($data['image'], $simplehtml), $data['title']);
} else {
if (!empty($data["image"])) {
$return .= sprintf('<a href="%s" target="_blank"><img src="%s" alt="" title="%s" class="attachment-image" /></a><br />', $data["url"], self::proxyUrl($data["image"], $simplehtml), $data["title"]);
} elseif (!empty($data["preview"])) {
$return .= sprintf('<a href="%s" target="_blank"><img src="%s" alt="" title="%s" class="attachment-preview" /></a><br />', $data["url"], self::proxyUrl($data["preview"], $simplehtml), $data["title"]);
if (!empty($data['image'])) {
$return .= sprintf('<a href="%s" target="_blank"><img src="%s" alt="" title="%s" class="attachment-image" /></a><br />', $data['url'], self::proxyUrl($data['image'], $simplehtml), $data['title']);
} elseif (!empty($data['preview'])) {
$return .= sprintf('<a href="%s" target="_blank"><img src="%s" alt="" title="%s" class="attachment-preview" /></a><br />', $data['url'], self::proxyUrl($data['preview'], $simplehtml), $data['title']);
}
$return .= sprintf('<h4><a href="%s">%s</a></h4>', $data['url'], $data['title']);
}
}
if (!empty($data["description"]) && $data["description"] != $data["title"]) {
if (!empty($data['description']) && $data['description'] != $data['title']) {
// Sanitize the HTML by converting it to BBCode
$bbcode = HTML::toBBCode($data["description"]);
$bbcode = HTML::toBBCode($data['description']);
$return .= sprintf('<blockquote>%s</blockquote>', trim(self::convert($bbcode)));
}
@ -645,7 +645,7 @@ class BBCode extends BaseObject
}
}
return trim(defaults($data, 'text', '') . ' ' . $return . ' ' . defaults($data, 'after', ''));
return trim(($data['text'] ?? '') . ' ' . $return . ' ' . ($data['after'] ?? ''));
}
public static function removeShareInformation($Text, $plaintext = false, $nolink = false)
@ -655,36 +655,36 @@ class BBCode extends BaseObject
if (!$data) {
return $Text;
} elseif ($nolink) {
return $data["text"] . defaults($data, 'after', '');
return $data['text'] . ($data['after'] ?? '');
}
$title = htmlentities(defaults($data, 'title', ''), ENT_QUOTES, 'UTF-8', false);
$text = htmlentities($data["text"], ENT_QUOTES, 'UTF-8', false);
if ($plaintext || (($title != "") && strstr($text, $title))) {
$data["title"] = $data["url"];
} elseif (($text != "") && strstr($title, $text)) {
$data["text"] = $data["title"];
$data["title"] = $data["url"];
$title = htmlentities($data['title'] ?? '', ENT_QUOTES, 'UTF-8', false);
$text = htmlentities($data['text'], ENT_QUOTES, 'UTF-8', false);
if ($plaintext || (($title != '') && strstr($text, $title))) {
$data['title'] = $data['url'];
} elseif (($text != '') && strstr($title, $text)) {
$data['text'] = $data['title'];
$data['title'] = $data['url'];
}
if (empty($data["text"]) && !empty($data["title"]) && empty($data["url"])) {
return $data["title"] . $data["after"];
if (empty($data['text']) && !empty($data['title']) && empty($data['url'])) {
return $data['title'] . $data['after'];
}
// If the link already is included in the post, don't add it again
if (!empty($data["url"]) && strpos($data["text"], $data["url"])) {
return $data["text"] . $data["after"];
if (!empty($data['url']) && strpos($data['text'], $data['url'])) {
return $data['text'] . $data['after'];
}
$text = $data["text"];
$text = $data['text'];
if (!empty($data["url"]) && !empty($data["title"])) {
$text .= "\n[url=" . $data["url"] . "]" . $data["title"] . "[/url]";
} elseif (!empty($data["url"])) {
$text .= "\n[url]" . $data["url"] . "[/url]";
if (!empty($data['url']) && !empty($data['title'])) {
$text .= "\n[url=" . $data['url'] . ']' . $data['title'] . '[/url]';
} elseif (!empty($data['url'])) {
$text .= "\n[url]" . $data['url'] . '[/url]';
}
return $text . "\n" . $data["after"];
return $text . "\n" . $data['after'];
}
/**
@ -694,7 +694,7 @@ class BBCode extends BaseObject
* @param array $match Array with the matching values
* @return string reformatted link including HTML codes
*/
private static function convertUrlForOStatusCallback($match)
private static function convertUrlForActivityPubCallback($match)
{
$url = $match[1];
@ -707,15 +707,26 @@ class BBCode extends BaseObject
return $match[0];
}
return self::convertUrlForOStatus($url);
return self::convertUrlForActivityPub($url);
}
/**
* @brief Converts [url] BBCodes in a format that looks fine on OStatus systems.
* @brief Converts [url] BBCodes in a format that looks fine on ActivityPub systems.
* @param string $url URL that is about to be reformatted
* @return string reformatted link including HTML codes
*/
private static function convertUrlForOStatus($url)
private static function convertUrlForActivityPub($url)
{
$html = '<a href="%s" target="_blank">%s</a>';
return sprintf($html, $url, self::getStyledURL($url));
}
/**
* Converts an URL in a nicer format (without the scheme and possibly shortened)
* @param string $url URL that is about to be reformatted
* @return string reformatted link
*/
private static function getStyledURL($url)
{
$parts = parse_url($url);
$scheme = $parts['scheme'] . '://';
@ -725,9 +736,7 @@ class BBCode extends BaseObject
$styled_url = substr($styled_url, 0, 30) . "";
}
$html = '<a href="%s" target="_blank">%s</a>';
return sprintf($html, $url, $styled_url);
return $styled_url;
}
/*
@ -932,7 +941,7 @@ class BBCode extends BaseObject
$attributes = [];
foreach(['author', 'profile', 'avatar', 'link', 'posted'] as $field) {
preg_match("/$field=(['\"])(.+?)\\1/ism", $attribute_string, $matches);
$attributes[$field] = html_entity_decode(defaults($matches, 2, ''), ENT_QUOTES, 'UTF-8');
$attributes[$field] = html_entity_decode($matches[2] ?? '', ENT_QUOTES, 'UTF-8');
}
// We only call this so that a previously unknown contact can be added.
@ -951,11 +960,11 @@ class BBCode extends BaseObject
Contact::getIdForURL($attributes['profile'], 0, true, $default);
$author_contact = Contact::getDetailsByURL($attributes['profile']);
$author_contact['addr'] = defaults($author_contact, 'addr' , Protocol::getAddrFromProfileUrl($attributes['profile']));
$author_contact['addr'] = ($author_contact['addr'] ?? '') ?: Protocol::getAddrFromProfileUrl($attributes['profile']);
$attributes['author'] = defaults($author_contact, 'name' , $attributes['author']);
$attributes['avatar'] = defaults($author_contact, 'micro', $attributes['avatar']);
$attributes['profile'] = defaults($author_contact, 'url' , $attributes['profile']);
$attributes['author'] = ($author_contact['name'] ?? '') ?: $attributes['author'];
$attributes['avatar'] = ($author_contact['micro'] ?? '') ?: $attributes['avatar'];
$attributes['profile'] = ($author_contact['url'] ?? '') ?: $attributes['profile'];
if ($attributes['avatar']) {
$attributes['avatar'] = ProxyUtils::proxifyUrl($attributes['avatar'], false, ProxyUtils::SIZE_THUMB);
@ -1056,7 +1065,8 @@ class BBCode extends BaseObject
private static function removePictureLinksCallback($match)
{
$text = Cache::get($match[1]);
$cache_key = 'remove:' . $match[1];
$text = Cache::get($cache_key);
if (is_null($text)) {
$a = self::getApp();
@ -1072,10 +1082,10 @@ class BBCode extends BaseObject
$a->getProfiler()->saveTimestamp($stamp1, "network", System::callstack());
if (substr($curl_info["content_type"], 0, 6) == "image/") {
$text = "[url=" . $match[1] . "]" . $match[1] . "[/url]";
if (substr($curl_info['content_type'], 0, 6) == 'image/') {
$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 = Network::fetchUrl($match[1]);
@ -1093,12 +1103,12 @@ class BBCode extends BaseObject
}
}
if (strtolower($attr["name"]) == "twitter:image") {
$text = "[url=" . $attr["content"] . "]" . $attr["content"] . "[/url]";
if (strtolower($attr['name']) == 'twitter:image') {
$text = '[url=' . $attr['content'] . ']' . $attr['content'] . '[/url]';
}
}
}
Cache::set($match[1], $text);
Cache::set($cache_key, $text);
}
return $text;
@ -1106,7 +1116,7 @@ class BBCode extends BaseObject
private static function expandLinksCallback($match)
{
if (($match[3] == "") || ($match[2] == $match[3]) || stristr($match[2], $match[3])) {
if (($match[3] == '') || ($match[2] == $match[3]) || stristr($match[2], $match[3])) {
return ($match[1] . "[url]" . $match[2] . "[/url]");
} else {
return ($match[1] . $match[3] . " [url]" . $match[2] . "[/url]");
@ -1115,11 +1125,26 @@ class BBCode extends BaseObject
private static function cleanPictureLinksCallback($match)
{
$text = Cache::get($match[1]);
if (is_null($text)) {
$a = self::getApp();
// When the picture link is the own photo path then we can avoid fetching the link
$own_photo_url = preg_quote(Strings::normaliseLink($a->getBaseURL()) . '/photos/');
if (preg_match('|' . $own_photo_url . '.*?/image/|', Strings::normaliseLink($match[1]))) {
if (!empty($match[3])) {
$text = '[img=' . str_replace('-1.', '-0.', $match[2]) . ']' . $match[3] . '[/img]';
} else {
$text = '[img]' . str_replace('-1.', '-0.', $match[2]) . '[/img]';
}
return $text;
}
$cache_key = 'clean:' . $match[1];
$text = Cache::get($cache_key);
if (!is_null($text)) {
return $text;
}
// Only fetch the header, not the content
$stamp1 = microtime(true);
$ch = @curl_init($match[1]);
@ -1132,13 +1157,13 @@ class BBCode extends BaseObject
$a->getProfiler()->saveTimestamp($stamp1, "network", System::callstack());
// if its a link to a picture then embed this picture
if (substr($curl_info["content_type"], 0, 6) == "image/") {
$text = "[img]" . $match[1] . "[/img]";
if (substr($curl_info['content_type'], 0, 6) == 'image/') {
$text = '[img]' . $match[1] . '[/img]';
} else {
if (!empty($match[3])) {
$text = "[img=" . $match[2] . "]" . $match[3] . "[/img]";
$text = '[img=' . $match[2] . ']' . $match[3] . '[/img]';
} else {
$text = "[img]" . $match[2] . "[/img]";
$text = '[img]' . $match[2] . '[/img]';
}
// if its not a picture then look if its a page that contains a picture link
@ -1156,17 +1181,16 @@ class BBCode extends BaseObject
}
}
if (strtolower($attr["name"]) == "twitter:image") {
if (strtolower($attr['name']) == "twitter:image") {
if (!empty($match[3])) {
$text = "[img=" . $attr["content"] . "]" . $match[3] . "[/img]";
$text = "[img=" . $attr['content'] . "]" . $match[3] . "[/img]";
} else {
$text = "[img]" . $attr["content"] . "[/img]";
$text = "[img]" . $attr['content'] . "[/img]";
}
}
}
}
Cache::set($match[1], $text);
}
Cache::set($cache_key, $text);
return $text;
}
@ -1217,7 +1241,7 @@ class BBCode extends BaseObject
$try_oembed_callback = function ($match)
{
$url = $match[1];
$title = defaults($match, 2, null);
$title = $match[2] ?? null;
try {
$return = OEmbed::getHTML($url, $title);
@ -1318,7 +1342,7 @@ class BBCode extends BaseObject
$text = str_replace($search, $replace, $text);
// removing multiplicated newlines
if (Config::get("system", "remove_multiplicated_lines")) {
if (Config::get('system', 'remove_multiplicated_lines')) {
$search = ["\n\n\n", "\n ", " \n", "[/quote]\n\n", "\n[/quote]", "[/li]\n", "\n[li]", "\n[ul]", "[/ul]\n", "\n\n[share ", "[/attachment]\n",
"\n[h1]", "[/h1]\n", "\n[h2]", "[/h2]\n", "\n[h3]", "[/h3]\n", "\n[h4]", "[/h4]\n", "\n[h5]", "[/h5]\n", "\n[h6]", "[/h6]\n"];
$replace = ["\n\n", "\n", "\n", "[/quote]\n", "[/quote]", "[/li]", "[li]", "[ul]", "[/ul]", "\n[share ", "[/attachment]",
@ -1389,8 +1413,14 @@ class BBCode extends BaseObject
// Check for sized text
// [size=50] --> font-size: 50px (with the unit).
if ($simple_html != 3) {
$text = preg_replace("(\[size=(\d*?)\](.*?)\[\/size\])ism", "<span style=\"font-size: $1px; line-height: initial;\">$2</span>", $text);
$text = preg_replace("(\[size=(.*?)\](.*?)\[\/size\])ism", "<span style=\"font-size: $1; line-height: initial;\">$2</span>", $text);
} else {
// Issue 2199: Diaspora doesn't interpret the construct above, nor the <small> or <big> element
$text = preg_replace("(\[size=(.*?)\](.*?)\[\/size\])ism", "$2", $text);
}
// Check for centered text
$text = preg_replace("(\[center\](.*?)\[\/center\])ism", "<div style=\"text-align:center;\">$1</div>", $text);
@ -1445,6 +1475,11 @@ class BBCode extends BaseObject
$text = str_replace('[hr]', '<hr />', $text);
if (!$for_plaintext) {
// Autolinker for isolated URLs
$text = preg_replace(Strings::autoLinkRegEx(), '[url]$1[/url]', $text);
}
// This is actually executed in Item::prepareBody()
$nosmile = strpos($text, '[nosmile]') !== false;
@ -1454,24 +1489,22 @@ class BBCode extends BaseObject
$text = preg_replace("/\[font=(.*?)\](.*?)\[\/font\]/sm", "<span style=\"font-family: $1;\">$2</span>", $text);
// Declare the format for [spoiler] layout
$SpoilerLayout = '<blockquote class="spoiler">$1</blockquote>';
$SpoilerLayout = '<details class="spoiler"><summary>' . L10n::t('Click to open/close') . '</summary>$1</details>';
// Check for [spoiler] text
// handle nested quotes
$endlessloop = 0;
while ((strpos($text, "[/spoiler]") !== false) && (strpos($text, "[spoiler]") !== false) && (++$endlessloop < 20)) {
$text = preg_replace("/\[spoiler\](.*?)\[\/spoiler\]/ism", "$SpoilerLayout", $text);
$text = preg_replace("/\[spoiler\](.*?)\[\/spoiler\]/ism", $SpoilerLayout, $text);
}
// Check for [spoiler=Author] text
$t_wrote = L10n::t('$1 wrote:');
// Check for [spoiler=Title] text
// handle nested quotes
$endlessloop = 0;
while ((strpos($text, "[/spoiler]")!== false) && (strpos($text, "[spoiler=") !== false) && (++$endlessloop < 20)) {
$text = preg_replace("/\[spoiler=[\"\']*(.*?)[\"\']*\](.*?)\[\/spoiler\]/ism",
"<br /><strong class=".'"spoiler"'.">" . $t_wrote . "</strong><blockquote class=".'"spoiler"'.">$2</blockquote>",
'<details class="spoiler"><summary>$1</summary>$2</details>',
$text);
}
@ -1629,12 +1662,10 @@ class BBCode extends BaseObject
$text = Smilies::replace($text);
}
// if the HTML is used to generate plain text, then don't do this search, but replace all URL of that kind to text
if (!$for_plaintext) {
$text = preg_replace(Strings::autoLinkRegEx(), '[url]$1[/url]', $text);
if (in_array($simple_html, [7, 9])) {
$text = preg_replace_callback("/\[url\](.*?)\[\/url\]/ism", 'self::convertUrlForOStatusCallback', $text);
$text = preg_replace_callback("/\[url\=(.*?)\](.*?)\[\/url\]/ism", 'self::convertUrlForOStatusCallback', $text);
$text = preg_replace_callback("/\[url\](.*?)\[\/url\]/ism", 'self::convertUrlForActivityPubCallback', $text);
$text = preg_replace_callback("/\[url\=(.*?)\](.*?)\[\/url\]/ism", 'self::convertUrlForActivityPubCallback', $text);
}
} else {
$text = preg_replace("(\[url\](.*?)\[\/url\])ism", " $1 ", $text);
@ -1810,7 +1841,7 @@ class BBCode extends BaseObject
// Clean up the HTML by loading and saving the HTML with the DOM.
// Bad structured html can break a whole page.
// For performance reasons do it only with activated item cache or at export.
if (!$try_oembed || (get_itemcachepath() != "")) {
if (!$try_oembed || (get_itemcachepath() != '')) {
$doc = new DOMDocument();
$doc->preserveWhiteSpace = false;
@ -1818,10 +1849,10 @@ class BBCode extends BaseObject
$doctype = '<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" "http://www.w3.org/TR/REC-html40/loose.dtd">';
$encoding = '<?xml encoding="UTF-8">';
@$doc->loadHTML($encoding.$doctype."<html><body>".$text."</body></html>");
@$doc->loadHTML($encoding . $doctype . '<html><body>' . $text . '</body></html>');
$doc->encoding = 'UTF-8';
$text = $doc->saveHTML();
$text = str_replace(["<html><body>", "</body></html>", $doctype, $encoding], ["", "", "", ""], $text);
$text = str_replace(['<html><body>', '</body></html>', $doctype, $encoding], ['', '', '', ''], $text);
$text = str_replace('<br></li>', '</li>', $text);
@ -1861,9 +1892,9 @@ class BBCode extends BaseObject
* @param string $addon The addon for which the abstract is meant for
* @return string The abstract
*/
public static function getAbstract($text, $addon = "")
public static function getAbstract($text, $addon = '')
{
$abstract = "";
$abstract = '';
$abstracts = [];
$addon = strtolower($addon);
@ -1877,7 +1908,7 @@ class BBCode extends BaseObject
$abstract = $abstracts[$addon];
}
if ($abstract == "" && preg_match("/\[abstract\](.*?)\[\/abstract\]/ism", $text, $result)) {
if ($abstract == '' && preg_match("/\[abstract\](.*?)\[\/abstract\]/ism", $text, $result)) {
$abstract = $result[1];
}
@ -1953,7 +1984,7 @@ class BBCode extends BaseObject
// Add all tags that maybe were removed
if (preg_match_all("/#\[url\=([$url_search_string]*)\](.*?)\[\/url\]/ism", $original_text, $tags)) {
$tagline = "";
$tagline = '';
foreach ($tags[2] as $tag) {
$tag = html_entity_decode($tag, ENT_QUOTES, 'UTF-8');
if (!strpos(html_entity_decode($text, ENT_QUOTES, 'UTF-8'), '#' . $tag)) {
@ -1971,7 +2002,7 @@ class BBCode extends BaseObject
// If a link is followed by a quote then there should be a newline before it
// Maybe we should make this newline at every time before a quote.
$text = str_replace(["</a><blockquote>"], ["</a><br><blockquote>"], $text);
$text = str_replace(['</a><blockquote>'], ['</a><br><blockquote>'], $text);
$stamp1 = microtime(true);

View file

@ -42,14 +42,32 @@ class HTML
return $cleaned;
}
private static function tagToBBCode(DOMDocument $doc, $tag, $attributes, $startbb, $endbb)
/**
* Search all instances of a specific HTML tag node in the provided DOM document and replaces them with BBCode text nodes.
*
* @see HTML::tagToBBCodeSub()
*/
private static function tagToBBCode(DOMDocument $doc, string $tag, array $attributes, string $startbb, string $endbb, bool $ignoreChildren = false)
{
do {
$done = self::tagToBBCodeSub($doc, $tag, $attributes, $startbb, $endbb);
$done = self::tagToBBCodeSub($doc, $tag, $attributes, $startbb, $endbb, $ignoreChildren);
} while ($done);
}
private static function tagToBBCodeSub(DOMDocument $doc, $tag, $attributes, $startbb, $endbb)
/**
* Search the first specific HTML tag node in the provided DOM document and replaces it with BBCode text nodes.
*
* @param DOMDocument $doc
* @param string $tag HTML tag name
* @param array $attributes Array of attributes to match and optionally use the value from
* @param string $startbb BBCode tag opening
* @param string $endbb BBCode tag closing
* @param bool $ignoreChildren If set to false, the HTML tag children will be appended as text inside the BBCode tag
* Otherwise, they will be entirely ignored. Useful for simple BBCode that draw their
* 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)
{
$savestart = str_replace('$', '\x01', $startbb);
$replace = false;
@ -98,7 +116,7 @@ class HTML
$node->parentNode->insertBefore($StartCode, $node);
if ($node->hasChildNodes()) {
if (!$ignoreChildren && $node->hasChildNodes()) {
/** @var \DOMNode $child */
foreach ($node->childNodes as $key => $child) {
/* Remove empty text nodes at the start or at the end of the children list */
@ -296,14 +314,14 @@ class HTML
self::tagToBBCode($doc, 'a', ['href' => '/mailto:(.+)/'], '[mail=$1]', '[/mail]');
self::tagToBBCode($doc, 'a', ['href' => '/(.+)/'], '[url=$1]', '[/url]');
self::tagToBBCode($doc, 'img', ['src' => '/(.+)/', 'alt' => '/(.+)/'], '[img=$1]$2', '[/img]');
self::tagToBBCode($doc, 'img', ['src' => '/(.+)/', 'width' => '/(\d+)/', 'height' => '/(\d+)/'], '[img=$2x$3]$1', '[/img]');
self::tagToBBCode($doc, 'img', ['src' => '/(.+)/'], '[img]$1', '[/img]');
self::tagToBBCode($doc, 'img', ['src' => '/(.+)/', 'alt' => '/(.+)/'], '[img=$1]$2', '[/img]', true);
self::tagToBBCode($doc, 'img', ['src' => '/(.+)/', 'width' => '/(\d+)/', 'height' => '/(\d+)/'], '[img=$2x$3]$1', '[/img]', true);
self::tagToBBCode($doc, 'img', ['src' => '/(.+)/'], '[img]$1', '[/img]', true);
self::tagToBBCode($doc, 'video', ['src' => '/(.+)/'], '[video]$1', '[/video]');
self::tagToBBCode($doc, 'audio', ['src' => '/(.+)/'], '[audio]$1', '[/audio]');
self::tagToBBCode($doc, 'iframe', ['src' => '/(.+)/'], '[iframe]$1', '[/iframe]');
self::tagToBBCode($doc, 'video', ['src' => '/(.+)/'], '[video]$1', '[/video]', true);
self::tagToBBCode($doc, 'audio', ['src' => '/(.+)/'], '[audio]$1', '[/audio]', true);
self::tagToBBCode($doc, 'iframe', ['src' => '/(.+)/'], '[iframe]$1', '[/iframe]', true);
self::tagToBBCode($doc, 'key', [], '[code]', '[/code]');
self::tagToBBCode($doc, 'code', [], '[code]', '[/code]');
@ -854,8 +872,8 @@ class HTML
$url = '';
}
return Renderer::replaceMacros(Renderer::getMarkupTemplate(($textmode)?'micropro_txt.tpl':'micropro_img.tpl'), [
'$click' => defaults($contact, 'click', ''),
return Renderer::replaceMacros(Renderer::getMarkupTemplate($textmode ? 'micropro_txt.tpl' : 'micropro_img.tpl'), [
'$click' => $contact['click'] ?? '',
'$class' => $class,
'$url' => $url,
'$photo' => ProxyUtils::proxifyUrl($contact['thumb'], false, ProxyUtils::SIZE_THUMB),
@ -875,9 +893,9 @@ class HTML
* @param bool $aside Display the search widgit aside.
*
* @return string Formatted HTML.
* @throws \Friendica\Network\HTTPException\InternalServerErrorException
* @throws \Exception
*/
public static function search($s, $id = 'search-box', $url = 'search', $aside = true)
public static function search($s, $id = 'search-box', $aside = true)
{
$mode = 'text';
@ -888,23 +906,24 @@ class HTML
$values = [
'$s' => $s,
'$q' => urlencode($s),
'$id' => $id,
'$action_url' => $url,
'$search_label' => L10n::t('Search'),
'$save_label' => $save_label,
'$savedsearch' => 'savedsearch',
'$search_hint' => L10n::t('@name, !forum, #tags, content'),
'$mode' => $mode
'$mode' => $mode,
'$return_url' => urlencode('search?q=' . urlencode($s)),
];
if (!$aside) {
$values['$searchoption'] = [
L10n::t("Full Text"),
L10n::t("Tags"),
L10n::t("Contacts")];
$values['$search_options'] = [
'fulltext' => L10n::t('Full Text'),
'tags' => L10n::t('Tags'),
'contacts' => L10n::t('Contacts')
];
if (Config::get('system', 'poco_local_search')) {
$values['$searchoption'][] = L10n::t("Forums");
$values['$searchoption']['forums'] = L10n::t('Forums');
}
}

View file

@ -11,6 +11,7 @@ use Friendica\Core\PConfig;
use Friendica\Core\Protocol;
use Friendica\Core\Renderer;
use Friendica\Core\System;
use Friendica\Core\Session;
use Friendica\Database\DBA;
use Friendica\Model\Contact;
use Friendica\Model\FileTag;
@ -337,16 +338,9 @@ class Widget
return;
}
$cid = $zcid = 0;
$zcid = 0;
if (!empty($_SESSION['remote'])) {
foreach ($_SESSION['remote'] as $visitor) {
if ($visitor['uid'] == $profile_uid) {
$cid = $visitor['cid'];
break;
}
}
}
$cid = Session::getRemoteContactID($profile_uid);
if (!$cid) {
if (Profile::getMyURL()) {

View file

@ -57,7 +57,7 @@ class CalendarExport
// $a->data is only available if the profile page is visited. If the visited page is not part
// of the profile page it should be the personal /events page. So we can use $a->user.
$user = defaults($a->data['user'], 'nickname', $a->user['nickname']);
$user = ($a->data['user']['nickname'] ?? '') ?: $a->user['nickname'];
$tpl = Renderer::getMarkupTemplate("widget/events.tpl");
$return = Renderer::replaceMacros($tpl, [

View file

@ -61,7 +61,7 @@ class ContactBlock
if ($total) {
// Only show followed for personal accounts, followers for pages
if (defaults($profile, 'account-type', User::ACCOUNT_TYPE_PERSON) == User::ACCOUNT_TYPE_PERSON) {
if ((($profile['account-type'] ?? '') ?: User::ACCOUNT_TYPE_PERSON) == User::ACCOUNT_TYPE_PERSON) {
$rel = [Contact::SHARING, Contact::FRIEND];
} else {
$rel = [Contact::FOLLOWER, Contact::FRIEND];

View file

@ -0,0 +1,47 @@
<?php
namespace Friendica\Content\Widget;
use Friendica\Core\L10n;
use Friendica\Core\Renderer;
use Friendica\Database\DBA;
class SavedSearches
{
/**
* @param string $return_url
* @param string $search
* @return string
* @throws \Exception
*/
public static function getHTML($return_url, $search = '')
{
$o = '';
$saved_searches = DBA::select('search', ['id', 'term'], ['uid' => local_user()]);
if (DBA::isResult($saved_searches)) {
$saved = [];
foreach ($saved_searches as $saved_search) {
$saved[] = [
'id' => $saved_search['id'],
'term' => $saved_search['term'],
'encodedterm' => urlencode($saved_search['term']),
'delete' => L10n::t('Remove term'),
'selected' => $search == $saved_search['term'],
];
}
$tpl = Renderer::getMarkupTemplate('widget/saved_searches.tpl');
$o = Renderer::replaceMacros($tpl, [
'$title' => L10n::t('Saved Searches'),
'$add' => '',
'$searchbox' => '',
'$saved' => $saved,
'$return_url' => urlencode($return_url),
]);
}
return $o;
}
}

View file

@ -11,6 +11,7 @@ use Friendica\Content\Feature;
use Friendica\Database\DBA;
use Friendica\Model\Contact;
use Friendica\Model\GContact;
use Friendica\Core\Session;
use Friendica\Util\Network;
/**
@ -40,12 +41,12 @@ class ACL extends BaseObject
$networks = null;
$size = defaults($options, 'size', 4);
$size = ($options['size'] ?? 0) ?: 4;
$mutual = !empty($options['mutual_friends']);
$single = !empty($options['single']) && empty($options['multiple']);
$exclude = defaults($options, 'exclude', false);
$exclude = $options['exclude'] ?? false;
switch (defaults($options, 'networks', Protocol::PHANTOM)) {
switch (($options['networks'] ?? '') ?: Protocol::PHANTOM) {
case 'DFRN_ONLY':
$networks = [Protocol::DFRN];
break;
@ -225,13 +226,13 @@ class ACL extends BaseObject
$acl_regex = '/<([0-9]+)>/i';
preg_match_all($acl_regex, defaults($user, 'allow_cid', ''), $matches);
preg_match_all($acl_regex, $user['allow_cid'] ?? '', $matches);
$allow_cid = $matches[1];
preg_match_all($acl_regex, defaults($user, 'allow_gid', ''), $matches);
preg_match_all($acl_regex, $user['allow_gid'] ?? '', $matches);
$allow_gid = $matches[1];
preg_match_all($acl_regex, defaults($user, 'deny_cid', ''), $matches);
preg_match_all($acl_regex, $user['deny_cid'] ?? '', $matches);
$deny_cid = $matches[1];
preg_match_all($acl_regex, defaults($user, 'deny_gid', ''), $matches);
preg_match_all($acl_regex, $user['deny_gid'] ?? '', $matches);
$deny_gid = $matches[1];
// Reformats the ACL data so that it is accepted by the JS frontend
@ -300,10 +301,10 @@ class ACL extends BaseObject
'$showall' => L10n::t('Visible to everybody'),
'$show' => L10n::t('show'),
'$hide' => L10n::t('don\'t show'),
'$allowcid' => json_encode(defaults($default_permissions, 'allow_cid', [])), // we need arrays for Javascript since we call .remove() and .push() on this values
'$allowgid' => json_encode(defaults($default_permissions, 'allow_gid', [])),
'$denycid' => json_encode(defaults($default_permissions, 'deny_cid', [])),
'$denygid' => json_encode(defaults($default_permissions, 'deny_gid', [])),
'$allowcid' => json_encode(($default_permissions['allow_cid'] ?? '') ?: []), // We need arrays for
'$allowgid' => json_encode(($default_permissions['allow_gid'] ?? '') ?: []), // Javascript since we
'$denycid' => json_encode(($default_permissions['deny_cid'] ?? '') ?: []), // call .remove() and
'$denygid' => json_encode(($default_permissions['deny_gid'] ?? '') ?: []), // .push() on these values
'$networks' => $show_jotnets,
'$emailcc' => L10n::t('CC: email addresses'),
'$emtitle' => L10n::t('Example: bob@example.com, mary@example.com'),
@ -320,46 +321,4 @@ class ACL extends BaseObject
return $o;
}
/**
* Searching for global contacts for autocompletion
*
* @brief Searching for global contacts for autocompletion
* @param string $search Name or part of a name or nick
* @param string $mode Search mode (e.g. "community")
* @return array with the search results
* @throws \Friendica\Network\HTTPException\InternalServerErrorException
*/
public static function contactAutocomplete($search, $mode)
{
if (Config::get('system', 'block_public') && !local_user() && !remote_user()) {
return [];
}
// don't search if search term has less than 2 characters
if (!$search || mb_strlen($search) < 2) {
return [];
}
if (substr($search, 0, 1) === '@') {
$search = substr($search, 1);
}
// check if searching in the local global contact table is enabled
if (Config::get('system', 'poco_local_search')) {
$return = GContact::searchByName($search, $mode);
} else {
$p = defaults($_GET, 'page', 1) != 1 ? '&p=' . defaults($_GET, 'page', 1) : '';
$curlResult = Network::curl(get_server() . '/lsearch?f=' . $p . '&search=' . urlencode($search));
if ($curlResult->isSuccess()) {
$lsearch = json_decode($curlResult->getBody(), true);
if (!empty($lsearch['results'])) {
$return = $lsearch['results'];
}
}
}
return defaults($return, []);
}
}

View file

@ -1,4 +1,5 @@
<?php
/**
* @file /src/Core/Authentication.php
*/
@ -24,9 +25,11 @@ class Authentication extends BaseObject
*/
public static function getCookieHashForUser($user)
{
return(hash("sha256", Config::get("system", "site_prvkey") .
$user["prvkey"] .
$user["password"]));
return hash_hmac(
"sha256",
hash_hmac("sha256", $user["password"], $user["prvkey"]),
Config::get("system", "site_prvkey")
);
}
/**
@ -43,9 +46,11 @@ class Authentication extends BaseObject
}
if ($user) {
$value = json_encode(["uid" => $user["uid"],
$value = json_encode([
"uid" => $user["uid"],
"hash" => self::getCookieHashForUser($user),
"ip" => defaults($_SERVER, 'REMOTE_ADDR', '0.0.0.0')]);
"ip" => ($_SERVER['REMOTE_ADDR'] ?? '') ?: '0.0.0.0'
]);
} else {
$value = "";
}
@ -88,4 +93,3 @@ class Authentication extends BaseObject
}
}
}

View file

@ -15,6 +15,7 @@ class MemcacheCache extends Cache implements IMemoryCache
{
use TraitCompareSet;
use TraitCompareDelete;
use TraitMemcacheCommand;
/**
* @var Memcache
@ -34,11 +35,11 @@ class MemcacheCache extends Cache implements IMemoryCache
$this->memcache = new Memcache();
$memcache_host = $config->get('system', 'memcache_host');
$memcache_port = $config->get('system', 'memcache_port');
$this->server = $config->get('system', 'memcache_host');;
$this->port = $config->get('system', 'memcache_port');
if (!$this->memcache->connect($memcache_host, $memcache_port)) {
throw new Exception('Expected Memcache server at ' . $memcache_host . ':' . $memcache_port . ' isn\'t available');
if (!@$this->memcache->connect($this->server, $this->port)) {
throw new Exception('Expected Memcache server at ' . $this->server . ':' . $this->port . ' isn\'t available');
}
}
@ -47,21 +48,7 @@ class MemcacheCache extends Cache implements IMemoryCache
*/
public function getAllKeys($prefix = null)
{
$keys = [];
$allSlabs = $this->memcache->getExtendedStats('slabs');
foreach ($allSlabs as $slabs) {
foreach (array_keys($slabs) as $slabId) {
$cachedump = $this->memcache->getExtendedStats('cachedump', (int)$slabId);
foreach ($cachedump as $key => $arrVal) {
if (!is_array($arrVal)) {
continue;
}
$keys = array_merge($keys, array_keys($arrVal));
}
}
}
$keys = $this->getOriginalKeys($keys);
$keys = $this->getOriginalKeys($this->getMemcacheKeys());
return $this->filterArrayKeysByPrefix($keys, $prefix);
}

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