Compare commits
62 Commits
c30b24d09f
...
fd98d6d117
Author | SHA1 | Date |
---|---|---|
Andrew Dolgov | fd98d6d117 | |
Andrew Dolgov | 92185933f9 | |
Andrew Dolgov | 4fd0d13b64 | |
Andrew Dolgov | e2a02f1f4b | |
Andrew Dolgov | 00d2cb0f93 | |
Andrew Dolgov | 2b01786124 | |
Andrew Dolgov | 088dd049b5 | |
Andrew Dolgov | 28a911a2a8 | |
Andrew Dolgov | 066b9a29d7 | |
fox | 269c0f53b8 | |
Rodney Stromlund | 80bd26b3b1 | |
Andrew Dolgov | 3ca3e54251 | |
Rodney Stromlund | 7795c415ab | |
Andrew Dolgov | cf656125b9 | |
Andrew Dolgov | 740d249aba | |
Andrew Dolgov | dfffa20e78 | |
Andrew Dolgov | d25440f051 | |
Andrew Dolgov | da620ef5d8 | |
Andrew Dolgov | ecedc51162 | |
Andrew Dolgov | 33a3672eab | |
Andrew Dolgov | a0b52caced | |
Andrew Dolgov | 37014d78fd | |
Andrew Dolgov | 0c42d99a93 | |
Andrew Dolgov | c41c1bd353 | |
Andrew Dolgov | d40b6c655f | |
Andrew Dolgov | 6cf4ebbabd | |
Andrew Dolgov | 723323d746 | |
Andrew Dolgov | d305532bce | |
Andrew Dolgov | 903b9dbb8b | |
Andrew Dolgov | 8e490af01c | |
Andrew Dolgov | ca86a0e239 | |
Andrew Dolgov | 563675de09 | |
Andrew Dolgov | 0f9488ace0 | |
fox | cddbf5bf5a | |
wn_ | b14a8a76eb | |
fox | c4026b408b | |
wn_ | c923fda8c9 | |
wn_ | fe08299ec4 | |
wn_ | 029cb8f442 | |
wn_ | 42b287e964 | |
wn_ | dabb85c7dd | |
wn_ | 7ed4fa4c1d | |
wn_ | c4b16ca608 | |
wn_ | c48dd6a3c4 | |
wn_ | d34d01fd72 | |
Andrew Dolgov | d210ae50ad | |
Andrew Dolgov | b7a6c948d0 | |
Andrew Dolgov | 04c2fa9f15 | |
Andrew Dolgov | 4d825fa6a6 | |
fox | 33c20d42df | |
Veit Lehmann | aa2b770e30 | |
Andrew Dolgov | a2af3a6bb4 | |
fox | fcfcb69a2e | |
wn_ | fd55e492c3 | |
fox | 7bbe71b818 | |
Chih-Hsuan Yen | 40afee5d12 | |
fox | 0cd4abe4eb | |
wn_ | 1646aba944 | |
wn_ | b28d339bf2 | |
wn_ | f484988967 | |
wn_ | 380624a484 | |
wn_ | f0f7a5f958 |
|
@ -0,0 +1,81 @@
|
|||
FROM registry.fakecake.org/docker.io/alpine:3.17
|
||||
EXPOSE 9000/tcp
|
||||
|
||||
ENV SCRIPT_ROOT=/opt/tt-rss
|
||||
ENV SRC_DIR=/src/tt-rss/
|
||||
|
||||
RUN apk add --no-cache dcron php81 php81-fpm php81-phar \
|
||||
php81-pdo php81-gd php81-pgsql php81-pdo_pgsql php81-xmlwriter \
|
||||
php81-mbstring php81-intl php81-xml php81-curl php81-simplexml \
|
||||
php81-session php81-tokenizer php81-dom php81-fileinfo php81-ctype \
|
||||
php81-json php81-iconv php81-pcntl php81-posix php81-zip php81-exif \
|
||||
php81-openssl git postgresql-client sudo php81-pecl-xdebug rsync tzdata && \
|
||||
sed -i 's/\(memory_limit =\) 128M/\1 256M/' /etc/php81/php.ini && \
|
||||
sed -i -e 's/^listen = 127.0.0.1:9000/listen = 9000/' \
|
||||
-e 's/;\(clear_env\) = .*/\1 = no/i' \
|
||||
-e 's/^\(user\|group\) = .*/\1 = app/i' \
|
||||
-e 's/;\(php_admin_value\[error_log\]\) = .*/\1 = \/tmp\/error.log/' \
|
||||
-e 's/;\(php_admin_flag\[log_errors\]\) = .*/\1 = on/' \
|
||||
/etc/php81/php-fpm.d/www.conf && \
|
||||
mkdir -p /var/www ${SCRIPT_ROOT}/config.d
|
||||
|
||||
ADD --chmod=0755 startup.sh ${SCRIPT_ROOT}
|
||||
ADD --chmod=0755 updater.sh ${SCRIPT_ROOT}
|
||||
ADD --chmod=0755 dcron.sh ${SCRIPT_ROOT}
|
||||
ADD --chmod=0755 backup.sh /etc/periodic/weekly/backup
|
||||
|
||||
ADD index.php ${SCRIPT_ROOT}
|
||||
ADD config.docker.php ${SCRIPT_ROOT}
|
||||
|
||||
COPY --from=app-src . ${SRC_DIR}
|
||||
|
||||
ARG ORIGIN_REPO_MAIN=https://git.tt-rss.org/fox/tt-rss.git
|
||||
ARG ORIGIN_REPO_XACCEL=https://git.tt-rss.org/fox/ttrss-nginx-xaccel.git
|
||||
ARG ORIGIN_COMMIT=
|
||||
|
||||
ENV ORIGIN_REPO_MAIN=${ORIGIN_REPO_MAIN}
|
||||
ENV ORIGIN_REPO_XACCEL=${ORIGIN_REPO_XACCEL}
|
||||
ENV ORIGIN_COMMIT=${ORIGIN_COMMIT}
|
||||
|
||||
RUN git clone --depth=1 ${ORIGIN_REPO_XACCEL} ${SRC_DIR}/plugins.local/nginx_xaccel
|
||||
|
||||
ENV OWNER_UID=1000
|
||||
ENV OWNER_GID=1000
|
||||
|
||||
ENV PHP_WORKER_MAX_CHILDREN=5
|
||||
ENV PHP_WORKER_MEMORY_LIMIT=256M
|
||||
|
||||
# these are applied on every startup, if set
|
||||
ENV ADMIN_USER_PASS=""
|
||||
# see classes/UserHelper.php ACCESS_LEVEL_*
|
||||
# setting this to -2 would effectively disable built-in admin user
|
||||
# unless single user mode is enabled
|
||||
ENV ADMIN_USER_ACCESS_LEVEL=""
|
||||
|
||||
# these are applied unless user already exists
|
||||
ENV AUTO_CREATE_USER=""
|
||||
ENV AUTO_CREATE_USER_PASS=""
|
||||
ENV AUTO_CREATE_USER_ACCESS_LEVEL="0"
|
||||
|
||||
# TODO: remove prefix from container variables not used by tt-rss itself:
|
||||
#
|
||||
# - TTRSS_NO_STARTUP_PLUGIN_UPDATES -> NO_STARTUP_PLUGIN_UPDATES
|
||||
# - TTRSS_XDEBUG_... -> XDEBUG_...
|
||||
|
||||
# don't try to update local plugins on startup
|
||||
ENV TTRSS_NO_STARTUP_PLUGIN_UPDATES=""
|
||||
|
||||
# TTRSS_XDEBUG_HOST defaults to host IP if unset
|
||||
ENV TTRSS_XDEBUG_ENABLED=""
|
||||
ENV TTRSS_XDEBUG_HOST=""
|
||||
ENV TTRSS_XDEBUG_PORT="9000"
|
||||
|
||||
ENV TTRSS_DB_TYPE="pgsql"
|
||||
ENV TTRSS_DB_HOST="db"
|
||||
ENV TTRSS_DB_PORT="5432"
|
||||
|
||||
ENV TTRSS_MYSQL_CHARSET="UTF8"
|
||||
ENV TTRSS_PHP_EXECUTABLE="/usr/bin/php81"
|
||||
ENV TTRSS_PLUGINS="auth_internal, note, nginx_xaccel"
|
||||
|
||||
CMD ${SCRIPT_ROOT}/startup.sh
|
|
@ -0,0 +1,31 @@
|
|||
#!/bin/sh -e
|
||||
|
||||
DST_DIR=/backups
|
||||
KEEP_DAYS=28
|
||||
APP_ROOT=/var/www/html/tt-rss
|
||||
|
||||
if pg_isready -h $TTRSS_DB_HOST -U $TTRSS_DB_USER; then
|
||||
DST_FILE=ttrss-backup-$(date +%Y%m%d).sql.gz
|
||||
|
||||
echo backing up tt-rss database to $DST_DIR/$DST_FILE...
|
||||
|
||||
export PGPASSWORD=$TTRSS_DB_PASS
|
||||
|
||||
pg_dump --clean -h $TTRSS_DB_HOST -U $TTRSS_DB_USER $TTRSS_DB_NAME | gzip > $DST_DIR/$DST_FILE
|
||||
|
||||
DST_FILE=ttrss-backup-$(date +%Y%m%d).tar.gz
|
||||
|
||||
echo backing up tt-rss local directories to $DST_DIR/$DST_FILE...
|
||||
|
||||
tar -cz -f $DST_DIR/$DST_FILE $APP_ROOT/*.local \
|
||||
$APP_ROOT/feed-icons/ \
|
||||
$APP_ROOT/config.php
|
||||
|
||||
echo cleaning up...
|
||||
|
||||
find $DST_DIR -type f -name '*.gz' -mtime +$KEEP_DAYS -delete
|
||||
|
||||
echo done.
|
||||
else
|
||||
echo backup failed: database is not ready.
|
||||
fi
|
|
@ -0,0 +1,8 @@
|
|||
<?php
|
||||
|
||||
$snippets = glob(getenv("SCRIPT_ROOT")."/config.d/*.php");
|
||||
|
||||
foreach ($snippets as $snippet) {
|
||||
require_once $snippet;
|
||||
}
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
#!/bin/sh
|
||||
# https://github.com/dubiousjim/dcron/issues/13
|
||||
set -e
|
||||
|
||||
/usr/sbin/crond "$@"
|
|
@ -0,0 +1,3 @@
|
|||
<?php
|
||||
header("Location: /tt-rss/");
|
||||
return;
|
|
@ -0,0 +1,153 @@
|
|||
#!/bin/sh -e
|
||||
|
||||
while ! pg_isready -h $TTRSS_DB_HOST -U $TTRSS_DB_USER; do
|
||||
echo waiting until $TTRSS_DB_HOST is ready...
|
||||
sleep 3
|
||||
done
|
||||
|
||||
# We don't need those here (HTTP_HOST would cause false SELF_URL_PATH check failures)
|
||||
unset HTTP_PORT
|
||||
unset HTTP_HOST
|
||||
|
||||
if ! id app >/dev/null 2>&1; then
|
||||
addgroup -g $OWNER_GID app
|
||||
adduser -D -h /var/www/html -G app -u $OWNER_UID app
|
||||
fi
|
||||
|
||||
update-ca-certificates || true
|
||||
|
||||
DST_DIR=/var/www/html/tt-rss
|
||||
|
||||
[ -e $DST_DIR ] && rm -f $DST_DIR/.app_is_ready
|
||||
|
||||
export PGPASSWORD=$TTRSS_DB_PASS
|
||||
|
||||
[ ! -e /var/www/html/index.php ] && cp ${SCRIPT_ROOT}/index.php /var/www/html
|
||||
|
||||
if [ ! -d $DST_DIR ]; then
|
||||
mkdir -p $DST_DIR
|
||||
chown $OWNER_UID:$OWNER_GID $DST_DIR
|
||||
|
||||
sudo -u app rsync -a \
|
||||
$SRC_DIR/ $DST_DIR/
|
||||
else
|
||||
chown -R $OWNER_UID:$OWNER_GID $DST_DIR
|
||||
|
||||
sudo -u app rsync -a --delete \
|
||||
--exclude /cache \
|
||||
--exclude /lock \
|
||||
--exclude /feed-icons \
|
||||
--exclude /plugins/af_comics/filters.local \
|
||||
--exclude /plugins.local \
|
||||
--exclude /templates.local \
|
||||
--exclude /themes.local \
|
||||
$SRC_DIR/ $DST_DIR/
|
||||
|
||||
sudo -u app rsync -a --delete \
|
||||
$SRC_DIR/plugins.local/nginx_xaccel \
|
||||
$DST_DIR/plugins.local/nginx_xaccel
|
||||
fi
|
||||
|
||||
for d in cache lock feed-icons plugins.local themes.local; do
|
||||
sudo -u app mkdir -p $DST_DIR/$d
|
||||
done
|
||||
|
||||
for d in cache lock feed-icons; do
|
||||
chmod 777 $DST_DIR/$d
|
||||
find $DST_DIR/$d -type f -exec chmod 666 {} \;
|
||||
done
|
||||
|
||||
sudo -u app cp ${SCRIPT_ROOT}/config.docker.php $DST_DIR/config.php
|
||||
chmod 644 $DST_DIR/config.php
|
||||
|
||||
chown -R $OWNER_UID:$OWNER_GID $DST_DIR \
|
||||
/var/log/php81
|
||||
|
||||
if [ -z "$TTRSS_NO_STARTUP_PLUGIN_UPDATES" ]; then
|
||||
echo updating all local plugins...
|
||||
|
||||
find $DST_DIR/plugins.local -mindepth 1 -maxdepth 1 -type d | while read PLUGIN; do
|
||||
if [ -d $PLUGIN/.git ]; then
|
||||
echo updating $PLUGIN...
|
||||
|
||||
cd $PLUGIN && \
|
||||
sudo -u app git config core.filemode false && \
|
||||
sudo -u app git config pull.rebase false && \
|
||||
sudo -u app git pull origin master || echo warning: attempt to update plugin $PLUGIN failed.
|
||||
fi
|
||||
done
|
||||
else
|
||||
echo skipping local plugin updates, disabled.
|
||||
fi
|
||||
|
||||
PSQL="psql -q -h $TTRSS_DB_HOST -U $TTRSS_DB_USER $TTRSS_DB_NAME"
|
||||
|
||||
$PSQL -c "create extension if not exists pg_trgm"
|
||||
|
||||
RESTORE_SCHEMA=${SCRIPT_ROOT}/restore-schema.sql.gz
|
||||
|
||||
if [ -r $RESTORE_SCHEMA ]; then
|
||||
$PSQL -c "drop schema public cascade; create schema public;"
|
||||
zcat $RESTORE_SCHEMA | $PSQL
|
||||
fi
|
||||
|
||||
# this was previously generated
|
||||
rm -f $DST_DIR/config.php.bak
|
||||
|
||||
if [ ! -z "${TTRSS_XDEBUG_ENABLED}" ]; then
|
||||
if [ -z "${TTRSS_XDEBUG_HOST}" ]; then
|
||||
export TTRSS_XDEBUG_HOST=$(ip ro sh 0/0 | cut -d " " -f 3)
|
||||
fi
|
||||
echo enabling xdebug with the following parameters:
|
||||
env | grep TTRSS_XDEBUG
|
||||
cat > /etc/php81/conf.d/50_xdebug.ini <<EOF
|
||||
zend_extension=xdebug.so
|
||||
xdebug.mode=develop,trace,debug
|
||||
xdebug.start_with_request = yes
|
||||
xdebug.client_port = ${TTRSS_XDEBUG_PORT}
|
||||
xdebug.client_host = ${TTRSS_XDEBUG_HOST}
|
||||
EOF
|
||||
fi
|
||||
|
||||
sed -i.bak "s/^\(memory_limit\) = \(.*\)/\1 = ${PHP_WORKER_MEMORY_LIMIT}/" \
|
||||
/etc/php81/php.ini
|
||||
|
||||
sed -i.bak "s/^\(pm.max_children\) = \(.*\)/\1 = ${PHP_WORKER_MAX_CHILDREN}/" \
|
||||
/etc/php81/php-fpm.d/www.conf
|
||||
|
||||
sudo -Eu app php81 $DST_DIR/update.php --update-schema=force-yes
|
||||
|
||||
if [ ! -z "$ADMIN_USER_PASS" ]; then
|
||||
sudo -Eu app php81 $DST_DIR/update.php --user-set-password "admin:$ADMIN_USER_PASS"
|
||||
else
|
||||
if sudo -Eu app php81 $DST_DIR/update.php --user-check-password "admin:password"; then
|
||||
RANDOM_PASS=$(tr -dc A-Za-z0-9 </dev/urandom | head -c 16 ; echo '')
|
||||
|
||||
echo "*****************************************************************************"
|
||||
echo "* Setting initial built-in admin user password to '$RANDOM_PASS' *"
|
||||
echo "* If you want to set it manually, use ADMIN_USER_PASS environment variable. *"
|
||||
echo "*****************************************************************************"
|
||||
|
||||
sudo -Eu app php81 $DST_DIR/update.php --user-set-password "admin:$RANDOM_PASS"
|
||||
fi
|
||||
fi
|
||||
|
||||
if [ ! -z "$ADMIN_USER_ACCESS_LEVEL" ]; then
|
||||
sudo -Eu app php81 $DST_DIR/update.php --user-set-access-level "admin:$ADMIN_USER_ACCESS_LEVEL"
|
||||
fi
|
||||
|
||||
if [ ! -z "$AUTO_CREATE_USER" ]; then
|
||||
sudo -Eu app /bin/sh -c "php81 $DST_DIR/update.php --user-exists $AUTO_CREATE_USER ||
|
||||
php81 $DST_DIR/update.php --force-yes --user-add \"$AUTO_CREATE_USER:$AUTO_CREATE_USER_PASS:$AUTO_CREATE_USER_ACCESS_LEVEL\""
|
||||
fi
|
||||
|
||||
rm -f /tmp/error.log && mkfifo /tmp/error.log && chown app:app /tmp/error.log
|
||||
|
||||
(tail -q -f /tmp/error.log >> /proc/1/fd/2) &
|
||||
|
||||
unset ADMIN_USER_PASS
|
||||
unset AUTO_CREATE_USER_PASS
|
||||
|
||||
touch $DST_DIR/.app_is_ready
|
||||
|
||||
exec /usr/sbin/php-fpm81 --nodaemonize --force-stderr
|
|
@ -0,0 +1,33 @@
|
|||
#!/bin/sh -e
|
||||
|
||||
# We don't need those here (HTTP_HOST would cause false SELF_URL_PATH check failures)
|
||||
unset HTTP_PORT
|
||||
unset HTTP_HOST
|
||||
|
||||
unset ADMIN_USER_PASS
|
||||
unset AUTO_CREATE_USER_PASS
|
||||
|
||||
# wait for the app container to delete .app_is_ready and perform rsync, etc.
|
||||
sleep 30
|
||||
|
||||
if ! id app; then
|
||||
addgroup -g $OWNER_GID app
|
||||
adduser -D -h /var/www/html -G app -u $OWNER_UID app
|
||||
fi
|
||||
|
||||
while ! pg_isready -h $TTRSS_DB_HOST -U $TTRSS_DB_USER; do
|
||||
echo waiting until $TTRSS_DB_HOST is ready...
|
||||
sleep 3
|
||||
done
|
||||
|
||||
sed -i.bak "s/^\(memory_limit\) = \(.*\)/\1 = ${PHP_WORKER_MEMORY_LIMIT}/" \
|
||||
/etc/php81/php.ini
|
||||
|
||||
DST_DIR=/var/www/html/tt-rss
|
||||
|
||||
while [ ! -s $DST_DIR/config.php -a -e $DST_DIR/.app_is_ready ]; do
|
||||
echo waiting for app container...
|
||||
sleep 3
|
||||
done
|
||||
|
||||
sudo -E -u app /usr/bin/php81 /var/www/html/tt-rss/update_daemon2.php
|
|
@ -0,0 +1,15 @@
|
|||
FROM registry.fakecake.org/docker.io/nginx:alpine
|
||||
|
||||
HEALTHCHECK CMD curl --fail http://localhost/tt-rss/index.php || exit 1
|
||||
|
||||
COPY nginx.conf /etc/nginx/templates/nginx.conf.template
|
||||
|
||||
# By default, nginx will send the php requests to "app" server, but this server
|
||||
# name can be overridden at runtime by passing an APP_UPSTREAM env var
|
||||
ENV APP_UPSTREAM=${APP_UPSTREAM:-app}
|
||||
|
||||
# It's necessary to set the following NGINX_ENVSUBST_OUTPUT_DIR env var to tell
|
||||
# nginx to replace the env vars of /etc/nginx/templates/nginx.conf.template
|
||||
# and put the result in /etc/nginx/nginx.conf (instead of /etc/nginx/conf.d/nginx.conf)
|
||||
# See https://github.com/docker-library/docs/tree/master/nginx#using-environment-variables-in-nginx-configuration-new-in-119
|
||||
ENV NGINX_ENVSUBST_OUTPUT_DIR=/etc/nginx
|
|
@ -0,0 +1,61 @@
|
|||
worker_processes auto;
|
||||
pid /var/run/nginx.pid;
|
||||
|
||||
events {
|
||||
worker_connections 1024;
|
||||
}
|
||||
|
||||
http {
|
||||
include /etc/nginx/mime.types;
|
||||
default_type application/octet-stream;
|
||||
|
||||
access_log /dev/stdout;
|
||||
error_log /dev/stderr warn;
|
||||
|
||||
sendfile on;
|
||||
|
||||
index index.php;
|
||||
|
||||
upstream app {
|
||||
server ${APP_UPSTREAM}:9000;
|
||||
}
|
||||
|
||||
server {
|
||||
listen 80;
|
||||
listen [::]:80;
|
||||
|
||||
root /var/www/html;
|
||||
|
||||
location /tt-rss/cache {
|
||||
aio threads;
|
||||
internal;
|
||||
}
|
||||
|
||||
location /tt-rss/backups {
|
||||
internal;
|
||||
}
|
||||
|
||||
location ~ \.php$ {
|
||||
# regex to split $uri to $fastcgi_script_name and $fastcgi_path
|
||||
fastcgi_split_path_info ^(.+?\.php)(/.*)$;
|
||||
|
||||
# Check that the PHP script exists before passing it
|
||||
try_files $fastcgi_script_name =404;
|
||||
|
||||
# Bypass the fact that try_files resets $fastcgi_path_info
|
||||
# see: http://trac.nginx.org/nginx/ticket/321
|
||||
set $path_info $fastcgi_path_info;
|
||||
fastcgi_param PATH_INFO $path_info;
|
||||
|
||||
fastcgi_index index.php;
|
||||
include fastcgi.conf;
|
||||
|
||||
fastcgi_pass app;
|
||||
}
|
||||
|
||||
location / {
|
||||
try_files $uri $uri/ =404;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
|
@ -0,0 +1,123 @@
|
|||
# yaml-language-server: $schema=https://json.schemastore.org/github-workflow.json
|
||||
|
||||
name: build
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- "master"
|
||||
workflow_dispatch: {}
|
||||
|
||||
defaults:
|
||||
run:
|
||||
shell: sh
|
||||
|
||||
jobs:
|
||||
phpdoc:
|
||||
runs-on: alpine-3.16
|
||||
steps:
|
||||
- uses: https://gitea.com/actions/checkout@v3
|
||||
|
||||
- name: phpdoc
|
||||
run: php81 /phpDocumentor.phar -d classes -d include -t phpdoc --visibility=public
|
||||
|
||||
- name: prepare ssh
|
||||
run: |
|
||||
mkdir -p ~/.ssh
|
||||
echo "${{ secrets.APK_DEPLOY_SSH_KEY }}" | tr -d \\r > ~/.ssh/id_ed25519
|
||||
chmod 600 ~/.ssh/id_ed25519
|
||||
|
||||
- name: upload results
|
||||
run: rsync -av -e 'ssh -o StrictHostKeyChecking=no' phpdoc/ ${{ secrets.APK_DEPLOY_USER }}@${{ secrets.APK_DEPLOY_HOST }}:phpdoc/
|
||||
|
||||
build:
|
||||
runs-on: alpine-3.16
|
||||
steps:
|
||||
- uses: https://gitea.com/actions/checkout@v3
|
||||
|
||||
- name: eslint
|
||||
run: npx eslint js plugins
|
||||
|
||||
- run: rm -rf node_modules
|
||||
|
||||
- name: phpunit
|
||||
run: php81 ./vendor/bin/phpunit
|
||||
|
||||
- name: calculate cache key hash
|
||||
uses: actions/go-hashfiles@v0.0.1
|
||||
id: cache-hash
|
||||
with:
|
||||
patterns: |
|
||||
classes/*.php
|
||||
include/*.php
|
||||
plugins/**/*.php
|
||||
|
||||
- name: phpstan
|
||||
run: php81 -d memory_limit=-1 ./vendor/bin/phpstan --memory-limit=2G
|
||||
|
||||
- name: setup qemu
|
||||
uses: https://github.com/docker/setup-qemu-action@v2
|
||||
|
||||
- name: setup buildx
|
||||
uses: https://github.com/docker/setup-buildx-action@v2
|
||||
|
||||
- name: login to registry
|
||||
uses: https://github.com/docker/login-action@v2
|
||||
with:
|
||||
registry: ${{ secrets.REGISTRY_HOST }}
|
||||
username: ${{ secrets.REGISTRY_USER }}
|
||||
password: ${{ secrets.REGISTRY_PASSWORD }}
|
||||
|
||||
- name: login to docker hub
|
||||
uses: https://github.com/docker/login-action@v2
|
||||
with:
|
||||
username: ${{ secrets.DOCKER_HUB_USER }}
|
||||
password: ${{ secrets.DOCKER_HUB_TOKEN }}
|
||||
|
||||
- name: get docker meta for web-nginx
|
||||
id: meta_web_nginx
|
||||
uses: https://github.com/docker/metadata-action@v4
|
||||
with:
|
||||
images: |
|
||||
${{ secrets.REGISTRY_HOST }}/cthulhoo/ttrss-web-nginx
|
||||
cthulhoo/ttrss-web-nginx
|
||||
tags: |
|
||||
type=sha,prefix={{ date 'YY.MM-' tz='UTC'}}
|
||||
type=raw,value=latest,enable={{ is_default_branch }}
|
||||
|
||||
- name: build web-nginx image
|
||||
uses: https://github.com/docker/build-push-action@v4
|
||||
with:
|
||||
push: true
|
||||
platforms: linux/amd64,linux/arm64,linux/arm/v7
|
||||
context: .docker/web-nginx
|
||||
tags: ${{ steps.meta_web_nginx.outputs.tags }}
|
||||
labels: ${{ steps.meta_web_nginx.outputs.labels }}
|
||||
provenance: false
|
||||
cache-from: type=registry,ref=${{ secrets.REGISTRY_HOST }}/cthulhoo/ttrss-web-nginx:latest
|
||||
cache-to: type=inline
|
||||
|
||||
- name: get docker meta for app
|
||||
id: meta_app
|
||||
uses: https://github.com/docker/metadata-action@v4
|
||||
with:
|
||||
images: |
|
||||
${{ secrets.REGISTRY_HOST }}/cthulhoo/ttrss-fpm-pgsql-static
|
||||
cthulhoo/ttrss-fpm-pgsql-static
|
||||
tags: |
|
||||
type=sha,prefix={{ date 'YY.MM-' tz='UTC'}}
|
||||
type=raw,value=latest,enable={{ is_default_branch }}
|
||||
|
||||
- name: build app image
|
||||
uses: https://github.com/docker/build-push-action@v4
|
||||
with:
|
||||
push: true
|
||||
platforms: linux/amd64,linux/arm64,linux/arm/v7
|
||||
context: .docker/app
|
||||
build-contexts:
|
||||
app-src=.
|
||||
tags: ${{ steps.meta_app.outputs.tags }}
|
||||
labels: ${{ steps.meta_app.outputs.labels }}
|
||||
provenance: false
|
||||
cache-from: type=registry,ref=${{ secrets.REGISTRY_HOST }}/cthulhoo/ttrss-fpm-pgsql-static:latest
|
||||
cache-to: type=inline
|
|
@ -0,0 +1,33 @@
|
|||
# yaml-language-server: $schema=https://json.schemastore.org/github-workflow.json
|
||||
|
||||
name: lint
|
||||
|
||||
on:
|
||||
push:
|
||||
branches-ignore:
|
||||
- "master"
|
||||
workflow_dispatch: {}
|
||||
pull_request: {}
|
||||
|
||||
defaults:
|
||||
run:
|
||||
shell: sh
|
||||
|
||||
jobs:
|
||||
lint:
|
||||
runs-on: alpine-3.16
|
||||
steps:
|
||||
- name: checkout source
|
||||
uses: actions/checkout@v3
|
||||
|
||||
- name: npm install
|
||||
run: npm install
|
||||
|
||||
- name: eslint
|
||||
run: npx eslint js plugins
|
||||
|
||||
- name: phpunit
|
||||
run: php81 ./vendor/bin/phpunit
|
||||
|
||||
- name: phpstan
|
||||
run: php81 -d memory_limit=-1 ./vendor/bin/phpstan --memory-limit=2G
|
|
@ -3,7 +3,6 @@ Thumbs.db
|
|||
/messages.mo
|
||||
/node_modules
|
||||
/locale/**/*.po~
|
||||
/package-lock.json
|
||||
/plugins.local/*
|
||||
/themes.local/*
|
||||
/config.php
|
||||
|
|
|
@ -0,0 +1,150 @@
|
|||
stages:
|
||||
- lint
|
||||
- build
|
||||
|
||||
.build-master:
|
||||
image:
|
||||
name: ${CI_DOCKER_IMAGE}
|
||||
stage: build
|
||||
rules:
|
||||
- if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH && $CI_PIPELINE_SOURCE != "web"
|
||||
changes:
|
||||
- '**/*.php'
|
||||
- '**/*.js'
|
||||
- '.docker/**/*'
|
||||
- if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH
|
||||
when: manual
|
||||
before_script:
|
||||
- docker login -u ${CI_REGISTRY_USER} -p ${CI_REGISTRY_PASSWORD} ${CI_REGISTRY}
|
||||
- docker login -u ${DOCKER_HUB_USER} -p ${DOCKER_HUB_TOKEN}
|
||||
|
||||
- docker run --privileged --rm registry.fakecake.org/docker.io/tonistiigi/binfmt --install all
|
||||
- docker buildx create --name mp-builder --driver docker-container --bootstrap --use
|
||||
|
||||
script:
|
||||
- BUILD_TIMESTAMP=$(date -d $(echo ${CI_COMMIT_TIMESTAMP} | cut -b 1-10) +%y.%m)
|
||||
|
||||
- docker buildx build
|
||||
--push
|
||||
--platform linux/amd64,linux/arm64,linux/arm/v7
|
||||
--tag ${CI_REGISTRY}/cthulhoo/${CI_JOB_NAME}:${BUILD_TIMESTAMP}-${CI_COMMIT_SHORT_SHA}
|
||||
--tag ${CI_REGISTRY}/cthulhoo/${CI_JOB_NAME}:latest
|
||||
--tag cthulhoo/${CI_JOB_NAME}:${BUILD_TIMESTAMP}-${CI_COMMIT_SHORT_SHA}
|
||||
--tag cthulhoo/${CI_JOB_NAME}:latest
|
||||
--build-context app-src=.
|
||||
--cache-from type=registry,ref=${CI_REGISTRY}/cthulhoo/${CI_JOB_NAME}:latest
|
||||
--cache-to type=inline
|
||||
${BUILD_CONTEXT}
|
||||
|
||||
# note: CI_REGISTRY, etc. variables are privileged
|
||||
#
|
||||
# .build-branch:
|
||||
# image:
|
||||
# name: ${CI_DOCKER_IMAGE}
|
||||
# stage: build
|
||||
# rules:
|
||||
# - if: $CI_COMMIT_BRANCH && $CI_COMMIT_BRANCH != $CI_DEFAULT_BRANCH && $CI_PIPELINE_SOURCE != "web"
|
||||
# changes:
|
||||
# - '**/*.php'
|
||||
# - '**/*.js'
|
||||
# - '.docker/**/*'
|
||||
# - if: $CI_COMMIT_BRANCH && $CI_COMMIT_BRANCH != $CI_DEFAULT_BRANCH
|
||||
# when: manual
|
||||
# before_script:
|
||||
# - docker buildx create --name mp-builder --driver docker-container --bootstrap --use
|
||||
# - CONTAINER_NAME=$(echo ${CI_JOB_NAME} | sed 's/branch://')
|
||||
# script:
|
||||
# - docker buildx build
|
||||
# --push
|
||||
# --platform linux/amd64
|
||||
# --tag ${CI_REGISTRY}/cthulhoo/$CONTAINER_NAME:${CI_COMMIT_BRANCH}-${CI_COMMIT_SHORT_SHA}
|
||||
# --tag ${CI_REGISTRY}/cthulhoo/$CONTAINER_NAME:${CI_COMMIT_BRANCH}
|
||||
# --build-context app-src=.
|
||||
# --cache-from type=registry,ref=${CI_REGISTRY}/cthulhoo/$CONTAINER_NAME:${CI_COMMIT_BRANCH}
|
||||
# --cache-to type=inline
|
||||
# ${BUILD_CONTEXT}
|
||||
|
||||
phpunit:
|
||||
image:
|
||||
name: ${CI_DOCKER_IMAGE}
|
||||
stage: lint
|
||||
rules:
|
||||
- if: $CI_COMMIT_BRANCH && $CI_PIPELINE_SOURCE != "web"
|
||||
changes:
|
||||
- '**/*.php'
|
||||
- if: $CI_PIPELINE_SOURCE == 'merge_request_event'
|
||||
- if: $CI_COMMIT_BRANCH
|
||||
when: manual
|
||||
allow_failure: true
|
||||
script:
|
||||
- php81 ./vendor/bin/phpunit
|
||||
|
||||
eslint:
|
||||
image:
|
||||
name: ${CI_DOCKER_IMAGE}
|
||||
stage: lint
|
||||
rules:
|
||||
- if: $CI_COMMIT_BRANCH && $CI_PIPELINE_SOURCE != "web"
|
||||
changes:
|
||||
- '**/*.js'
|
||||
- if: $CI_PIPELINE_SOURCE == 'merge_request_event'
|
||||
- if: $CI_COMMIT_BRANCH
|
||||
when: manual
|
||||
allow_failure: true
|
||||
script:
|
||||
- npm install
|
||||
- npx eslint js plugins
|
||||
|
||||
phpstan:
|
||||
image:
|
||||
name: ${CI_DOCKER_IMAGE}
|
||||
needs:
|
||||
- phpunit
|
||||
stage: lint
|
||||
rules:
|
||||
- if: $CI_COMMIT_BRANCH && $CI_PIPELINE_SOURCE != "web"
|
||||
changes:
|
||||
- '**/*.php'
|
||||
- if: $CI_PIPELINE_SOURCE == 'merge_request_event'
|
||||
- if: $CI_COMMIT_BRANCH
|
||||
when: manual
|
||||
allow_failure: true
|
||||
script:
|
||||
- php81 -d memory_limit=-1 ./vendor/bin/phpstan --memory-limit=2G
|
||||
|
||||
ttrss-web-nginx:
|
||||
extends: .build-master
|
||||
variables:
|
||||
BUILD_CONTEXT: ${CI_PROJECT_DIR}/.docker/web-nginx
|
||||
|
||||
ttrss-fpm-pgsql-static:
|
||||
extends: .build-master
|
||||
variables:
|
||||
BUILD_CONTEXT: ${CI_PROJECT_DIR}/.docker/app
|
||||
|
||||
# branch:ttrss-web-nginx:
|
||||
# extends: .build-branch
|
||||
# variables:
|
||||
# BUILD_CONTEXT: ${CI_PROJECT_DIR}/.docker/web-nginx
|
||||
|
||||
# branch:ttrss-fpm-pgsql-static:
|
||||
# extends: .build-branch
|
||||
# variables:
|
||||
# BUILD_CONTEXT: ${CI_PROJECT_DIR}/.docker/app
|
||||
|
||||
phpdoc:
|
||||
image:
|
||||
name: ${CI_DOCKER_IMAGE}
|
||||
stage: build
|
||||
rules:
|
||||
- if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH && $CI_PIPELINE_SOURCE != "web"
|
||||
changes:
|
||||
- '**/*.php'
|
||||
- if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH
|
||||
when: manual
|
||||
script:
|
||||
- php81 /phpDocumentor.phar -d classes -d include -t phpdoc --visibility=public
|
||||
- mkdir -p ~/.ssh &&
|
||||
cp ${PHPDOC_DEPLOY_SSH_KEY} ~/.ssh/id_ed25519 &&
|
||||
chmod 0600 ~/.ssh/id_ed25519
|
||||
- rsync -av -e 'ssh -o StrictHostKeyChecking=no' phpdoc/ ${PHPDOC_DEPLOY_HOST}:phpdoc/
|
|
@ -1,33 +0,0 @@
|
|||
pipeline {
|
||||
agent any
|
||||
|
||||
options {
|
||||
buildDiscarder(logRotator(numToKeepStr: '5'))
|
||||
}
|
||||
|
||||
stages {
|
||||
stage('phpunit') {
|
||||
steps {
|
||||
sh """
|
||||
docker run --rm \
|
||||
--workdir /app \
|
||||
-v ${env.WORKSPACE}:/app \
|
||||
registry.fakecake.org/php:8.1-cli \
|
||||
php ./vendor/bin/phpunit
|
||||
"""
|
||||
}
|
||||
}
|
||||
stage('phpstan') {
|
||||
steps {
|
||||
sh """
|
||||
# php -d memory_limit=-1 ....
|
||||
docker run --rm \
|
||||
--workdir /app \
|
||||
-v ${env.WORKSPACE}:/app \
|
||||
registry.fakecake.org/php:8.1-cli \
|
||||
php -d memory_limit=-1 ./vendor/bin/phpstan --memory-limit=2G
|
||||
"""
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,7 +1,7 @@
|
|||
<?php
|
||||
class API extends Handler {
|
||||
|
||||
const API_LEVEL = 18;
|
||||
const API_LEVEL = 20;
|
||||
|
||||
const STATUS_OK = 0;
|
||||
const STATUS_ERR = 1;
|
||||
|
@ -12,6 +12,7 @@ class API extends Handler {
|
|||
const E_INCORRECT_USAGE = "INCORRECT_USAGE";
|
||||
const E_UNKNOWN_METHOD = "UNKNOWN_METHOD";
|
||||
const E_OPERATION_FAILED = "E_OPERATION_FAILED";
|
||||
const E_NOT_FOUND = "E_NOT_FOUND";
|
||||
|
||||
/** @var int|null */
|
||||
private $seq;
|
||||
|
@ -98,7 +99,7 @@ class API extends Handler {
|
|||
}
|
||||
|
||||
function isLoggedIn(): bool {
|
||||
return $this->_wrap(self::STATUS_OK, array("status" => $_SESSION["uid"] != ''));
|
||||
return $this->_wrap(self::STATUS_OK, array("status" => (bool)($_SESSION["uid"] ?? '')));
|
||||
}
|
||||
|
||||
function getUnread(): bool {
|
||||
|
@ -168,7 +169,7 @@ class API extends Handler {
|
|||
}
|
||||
}
|
||||
|
||||
foreach ([-2,-1,0] as $cat_id) {
|
||||
foreach ([Feeds::CATEGORY_LABELS, Feeds::CATEGORY_SPECIAL, Feeds::CATEGORY_UNCATEGORIZED] as $cat_id) {
|
||||
if ($include_empty || !$this->_is_cat_empty($cat_id)) {
|
||||
$unread = Feeds::_get_counters($cat_id, true, true);
|
||||
|
||||
|
@ -503,9 +504,14 @@ class API extends Handler {
|
|||
}
|
||||
|
||||
function shareToPublished(): bool {
|
||||
$title = strip_tags(clean($_REQUEST["title"]));
|
||||
$url = strip_tags(clean($_REQUEST["url"]));
|
||||
$content = strip_tags(clean($_REQUEST["content"]));
|
||||
$title = clean($_REQUEST["title"]);
|
||||
$url = clean($_REQUEST["url"]);
|
||||
$sanitize_content = self::_param_to_bool($_REQUEST["sanitize"] ?? true);
|
||||
|
||||
if ($sanitize_content)
|
||||
$content = clean($_REQUEST["content"]);
|
||||
else
|
||||
$content = $_REQUEST["content"];
|
||||
|
||||
if (Article::_create_published_article($title, $url, $content, "", $_SESSION["uid"])) {
|
||||
return $this->_wrap(self::STATUS_OK, array("status" => 'OK'));
|
||||
|
@ -522,8 +528,8 @@ class API extends Handler {
|
|||
|
||||
/* Labels */
|
||||
|
||||
/* API only: -4 All feeds, including virtual feeds */
|
||||
if ($cat_id == -4 || $cat_id == -2) {
|
||||
/* API only: -4 (Feeds::CATEGORY_ALL) All feeds, including virtual feeds */
|
||||
if ($cat_id == Feeds::CATEGORY_ALL || $cat_id == Feeds::CATEGORY_LABELS) {
|
||||
$counters = Counters::get_labels();
|
||||
|
||||
foreach (array_values($counters) as $cv) {
|
||||
|
@ -534,7 +540,7 @@ class API extends Handler {
|
|||
'id' => (int) $cv['id'],
|
||||
'title' => $cv['description'],
|
||||
'unread' => $cv['counter'],
|
||||
'cat_id' => -2,
|
||||
'cat_id' => Feeds::CATEGORY_LABELS,
|
||||
];
|
||||
|
||||
array_push($feeds, $row);
|
||||
|
@ -544,7 +550,7 @@ class API extends Handler {
|
|||
|
||||
/* Virtual feeds */
|
||||
|
||||
$vfeeds = PluginHost::getInstance()->get_feeds(-1);
|
||||
$vfeeds = PluginHost::getInstance()->get_feeds(Feeds::CATEGORY_SPECIAL);
|
||||
|
||||
if (is_array($vfeeds)) {
|
||||
foreach ($vfeeds as $feed) {
|
||||
|
@ -559,7 +565,7 @@ class API extends Handler {
|
|||
'id' => PluginHost::pfeed_to_feed_id($feed['id']),
|
||||
'title' => $feed['title'],
|
||||
'unread' => $unread,
|
||||
'cat_id' => -1,
|
||||
'cat_id' => Feeds::CATEGORY_SPECIAL,
|
||||
];
|
||||
|
||||
array_push($feeds, $row);
|
||||
|
@ -567,8 +573,9 @@ class API extends Handler {
|
|||
}
|
||||
}
|
||||
|
||||
if ($cat_id == -4 || $cat_id == -1) {
|
||||
foreach ([-1, -2, -3, -4, -6, 0] as $i) {
|
||||
if ($cat_id == Feeds::CATEGORY_ALL || $cat_id == Feeds::CATEGORY_SPECIAL) {
|
||||
foreach ([Feeds::FEED_STARRED, Feeds::FEED_PUBLISHED, Feeds::FEED_FRESH,
|
||||
Feeds::FEED_ALL, Feeds::FEED_RECENTLY_READ, Feeds::FEED_ARCHIVED] as $i) {
|
||||
$unread = Feeds::_get_counters($i, false, true);
|
||||
|
||||
if ($unread || !$unread_only) {
|
||||
|
@ -578,7 +585,7 @@ class API extends Handler {
|
|||
'id' => $i,
|
||||
'title' => $title,
|
||||
'unread' => $unread,
|
||||
'cat_id' => -1,
|
||||
'cat_id' => Feeds::CATEGORY_SPECIAL,
|
||||
];
|
||||
|
||||
array_push($feeds, $row);
|
||||
|
@ -614,7 +621,7 @@ class API extends Handler {
|
|||
|
||||
/* Real feeds */
|
||||
|
||||
/* API only: -3 All feeds, excluding virtual feeds (e.g. Labels and such) */
|
||||
/* API only: -3 (Feeds::CATEGORY_ALL_EXCEPT_VIRTUAL) All feeds, excluding virtual feeds (e.g. Labels and such) */
|
||||
$feeds_obj = ORM::for_table('ttrss_feeds')
|
||||
->select_many('id', 'feed_url', 'cat_id', 'title', 'order_id')
|
||||
->select_expr(SUBSTRING_FOR_DATE.'(last_updated,1,19)', 'last_updated')
|
||||
|
@ -625,7 +632,7 @@ class API extends Handler {
|
|||
if ($limit) $feeds_obj->limit($limit);
|
||||
if ($offset) $feeds_obj->offset($offset);
|
||||
|
||||
if ($cat_id != -3 && $cat_id != -4) {
|
||||
if ($cat_id != Feeds::CATEGORY_ALL_EXCEPT_VIRTUAL && $cat_id != Feeds::CATEGORY_ALL) {
|
||||
$feeds_obj->where_raw('(cat_id = ? OR (? = 0 AND cat_id IS NULL))', [$cat_id, $cat_id]);
|
||||
}
|
||||
|
||||
|
@ -912,15 +919,26 @@ class API extends Handler {
|
|||
array("categories" => $pf->_makefeedtree()));
|
||||
}
|
||||
|
||||
function getFeedIcon(): bool {
|
||||
$id = (int)$_REQUEST['id'];
|
||||
$cache = DiskCache::instance('feed-icons');
|
||||
|
||||
if ($cache->exists((string)$id)) {
|
||||
return $cache->send((string)$id) > 0;
|
||||
} else {
|
||||
return $this->_wrap(self::STATUS_ERR, array("error" => self::E_NOT_FOUND));
|
||||
}
|
||||
}
|
||||
|
||||
// only works for labels or uncategorized for the time being
|
||||
private function _is_cat_empty(int $id): bool {
|
||||
if ($id == -2) {
|
||||
if ($id == Feeds::CATEGORY_LABELS) {
|
||||
$label_count = ORM::for_table('ttrss_labels2')
|
||||
->where('owner_uid', $_SESSION['uid'])
|
||||
->count();
|
||||
|
||||
return $label_count == 0;
|
||||
} else if ($id == 0) {
|
||||
} else if ($id == Feeds::CATEGORY_UNCATEGORIZED) {
|
||||
$uncategorized_count = ORM::for_table('ttrss_feeds')
|
||||
->where_null('cat_id')
|
||||
->where('owner_uid', $_SESSION['uid'])
|
||||
|
|
|
@ -541,6 +541,10 @@ class Config {
|
|||
array_push($errors, "PHP support for JSON is required, but was not found.");
|
||||
}
|
||||
|
||||
if (!function_exists("flock")) {
|
||||
array_push($errors, "PHP support for flock() function is required.");
|
||||
}
|
||||
|
||||
if (!class_exists("PDO")) {
|
||||
array_push($errors, "PHP support for PDO is required but was not found.");
|
||||
}
|
||||
|
|
|
@ -60,8 +60,8 @@ class Counters {
|
|||
|
||||
/* Labels category */
|
||||
|
||||
$cv = array("id" => -2, "kind" => "cat",
|
||||
"counter" => Feeds::_get_cat_unread(-2));
|
||||
$cv = array("id" => Feeds::CATEGORY_LABELS, "kind" => "cat",
|
||||
"counter" => Feeds::_get_cat_unread(Feeds::CATEGORY_LABELS));
|
||||
|
||||
array_push($ret, $cv);
|
||||
|
||||
|
@ -244,28 +244,29 @@ class Counters {
|
|||
|
||||
$ret = [];
|
||||
|
||||
for ($i = 0; $i >= -4; $i--) {
|
||||
foreach ([Feeds::FEED_ARCHIVED, Feeds::FEED_STARRED, Feeds::FEED_PUBLISHED,
|
||||
Feeds::FEED_FRESH, Feeds::FEED_ALL] as $feed_id) {
|
||||
|
||||
$count = Feeds::_get_counters($i, false, true);
|
||||
$count = Feeds::_get_counters($feed_id, false, true);
|
||||
|
||||
if ($i == 0 || $i == -1 || $i == -2)
|
||||
$auxctr = Feeds::_get_counters($i, false);
|
||||
if (in_array($feed_id, [Feeds::FEED_ARCHIVED, Feeds::FEED_STARRED, Feeds::FEED_PUBLISHED]))
|
||||
$auxctr = Feeds::_get_counters($feed_id, false);
|
||||
else
|
||||
$auxctr = 0;
|
||||
|
||||
$cv = [
|
||||
"id" => $i,
|
||||
"id" => $feed_id,
|
||||
"counter" => (int) $count,
|
||||
"auxcounter" => (int) $auxctr
|
||||
];
|
||||
|
||||
if ($i == -1)
|
||||
if ($feed_id == Feeds::FEED_STARRED)
|
||||
$cv["markedcounter"] = $auxctr;
|
||||
|
||||
array_push($ret, $cv);
|
||||
}
|
||||
|
||||
$feeds = PluginHost::getInstance()->get_feeds(-1);
|
||||
$feeds = PluginHost::getInstance()->get_feeds(Feeds::CATEGORY_SPECIAL);
|
||||
|
||||
if (is_array($feeds)) {
|
||||
foreach ($feeds as $feed) {
|
||||
|
|
|
@ -84,15 +84,6 @@ class FeedItem_RSS extends FeedItem_Common {
|
|||
/** @var DOMElement|null */
|
||||
$contentB = $this->elem->getElementsByTagName("description")->item(0);
|
||||
|
||||
if ($contentA && !$contentB) {
|
||||
return $this->subtree_or_text($contentA);
|
||||
}
|
||||
|
||||
|
||||
if ($contentB && !$contentA) {
|
||||
return $this->subtree_or_text($contentB);
|
||||
}
|
||||
|
||||
if ($contentA && $contentB) {
|
||||
$resultA = $this->subtree_or_text($contentA);
|
||||
$resultB = $this->subtree_or_text($contentB);
|
||||
|
@ -100,6 +91,14 @@ class FeedItem_RSS extends FeedItem_Common {
|
|||
return mb_strlen($resultA) > mb_strlen($resultB) ? $resultA : $resultB;
|
||||
}
|
||||
|
||||
if ($contentA) {
|
||||
return $this->subtree_or_text($contentA);
|
||||
}
|
||||
|
||||
if ($contentB) {
|
||||
return $this->subtree_or_text($contentB);
|
||||
}
|
||||
|
||||
return '';
|
||||
}
|
||||
|
||||
|
|
|
@ -2,8 +2,52 @@
|
|||
require_once "colors.php";
|
||||
|
||||
class Feeds extends Handler_Protected {
|
||||
const NEVER_GROUP_FEEDS = [ -6, 0 ];
|
||||
const NEVER_GROUP_BY_DATE = [ -2, -1, -3 ];
|
||||
/** special feed for archived articles */
|
||||
const FEED_ARCHIVED = 0;
|
||||
|
||||
/** special feed for starred articles */
|
||||
const FEED_STARRED = -1;
|
||||
|
||||
/** special feed for published articles */
|
||||
const FEED_PUBLISHED = -2;
|
||||
|
||||
/** special feed for archived articles */
|
||||
const FEED_FRESH = -3;
|
||||
|
||||
/** special feed for all articles */
|
||||
const FEED_ALL = -4;
|
||||
|
||||
/**
|
||||
* a special case feed used to display auxiliary information when there's nothing to load (e.g. no stuff in fresh feed)
|
||||
*
|
||||
* TODO: Remove this and 'Feeds::_generate_dashboard_feed()'? It only seems to be used if 'Feeds::view()' (also potentially removable)
|
||||
* gets passed the ID.
|
||||
*/
|
||||
const FEED_DASHBOARD = -5;
|
||||
|
||||
/** special feed for recently read articles */
|
||||
const FEED_RECENTLY_READ = -6;
|
||||
|
||||
/** special feed for error scenarios (e.g. feed not found) */
|
||||
const FEED_ERROR = -7;
|
||||
|
||||
/** special "category" for uncategorized articles */
|
||||
const CATEGORY_UNCATEGORIZED = 0;
|
||||
|
||||
/** special category for "special" articles (e.g. Starred, Published, Archived, plugin-provided, etc.) */
|
||||
const CATEGORY_SPECIAL = -1;
|
||||
|
||||
/** special category for labels */
|
||||
const CATEGORY_LABELS = -2;
|
||||
|
||||
/** special category for all feeds, excluding virtual feeds (e.g. labels and such) */
|
||||
const CATEGORY_ALL_EXCEPT_VIRTUAL = -3;
|
||||
|
||||
/** special category for all feeds, including virtual feeds (e.g. labels and such) */
|
||||
const CATEGORY_ALL = -4;
|
||||
|
||||
const NEVER_GROUP_FEEDS = [ Feeds::FEED_RECENTLY_READ, Feeds::FEED_ARCHIVED ];
|
||||
const NEVER_GROUP_BY_DATE = [ Feeds::FEED_PUBLISHED, Feeds::FEED_STARRED, Feeds::FEED_FRESH ];
|
||||
|
||||
/** @var int|float int on 64-bit, float on 32-bit */
|
||||
private $viewfeed_timestamp;
|
||||
|
@ -205,7 +249,7 @@ class Feeds extends Handler_Protected {
|
|||
|
||||
// normalize archived feed
|
||||
if ($line['feed_id'] === null) {
|
||||
$line['feed_id'] = 0;
|
||||
$line['feed_id'] = Feeds::FEED_ARCHIVED;
|
||||
$line["feed_title"] = __("Archived articles");
|
||||
}
|
||||
|
||||
|
@ -478,10 +522,7 @@ class Feeds extends Handler_Protected {
|
|||
|
||||
if (is_numeric($feed)) $feed = (int) $feed;
|
||||
|
||||
/* Feed -5 is a special case: it is used to display auxiliary information
|
||||
* when there's nothing to load - e.g. no stuff in fresh feed */
|
||||
|
||||
if ($feed == -5) {
|
||||
if ($feed == Feeds::FEED_DASHBOARD) {
|
||||
print json_encode($this->_generate_dashboard_feed());
|
||||
return;
|
||||
}
|
||||
|
@ -566,7 +607,7 @@ class Feeds extends Handler_Protected {
|
|||
private function _generate_dashboard_feed(): array {
|
||||
$reply = array();
|
||||
|
||||
$reply['headlines']['id'] = -5;
|
||||
$reply['headlines']['id'] = Feeds::FEED_DASHBOARD;
|
||||
$reply['headlines']['is_cat'] = false;
|
||||
|
||||
$reply['headlines']['toolbar'] = '';
|
||||
|
@ -610,7 +651,7 @@ class Feeds extends Handler_Protected {
|
|||
private function _generate_error_feed(string $error): array {
|
||||
$reply = array();
|
||||
|
||||
$reply['headlines']['id'] = -7;
|
||||
$reply['headlines']['id'] = Feeds::FEED_ERROR;
|
||||
$reply['headlines']['is_cat'] = false;
|
||||
|
||||
$reply['headlines']['toolbar'] = '';
|
||||
|
@ -706,6 +747,7 @@ class Feeds extends Handler_Protected {
|
|||
<?= javascript_tag("js/common.js") ?>
|
||||
<?= javascript_tag("lib/dojo/dojo.js") ?>
|
||||
<?= javascript_tag("lib/dojo/tt-rss-layer.js") ?>
|
||||
<?= Config::get_override_links() ?>
|
||||
</head>
|
||||
<body class="flat ttrss_utility feed_debugger css_loading">
|
||||
<script type="text/javascript">
|
||||
|
@ -826,7 +868,9 @@ class Feeds extends Handler_Protected {
|
|||
|
||||
if ($feed_id >= 0) {
|
||||
|
||||
if ($feed_id > 0) {
|
||||
if ($feed_id == Feeds::CATEGORY_UNCATEGORIZED) {
|
||||
$cat_qpart = "cat_id IS NULL";
|
||||
} else {
|
||||
$children = self::_get_child_cats($feed_id, $owner_uid);
|
||||
array_push($children, $feed_id);
|
||||
$children = array_map("intval", $children);
|
||||
|
@ -834,8 +878,6 @@ class Feeds extends Handler_Protected {
|
|||
$children = join(",", $children);
|
||||
|
||||
$cat_qpart = "cat_id IN ($children)";
|
||||
} else {
|
||||
$cat_qpart = "cat_id IS NULL";
|
||||
}
|
||||
|
||||
$sth = $pdo->prepare("UPDATE ttrss_user_entries
|
||||
|
@ -846,7 +888,7 @@ class Feeds extends Handler_Protected {
|
|||
(SELECT id FROM ttrss_feeds WHERE $cat_qpart) AND $date_qpart AND $search_qpart) as tmp)");
|
||||
$sth->execute([$owner_uid]);
|
||||
|
||||
} else if ($feed_id == -2) {
|
||||
} else if ($feed_id == Feeds::CATEGORY_LABELS) {
|
||||
|
||||
$sth = $pdo->prepare("UPDATE ttrss_user_entries
|
||||
SET unread = false,last_read = NOW() WHERE (SELECT COUNT(*)
|
||||
|
@ -866,7 +908,7 @@ class Feeds extends Handler_Protected {
|
|||
|
||||
} else if ($feed_id < 0 && $feed_id > LABEL_BASE_INDEX) { // special, like starred
|
||||
|
||||
if ($feed_id == -1) {
|
||||
if ($feed_id == Feeds::FEED_STARRED) {
|
||||
$sth = $pdo->prepare("UPDATE ttrss_user_entries
|
||||
SET unread = false, last_read = NOW() WHERE ref_id IN
|
||||
(SELECT id FROM
|
||||
|
@ -875,7 +917,7 @@ class Feeds extends Handler_Protected {
|
|||
$sth->execute([$owner_uid]);
|
||||
}
|
||||
|
||||
if ($feed_id == -2) {
|
||||
if ($feed_id == Feeds::FEED_PUBLISHED) {
|
||||
$sth = $pdo->prepare("UPDATE ttrss_user_entries
|
||||
SET unread = false, last_read = NOW() WHERE ref_id IN
|
||||
(SELECT id FROM
|
||||
|
@ -884,7 +926,7 @@ class Feeds extends Handler_Protected {
|
|||
$sth->execute([$owner_uid]);
|
||||
}
|
||||
|
||||
if ($feed_id == -3) {
|
||||
if ($feed_id == Feeds::FEED_FRESH) {
|
||||
|
||||
$intl = (int) get_pref(Prefs::FRESH_ARTICLE_MAX_AGE);
|
||||
|
||||
|
@ -903,7 +945,7 @@ class Feeds extends Handler_Protected {
|
|||
$sth->execute([$owner_uid]);
|
||||
}
|
||||
|
||||
if ($feed_id == -4) {
|
||||
if ($feed_id == Feeds::FEED_ALL) {
|
||||
$sth = $pdo->prepare("UPDATE ttrss_user_entries
|
||||
SET unread = false, last_read = NOW() WHERE ref_id IN
|
||||
(SELECT id FROM
|
||||
|
@ -972,7 +1014,7 @@ class Feeds extends Handler_Protected {
|
|||
} else {
|
||||
return 0;
|
||||
}
|
||||
} else if ($n_feed == -6) {
|
||||
} else if ($n_feed == Feeds::FEED_RECENTLY_READ) {
|
||||
return 0;
|
||||
// tags
|
||||
} else if ($feed != "0" && $n_feed == 0) {
|
||||
|
@ -988,11 +1030,11 @@ class Feeds extends Handler_Protected {
|
|||
// Handle 'SUM()' returning null if there are no results
|
||||
return $row["count"] ?? 0;
|
||||
|
||||
} else if ($n_feed == -1) {
|
||||
} else if ($n_feed == Feeds::FEED_STARRED) {
|
||||
$match_part = "marked = true";
|
||||
} else if ($n_feed == -2) {
|
||||
} else if ($n_feed == Feeds::FEED_PUBLISHED) {
|
||||
$match_part = "published = true";
|
||||
} else if ($n_feed == -3) {
|
||||
} else if ($n_feed == Feeds::FEED_FRESH) {
|
||||
$match_part = "unread = true AND score >= 0";
|
||||
|
||||
$intl = (int) get_pref(Prefs::FRESH_ARTICLE_MAX_AGE, $owner_uid);
|
||||
|
@ -1005,11 +1047,11 @@ class Feeds extends Handler_Protected {
|
|||
|
||||
$need_entries = true;
|
||||
|
||||
} else if ($n_feed == -4) {
|
||||
} else if ($n_feed == Feeds::FEED_ALL) {
|
||||
$match_part = "true";
|
||||
} else if ($n_feed >= 0) {
|
||||
|
||||
if ($n_feed != 0) {
|
||||
if ($n_feed != Feeds::FEED_ARCHIVED) {
|
||||
$match_part = sprintf("feed_id = %d", $n_feed);
|
||||
} else {
|
||||
$match_part = "feed_id IS NULL";
|
||||
|
@ -1190,17 +1232,17 @@ class Feeds extends Handler_Protected {
|
|||
*/
|
||||
static function _get_icon(int $id) {
|
||||
switch ($id) {
|
||||
case 0:
|
||||
case Feeds::FEED_ARCHIVED:
|
||||
return "archive";
|
||||
case -1:
|
||||
case Feeds::FEED_STARRED:
|
||||
return "star";
|
||||
case -2:
|
||||
case Feeds::FEED_PUBLISHED:
|
||||
return "rss_feed";
|
||||
case -3:
|
||||
case Feeds::FEED_FRESH:
|
||||
return "whatshot";
|
||||
case -4:
|
||||
case Feeds::FEED_ALL:
|
||||
return "inbox";
|
||||
case -6:
|
||||
case Feeds::FEED_RECENTLY_READ:
|
||||
return "restore";
|
||||
default:
|
||||
if ($id < LABEL_BASE_INDEX) {
|
||||
|
@ -1263,17 +1305,17 @@ class Feeds extends Handler_Protected {
|
|||
|
||||
if ($cat) {
|
||||
return self::_get_cat_title($id);
|
||||
} else if ($id == -1) {
|
||||
} else if ($id == Feeds::FEED_STARRED) {
|
||||
return __("Starred articles");
|
||||
} else if ($id == -2) {
|
||||
} else if ($id == Feeds::FEED_PUBLISHED) {
|
||||
return __("Published articles");
|
||||
} else if ($id == -3) {
|
||||
} else if ($id == Feeds::FEED_FRESH) {
|
||||
return __("Fresh articles");
|
||||
} else if ($id == -4) {
|
||||
} else if ($id == Feeds::FEED_ALL) {
|
||||
return __("All articles");
|
||||
} else if ($id === 0) {
|
||||
} else if ($id === Feeds::FEED_ARCHIVED) {
|
||||
return __("Archived articles");
|
||||
} else if ($id == -6) {
|
||||
} else if ($id == Feeds::FEED_RECENTLY_READ) {
|
||||
return __("Recently read");
|
||||
} else if ($id < LABEL_BASE_INDEX) {
|
||||
|
||||
|
@ -1349,9 +1391,9 @@ class Feeds extends Handler_Protected {
|
|||
if ($row = $sth->fetch()) {
|
||||
return (int) $row["unread"];
|
||||
}
|
||||
} else if ($cat == -1) {
|
||||
} else if ($cat == Feeds::CATEGORY_SPECIAL) {
|
||||
return 0;
|
||||
} else if ($cat == -2) {
|
||||
} else if ($cat == Feeds::CATEGORY_LABELS) {
|
||||
|
||||
$sth = $pdo->prepare("SELECT COUNT(DISTINCT article_id) AS unread
|
||||
FROM ttrss_user_entries ue, ttrss_user_labels2 l
|
||||
|
@ -1406,11 +1448,11 @@ class Feeds extends Handler_Protected {
|
|||
|
||||
static function _get_cat_title(int $cat_id): string {
|
||||
switch ($cat_id) {
|
||||
case 0:
|
||||
case Feeds::CATEGORY_UNCATEGORIZED:
|
||||
return __("Uncategorized");
|
||||
case -1:
|
||||
case Feeds::CATEGORY_SPECIAL:
|
||||
return __("Special");
|
||||
case -2:
|
||||
case Feeds::CATEGORY_LABELS:
|
||||
return __("Labels");
|
||||
default:
|
||||
$cat = ORM::for_table('ttrss_feed_categories')
|
||||
|
@ -1525,6 +1567,7 @@ class Feeds extends Handler_Protected {
|
|||
if ($search) {
|
||||
$view_query_part = " ";
|
||||
} else if ($feed != -1) {
|
||||
// not Feeds::FEED_STARRED or Feeds::CATEGORY_SPECIAL
|
||||
|
||||
$unread = Feeds::_get_counters($feed, $cat_view, true);
|
||||
|
||||
|
@ -1549,7 +1592,7 @@ class Feeds extends Handler_Protected {
|
|||
$view_query_part = " published = true AND ";
|
||||
}
|
||||
|
||||
if ($view_mode == "unread" && $feed != -6) {
|
||||
if ($view_mode == "unread" && $feed != Feeds::FEED_RECENTLY_READ) {
|
||||
$view_query_part = " unread = true AND ";
|
||||
}
|
||||
|
||||
|
@ -1593,13 +1636,13 @@ class Feeds extends Handler_Protected {
|
|||
} else {
|
||||
$query_strategy_part = "feed_id = " . $pdo->quote((string)$feed);
|
||||
}
|
||||
} else if ($feed == 0 && !$cat_view) { // archive virtual feed
|
||||
} else if ($feed == Feeds::FEED_ARCHIVED && !$cat_view) { // archive virtual feed
|
||||
$query_strategy_part = "feed_id IS NULL";
|
||||
$allow_archived = true;
|
||||
} else if ($feed == 0 && $cat_view) { // uncategorized
|
||||
} else if ($feed == Feeds::CATEGORY_UNCATEGORIZED && $cat_view) { // uncategorized
|
||||
$query_strategy_part = "cat_id IS NULL AND feed_id IS NOT NULL";
|
||||
$vfeed_query_part = "ttrss_feeds.title AS feed_title,";
|
||||
} else if ($feed == -1) { // starred virtual feed
|
||||
} else if ($feed == -1) { // starred virtual feed, Feeds::FEED_STARRED or Feeds::CATEGORY_SPECIAL
|
||||
$query_strategy_part = "marked = true";
|
||||
$vfeed_query_part = "ttrss_feeds.title AS feed_title,";
|
||||
$allow_archived = true;
|
||||
|
@ -1608,7 +1651,7 @@ class Feeds extends Handler_Protected {
|
|||
$override_order = "last_marked DESC, date_entered DESC, updated DESC";
|
||||
}
|
||||
|
||||
} else if ($feed == -2) { // published virtual feed OR labels category
|
||||
} else if ($feed == -2) { // published virtual feed (Feeds::FEED_PUBLISHED) OR labels category (Feeds::CATEGORY_LABELS)
|
||||
|
||||
if (!$cat_view) {
|
||||
$query_strategy_part = "published = true";
|
||||
|
@ -1628,7 +1671,7 @@ class Feeds extends Handler_Protected {
|
|||
ttrss_user_labels2.article_id = ref_id";
|
||||
|
||||
}
|
||||
} else if ($feed == -6) { // recently read
|
||||
} else if ($feed == Feeds::FEED_RECENTLY_READ) { // recently read
|
||||
$query_strategy_part = "unread = false AND last_read IS NOT NULL";
|
||||
|
||||
if (Config::get(Config::DB_TYPE) == "pgsql") {
|
||||
|
@ -1643,7 +1686,7 @@ class Feeds extends Handler_Protected {
|
|||
|
||||
if (!$override_order) $override_order = "last_read DESC";
|
||||
|
||||
} else if ($feed == -3) { // fresh virtual feed
|
||||
} else if ($feed == Feeds::FEED_FRESH) { // fresh virtual feed
|
||||
$query_strategy_part = "unread = true AND score >= 0";
|
||||
|
||||
$intl = (int) get_pref(Prefs::FRESH_ARTICLE_MAX_AGE, $owner_uid);
|
||||
|
@ -1655,7 +1698,7 @@ class Feeds extends Handler_Protected {
|
|||
}
|
||||
|
||||
$vfeed_query_part = "ttrss_feeds.title AS feed_title,";
|
||||
} else if ($feed == -4) { // all articles virtual feed
|
||||
} else if ($feed == Feeds::FEED_ALL) { // all articles virtual feed
|
||||
$allow_archived = true;
|
||||
$query_strategy_part = "true";
|
||||
$vfeed_query_part = "ttrss_feeds.title AS feed_title,";
|
||||
|
@ -1770,7 +1813,7 @@ class Feeds extends Handler_Protected {
|
|||
|
||||
$first_id_query_strategy_part = $query_strategy_part;
|
||||
|
||||
if ($feed == -3)
|
||||
if ($feed == Feeds::FEED_FRESH)
|
||||
$first_id_query_strategy_part = "true";
|
||||
|
||||
if (Config::get(Config::DB_TYPE) == "pgsql") {
|
||||
|
@ -1784,7 +1827,7 @@ class Feeds extends Handler_Protected {
|
|||
}
|
||||
|
||||
// except for Labels category
|
||||
if (get_pref(Prefs::HEADLINES_NO_DISTINCT, $owner_uid) && !($feed == -2 && $cat_view)) {
|
||||
if (get_pref(Prefs::HEADLINES_NO_DISTINCT, $owner_uid) && !($feed == Feeds::CATEGORY_LABELS && $cat_view)) {
|
||||
$distinct_qpart = "";
|
||||
}
|
||||
|
||||
|
|
|
@ -20,9 +20,9 @@ class Handler_Public extends Handler {
|
|||
if (!$override_order) {
|
||||
$override_order = "date_entered DESC, updated DESC";
|
||||
|
||||
if ($feed == -2 && !$is_cat) {
|
||||
if ($feed == Feeds::FEED_PUBLISHED && !$is_cat) {
|
||||
$override_order = "last_published DESC";
|
||||
} else if ($feed == -1 && !$is_cat) {
|
||||
} else if ($feed == Feeds::FEED_STARRED && !$is_cat) {
|
||||
$override_order = "last_marked DESC";
|
||||
}
|
||||
}
|
||||
|
@ -269,7 +269,7 @@ class Handler_Public extends Handler {
|
|||
|
||||
if ($fresh) {
|
||||
print ";";
|
||||
print Feeds::_get_counters(-3, false, true, $uid);
|
||||
print Feeds::_get_counters(Feeds::FEED_FRESH, false, true, $uid);
|
||||
}
|
||||
} else {
|
||||
print "-1;User not found";
|
||||
|
@ -416,10 +416,10 @@ class Handler_Public extends Handler {
|
|||
$_SESSION["login_error_msg"] ??= __("Incorrect username or password");
|
||||
}
|
||||
|
||||
$return = clean($_REQUEST['return']);
|
||||
$return = clean($_REQUEST['return'] ?? '');
|
||||
|
||||
if ($_REQUEST['return'] && mb_strpos($return, Config::get_self_url()) === 0) {
|
||||
header("Location: " . clean($_REQUEST['return']));
|
||||
if ($return && mb_strpos($return, Config::get_self_url()) === 0) {
|
||||
header("Location: $return");
|
||||
} else {
|
||||
header("Location: " . Config::get_self_url());
|
||||
}
|
||||
|
@ -451,6 +451,7 @@ class Handler_Public extends Handler {
|
|||
echo javascript_tag("lib/dojo/dojo.js");
|
||||
echo javascript_tag("lib/dojo/tt-rss-layer.js");
|
||||
?>
|
||||
<?= Config::get_override_links() ?>
|
||||
</head>
|
||||
<body class='flat ttrss_utility'>
|
||||
<div class='container'>
|
||||
|
|
|
@ -588,7 +588,7 @@ class PluginHost {
|
|||
function lookup_command(string $command) {
|
||||
$command = "-" . strtolower($command);
|
||||
|
||||
if (array_key_exists($command, $this->commands) && is_array($this->commands[$command])) {
|
||||
if (array_key_exists($command, $this->commands)) {
|
||||
return $this->commands[$command]["class"];
|
||||
} else {
|
||||
return false;
|
||||
|
@ -781,7 +781,7 @@ class PluginHost {
|
|||
|
||||
// Plugin feed functions are *EXPERIMENTAL*!
|
||||
|
||||
// cat_id: only -1 is supported (Special)
|
||||
// cat_id: only -1 (Feeds::CATEGORY_SPECIAL) is supported (Special)
|
||||
function add_feed(int $cat_id, string $title, string $icon, Plugin $sender): int {
|
||||
|
||||
if (empty($this->feeds[$cat_id]))
|
||||
|
|
|
@ -135,18 +135,19 @@ class Pref_Feeds extends Handler_Protected {
|
|||
if (clean($_REQUEST['mode'] ?? 0) == 2) {
|
||||
|
||||
if ($enable_cats) {
|
||||
$cat = $this->feedlist_init_cat(-1);
|
||||
$cat = $this->feedlist_init_cat(Feeds::CATEGORY_SPECIAL);
|
||||
} else {
|
||||
$cat['items'] = array();
|
||||
}
|
||||
|
||||
foreach (array(-4, -3, -1, -2, 0, -6) as $i) {
|
||||
array_push($cat['items'], $this->feedlist_init_feed($i));
|
||||
foreach ([Feeds::FEED_ALL, Feeds::FEED_FRESH, Feeds::FEED_STARRED, Feeds::FEED_PUBLISHED,
|
||||
Feeds::FEED_ARCHIVED, Feeds::FEED_RECENTLY_READ] as $feed_id) {
|
||||
array_push($cat['items'], $this->feedlist_init_feed($feed_id));
|
||||
}
|
||||
|
||||
/* Plugin feeds for -1 */
|
||||
/* Plugin feeds for -1 (Feeds::CATEGORY_SPECIAL) */
|
||||
|
||||
$feeds = PluginHost::getInstance()->get_feeds(-1);
|
||||
$feeds = PluginHost::getInstance()->get_feeds(Feeds::CATEGORY_SPECIAL);
|
||||
|
||||
if ($feeds) {
|
||||
foreach ($feeds as $feed) {
|
||||
|
@ -180,7 +181,7 @@ class Pref_Feeds extends Handler_Protected {
|
|||
$sth->execute([$_SESSION['uid']]);
|
||||
|
||||
if (get_pref(Prefs::ENABLE_FEED_CATS)) {
|
||||
$cat = $this->feedlist_init_cat(-2);
|
||||
$cat = $this->feedlist_init_cat(Feeds::CATEGORY_LABELS);
|
||||
} else {
|
||||
$cat['items'] = [];
|
||||
}
|
||||
|
@ -241,7 +242,12 @@ class Pref_Feeds extends Handler_Protected {
|
|||
//$root['param'] += count($cat['items']);
|
||||
}
|
||||
|
||||
/* Uncategorized is a special case */
|
||||
/**
|
||||
* Uncategorized is a special case.
|
||||
*
|
||||
* Define a minimal array shape to help PHPStan with the type of $cat['items']
|
||||
* @var array{items: array<int, array<string, mixed>>} $cat
|
||||
*/
|
||||
$cat = [
|
||||
'id' => 'CAT:0',
|
||||
'bare_id' => 0,
|
||||
|
@ -1027,7 +1033,7 @@ class Pref_Feeds extends Handler_Protected {
|
|||
<?= format_notice('Published articles can be subscribed by anyone who knows the following URL:') ?></h3>
|
||||
|
||||
<button dojoType='dijit.form.Button' class='alt-primary'
|
||||
onclick="CommonDialogs.generatedFeed(-2, false)">
|
||||
onclick="CommonDialogs.generatedFeed(<?= Feeds::FEED_PUBLISHED ?>, false)">
|
||||
<?= \Controls\icon('share') ?>
|
||||
<?= __('Display URL') ?>
|
||||
</button>
|
||||
|
|
|
@ -325,14 +325,6 @@ class Prefs {
|
|||
return self::get_instance()->_set($pref_name, $value, $owner_uid, $profile_id);
|
||||
}
|
||||
|
||||
private function _delete(string $pref_name, int $owner_uid, ?int $profile_id): bool {
|
||||
$sth = $this->pdo->prepare("DELETE FROM ttrss_user_prefs2
|
||||
WHERE pref_name = :name AND owner_uid = :uid AND
|
||||
(profile = :profile OR (:profile IS NULL AND profile IS NULL))");
|
||||
|
||||
return $sth->execute(["uid" => $owner_uid, "profile" => $profile_id, "name" => $pref_name ]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param bool|int|string $value
|
||||
*/
|
||||
|
@ -350,10 +342,6 @@ class Prefs {
|
|||
|
||||
$value = Config::cast_to($value, $type_hint);
|
||||
|
||||
// is this a good idea or not? probably not (user-set value remains user-set even if its at default)
|
||||
//if ($value == $def_val)
|
||||
// return $this->_delete($pref_name, $owner_uid, $profile_id);
|
||||
|
||||
if ($value == $this->_get($pref_name, $owner_uid, $profile_id))
|
||||
return false;
|
||||
|
||||
|
|
|
@ -316,6 +316,7 @@ class RSSUtils {
|
|||
|
||||
$feed_data = trim($feed_data);
|
||||
|
||||
if ($feed_data) {
|
||||
$rss = new FeedParser($feed_data);
|
||||
$rss->init();
|
||||
|
||||
|
@ -324,6 +325,11 @@ class RSSUtils {
|
|||
'title' => mb_substr(clean($rss->get_title()), 0, 199),
|
||||
'site_url' => mb_substr(UrlHelper::rewrite_relative($feed->feed_url, clean($rss->get_link())), 0, 245),
|
||||
];
|
||||
} else {
|
||||
Debug::log(sprintf("unable to parse feed for basic info: %s", $rss->error()), Debug::LOG_VERBOSE);
|
||||
}
|
||||
} else {
|
||||
Debug::log(sprintf("unable to fetch feed for basic info: %s [%s]", UrlHelper::$fetch_last_error, UrlHelper::$fetch_last_error_code), Debug::LOG_VERBOSE);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -597,10 +603,13 @@ class RSSUtils {
|
|||
Debug::log("site_url: {$feed_obj->site_url}", Debug::LOG_VERBOSE);
|
||||
Debug::log("feed_title: {$rss->get_title()}", Debug::LOG_VERBOSE);
|
||||
|
||||
Debug::log("favicon: needs check: {$feed_obj->favicon_needs_check} is custom: {$feed_obj->favicon_is_custom} avg color: {$feed_obj->favicon_avg_color}",
|
||||
Debug::log('favicon: needs check: ' . ($feed_obj->favicon_needs_check ? 'true' : 'false')
|
||||
. ', is custom: ' . ($feed_obj->favicon_is_custom ? 'true' : 'false')
|
||||
. ", avg color: {$feed_obj->favicon_avg_color}",
|
||||
Debug::LOG_VERBOSE);
|
||||
|
||||
if ($feed_obj->favicon_needs_check || $force_refetch) {
|
||||
if ($feed_obj->favicon_needs_check || $force_refetch
|
||||
|| ($feed_obj->favicon_is_custom && !$feed_obj->favicon_avg_color)) {
|
||||
|
||||
// restrict update attempts to once per 12h
|
||||
$feed_obj->favicon_last_checked = Db::NOW();
|
||||
|
@ -631,13 +640,16 @@ class RSSUtils {
|
|||
$feed_obj->favicon_avg_color = 'fail';
|
||||
$feed_obj->save();
|
||||
|
||||
$feed_obj->favicon_avg_color = \Colors\calculate_avg_color($favicon_cache->get_full_path($feed));
|
||||
$calculated_avg_color = \Colors\calculate_avg_color($favicon_cache->get_full_path($feed));
|
||||
if ($calculated_avg_color) {
|
||||
$feed_obj->favicon_avg_color = $calculated_avg_color;
|
||||
$feed_obj->save();
|
||||
}
|
||||
|
||||
Debug::log("favicon: avg color: {$feed_obj->favicon_avg_color}", Debug::LOG_VERBOSE);
|
||||
Debug::log("favicon: calculated avg color: {$calculated_avg_color}, setting avg color: {$feed_obj->favicon_avg_color}", Debug::LOG_VERBOSE);
|
||||
|
||||
} else if ($feed_obj->favicon_avg_color == 'fail') {
|
||||
Debug::log("floicon failed on $feed, not trying to recalculate avg color", Debug::LOG_VERBOSE);
|
||||
Debug::log("floicon failed on $feed or a suitable avg color couldn't be determined, not trying to recalculate avg color", Debug::LOG_VERBOSE);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -16,7 +16,7 @@
|
|||
"j4mie/idiorm": "dev-master"
|
||||
},
|
||||
"require-dev": {
|
||||
"phpstan/phpstan": "1.8.2",
|
||||
"phpstan/phpstan": "1.10.3",
|
||||
"phpunit/phpunit": "9.5.16"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
|
||||
"This file is @generated automatically"
|
||||
],
|
||||
"content-hash": "6beda4561e770d2f0c7c532c5e3693d3",
|
||||
"content-hash": "d2be3e2749aff1bebf6257ecbfd6dcb3",
|
||||
"packages": [
|
||||
{
|
||||
"name": "beberlei/assert",
|
||||
|
@ -1130,16 +1130,16 @@
|
|||
},
|
||||
{
|
||||
"name": "phpstan/phpstan",
|
||||
"version": "1.8.2",
|
||||
"version": "1.10.3",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/phpstan/phpstan.git",
|
||||
"reference": "c53312ecc575caf07b0e90dee43883fdf90ca67c"
|
||||
"reference": "5419375b5891add97dc74be71e6c1c34baaddf64"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/phpstan/phpstan/zipball/c53312ecc575caf07b0e90dee43883fdf90ca67c",
|
||||
"reference": "c53312ecc575caf07b0e90dee43883fdf90ca67c",
|
||||
"url": "https://api.github.com/repos/phpstan/phpstan/zipball/5419375b5891add97dc74be71e6c1c34baaddf64",
|
||||
"reference": "5419375b5891add97dc74be71e6c1c34baaddf64",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
|
@ -1163,9 +1163,13 @@
|
|||
"MIT"
|
||||
],
|
||||
"description": "PHPStan - PHP Static Analysis Tool",
|
||||
"keywords": [
|
||||
"dev",
|
||||
"static analysis"
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/phpstan/phpstan/issues",
|
||||
"source": "https://github.com/phpstan/phpstan/tree/1.8.2"
|
||||
"source": "https://github.com/phpstan/phpstan/tree/1.10.3"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
|
@ -1176,16 +1180,12 @@
|
|||
"url": "https://github.com/phpstan",
|
||||
"type": "github"
|
||||
},
|
||||
{
|
||||
"url": "https://www.patreon.com/phpstan",
|
||||
"type": "patreon"
|
||||
},
|
||||
{
|
||||
"url": "https://tidelift.com/funding/github/packagist/phpstan/phpstan",
|
||||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2022-07-20T09:57:31+00:00"
|
||||
"time": "2023-02-25T14:47:13+00:00"
|
||||
},
|
||||
{
|
||||
"name": "phpunit/php-code-coverage",
|
||||
|
@ -2690,5 +2690,5 @@
|
|||
"prefer-lowest": false,
|
||||
"platform": [],
|
||||
"platform-dev": [],
|
||||
"plugin-api-version": "2.0.0"
|
||||
"plugin-api-version": "2.3.0"
|
||||
}
|
||||
|
|
|
@ -355,8 +355,9 @@ function colorPalette(string $imageFile, int $numColors, int $granularity = 5):
|
|||
} else {
|
||||
$img = @$ico->images[count($ico->images)-1]->getImageResource();
|
||||
}
|
||||
}
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
} else if ($size[0] > 0 && $size[1] > 0) {
|
||||
$img = @imagecreatefromstring(file_get_contents($imageFile));
|
||||
}
|
||||
|
|
|
@ -366,7 +366,6 @@
|
|||
|
||||
function file_is_locked(string $filename): bool {
|
||||
if (file_exists(Config::get(Config::LOCK_DIRECTORY) . "/$filename")) {
|
||||
if (function_exists('flock')) {
|
||||
$fp = @fopen(Config::get(Config::LOCK_DIRECTORY) . "/$filename", "r");
|
||||
if ($fp) {
|
||||
if (flock($fp, LOCK_EX | LOCK_NB)) {
|
||||
|
@ -379,8 +378,6 @@
|
|||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true; // consider the file always locked and skip the test
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
|
|
10
js/App.js
10
js/App.js
|
@ -1198,19 +1198,19 @@ const App = {
|
|||
}
|
||||
};
|
||||
this.hotkey_actions["goto_read"] = () => {
|
||||
Feeds.open({feed: -6});
|
||||
Feeds.open({feed: Feeds.FEED_RECENTLY_READ});
|
||||
};
|
||||
this.hotkey_actions["goto_all"] = () => {
|
||||
Feeds.open({feed: -4});
|
||||
Feeds.open({feed: Feeds.FEED_ALL});
|
||||
};
|
||||
this.hotkey_actions["goto_fresh"] = () => {
|
||||
Feeds.open({feed: -3});
|
||||
Feeds.open({feed: Feeds.FEED_FRESH});
|
||||
};
|
||||
this.hotkey_actions["goto_marked"] = () => {
|
||||
Feeds.open({feed: -1});
|
||||
Feeds.open({feed: Feeds.FEED_STARRED});
|
||||
};
|
||||
this.hotkey_actions["goto_published"] = () => {
|
||||
Feeds.open({feed: -2});
|
||||
Feeds.open({feed: Feeds.FEED_PUBLISHED});
|
||||
};
|
||||
this.hotkey_actions["goto_prefs"] = () => {
|
||||
App.openPreferences();
|
||||
|
|
|
@ -146,10 +146,8 @@ const Article = {
|
|||
</div>`;
|
||||
},
|
||||
renderTags: function (id, tags) {
|
||||
const tags_short = tags.length > 5 ? tags.slice(0, 5) : tags;
|
||||
|
||||
return `<span class="tags" title="${tags.join(", ")}" data-tags-for="${id}">
|
||||
${tags_short.length > 0 ? tags_short.map((tag) => `
|
||||
${tags.length > 0 ? tags.map((tag) => `
|
||||
<a href="#" onclick="Feeds.open({feed: '${tag.trim()}'})" class="tag">${tag}</a>`
|
||||
).join(", ") : `${__("no tags")}`}</span>`;
|
||||
},
|
||||
|
|
|
@ -225,8 +225,8 @@ define(["dojo/_base/declare", "dojo/dom-construct", "dojo/_base/array", "dojo/co
|
|||
if (item.auxcounter > 0) rc += " Has_Aux";
|
||||
if (item.markedcounter > 0) rc += " Has_Marked";
|
||||
if (item.updates_disabled > 0) rc += " UpdatesDisabled";
|
||||
if (item.bare_id >= App.LABEL_BASE_INDEX && item.bare_id < 0 && !is_cat || item.bare_id == 0 && !is_cat) rc += " Special";
|
||||
if (item.bare_id == -1 && is_cat) rc += " AlwaysVisible";
|
||||
if (item.bare_id >= App.LABEL_BASE_INDEX && item.bare_id < 0 && !is_cat || item.bare_id == Feeds.FEED_ARCHIVED && !is_cat) rc += " Special";
|
||||
if (item.bare_id == Feeds.CATEGORY_SPECIAL && is_cat) rc += " AlwaysVisible";
|
||||
if (item.bare_id < App.LABEL_BASE_INDEX) rc += " Label";
|
||||
|
||||
return rc;
|
||||
|
|
13
js/Feeds.js
13
js/Feeds.js
|
@ -3,6 +3,19 @@
|
|||
/* global __, App, Headlines, xhr, dojo, dijit, fox, PluginHost, Notify, fox */
|
||||
|
||||
const Feeds = {
|
||||
FEED_ARCHIVED: 0,
|
||||
FEED_STARRED: -1,
|
||||
FEED_PUBLISHED: -2,
|
||||
FEED_FRESH: -3,
|
||||
FEED_ALL: -4,
|
||||
FEED_DASHBOARD: -5,
|
||||
FEED_RECENTLY_READ: -6,
|
||||
FEED_ERROR: -7,
|
||||
CATEGORY_UNCATEGORIZED: 0,
|
||||
CATEGORY_SPECIAL: -1,
|
||||
CATEGORY_LABELS: -2,
|
||||
CATEGORY_ALL_EXCEPT_VIRTUAL: -3,
|
||||
CATEGORY_ALL: -4,
|
||||
_default_feed_id: -3,
|
||||
counters_last_request: 0,
|
||||
_active_feed_id: undefined,
|
||||
|
|
|
@ -307,7 +307,7 @@ const Headlines = {
|
|||
offset = unread_in_buffer;
|
||||
break;
|
||||
case "adaptive":
|
||||
if (!(Feeds.getActive() == -1 && !Feeds.activeIsCat()))
|
||||
if (!(Feeds.getActive() == Feeds.FEED_STARRED && !Feeds.activeIsCat()))
|
||||
offset = num_unread > 0 ? unread_in_buffer : num_all;
|
||||
break;
|
||||
}
|
||||
|
@ -746,7 +746,7 @@ const Headlines = {
|
|||
feed_id = reply['headlines']['id'];
|
||||
Feeds.last_search_query = reply['headlines']['search_query'];
|
||||
|
||||
if (feed_id != -7 && (feed_id != Feeds.getActive() || is_cat != Feeds.activeIsCat()))
|
||||
if (feed_id != Feeds.FEED_ERROR && (feed_id != Feeds.getActive() || is_cat != Feeds.activeIsCat()))
|
||||
return;
|
||||
|
||||
const headlines_count = reply['headlines-info']['count'];
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -36,7 +36,7 @@ class Auth_Internal extends Auth_Base {
|
|||
return false;
|
||||
|
||||
} else {
|
||||
$return = urlencode($_REQUEST["return"]);
|
||||
$return = urlencode(with_trailing_slash($_REQUEST["return"]));
|
||||
?>
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
|
@ -76,11 +76,12 @@ class Auth_Internal extends Auth_Base {
|
|||
},
|
||||
};
|
||||
</script>
|
||||
<?= Config::get_override_links() ?>
|
||||
</head>
|
||||
<body class="flat ttrss_utility otp css_loading">
|
||||
<h1><?= __("Authentication") ?></h1>
|
||||
<div class="content">
|
||||
<form dojoType="dijit.form.Form" action="public.php?return=<?= urlencode(with_trailing_slash($return)) ?>" method="post" class="otpform">
|
||||
<form dojoType="dijit.form.Form" action="public.php?return=<?= $return ?>" method="post" class="otpform">
|
||||
|
||||
<?php foreach (["login", "password", "bw_limit", "safe_mode", "remember_me", "profile"] as $key) {
|
||||
print \Controls\hidden_tag($key, $_POST[$key] ?? "");
|
||||
|
|
|
@ -56,6 +56,7 @@ class Bookmarklets extends Plugin {
|
|||
display : none;
|
||||
}
|
||||
</style>
|
||||
<?= Config::get_override_links() ?>
|
||||
</head>
|
||||
<body class='flat ttrss_utility css_loading'>
|
||||
<script type="text/javascript">
|
||||
|
@ -202,6 +203,7 @@ class Bookmarklets extends Plugin {
|
|||
display : none;
|
||||
}
|
||||
</style>
|
||||
<?= Config::get_override_links() ?>
|
||||
</head>
|
||||
<body class='flat ttrss_utility share_popup css_loading'>
|
||||
<script type="text/javascript">
|
||||
|
|
|
@ -195,6 +195,7 @@ class Share extends Plugin {
|
|||
)
|
||||
), 500, "...")) ?>">
|
||||
<meta property='og:image' content="<?= htmlspecialchars($og_image) ?>">
|
||||
<?= Config::get_override_links() ?>
|
||||
</head>
|
||||
|
||||
<body class='flat ttrss_utility ttrss_zoom css_loading'>
|
||||
|
|
|
@ -73,6 +73,12 @@ body.ttrss_main .post .header .title {
|
|||
font-family: system-ui, "Helvetica Neue", Helvetica, Arial, sans-serif;
|
||||
word-break: break-all;
|
||||
}
|
||||
body.ttrss_main .post .header .tags {
|
||||
max-width: 25%;
|
||||
overflow: hidden;
|
||||
white-space: nowrap;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
body.ttrss_main .post div.content {
|
||||
padding: 10px;
|
||||
font-size: 16px;
|
||||
|
@ -1311,6 +1317,7 @@ body.ttrss_utility hr {
|
|||
}
|
||||
.cdm .footer .left {
|
||||
flex-grow: 2;
|
||||
min-width: 0;
|
||||
}
|
||||
.cdm .footer .left > * {
|
||||
margin-right: 4px;
|
||||
|
@ -1318,6 +1325,12 @@ body.ttrss_utility hr {
|
|||
.cdm .footer .right > * {
|
||||
margin-left: 4px;
|
||||
}
|
||||
.cdm .footer .tags {
|
||||
max-width: 50%;
|
||||
overflow: hidden;
|
||||
white-space: nowrap;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
.cdm .content-inner {
|
||||
margin: 10px;
|
||||
line-height: 1.5;
|
||||
|
|
|
@ -73,6 +73,12 @@ body.ttrss_main .post .header .title {
|
|||
font-family: system-ui, "Helvetica Neue", Helvetica, Arial, sans-serif;
|
||||
word-break: break-all;
|
||||
}
|
||||
body.ttrss_main .post .header .tags {
|
||||
max-width: 25%;
|
||||
overflow: hidden;
|
||||
white-space: nowrap;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
body.ttrss_main .post div.content {
|
||||
padding: 10px;
|
||||
font-size: 16px;
|
||||
|
@ -1311,6 +1317,7 @@ body.ttrss_utility hr {
|
|||
}
|
||||
.cdm .footer .left {
|
||||
flex-grow: 2;
|
||||
min-width: 0;
|
||||
}
|
||||
.cdm .footer .left > * {
|
||||
margin-right: 4px;
|
||||
|
@ -1318,6 +1325,12 @@ body.ttrss_utility hr {
|
|||
.cdm .footer .right > * {
|
||||
margin-left: 4px;
|
||||
}
|
||||
.cdm .footer .tags {
|
||||
max-width: 50%;
|
||||
overflow: hidden;
|
||||
white-space: nowrap;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
.cdm .content-inner {
|
||||
margin: 10px;
|
||||
line-height: 1.5;
|
||||
|
|
|
@ -73,6 +73,12 @@ body.ttrss_main .post .header .title {
|
|||
font-family: system-ui, "Helvetica Neue", Helvetica, Arial, sans-serif;
|
||||
word-break: break-all;
|
||||
}
|
||||
body.ttrss_main .post .header .tags {
|
||||
max-width: 25%;
|
||||
overflow: hidden;
|
||||
white-space: nowrap;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
body.ttrss_main .post div.content {
|
||||
padding: 10px;
|
||||
font-size: 16px;
|
||||
|
@ -1311,6 +1317,7 @@ body.ttrss_utility hr {
|
|||
}
|
||||
.cdm .footer .left {
|
||||
flex-grow: 2;
|
||||
min-width: 0;
|
||||
}
|
||||
.cdm .footer .left > * {
|
||||
margin-right: 4px;
|
||||
|
@ -1318,6 +1325,12 @@ body.ttrss_utility hr {
|
|||
.cdm .footer .right > * {
|
||||
margin-left: 4px;
|
||||
}
|
||||
.cdm .footer .tags {
|
||||
max-width: 50%;
|
||||
overflow: hidden;
|
||||
white-space: nowrap;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
.cdm .content-inner {
|
||||
margin: 10px;
|
||||
line-height: 1.5;
|
||||
|
|
|
@ -73,6 +73,12 @@ body.ttrss_main .post .header .title {
|
|||
font-family: system-ui, "Helvetica Neue", Helvetica, Arial, sans-serif;
|
||||
word-break: break-all;
|
||||
}
|
||||
body.ttrss_main .post .header .tags {
|
||||
max-width: 25%;
|
||||
overflow: hidden;
|
||||
white-space: nowrap;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
body.ttrss_main .post div.content {
|
||||
padding: 10px;
|
||||
font-size: 16px;
|
||||
|
@ -1311,6 +1317,7 @@ body.ttrss_utility hr {
|
|||
}
|
||||
.cdm .footer .left {
|
||||
flex-grow: 2;
|
||||
min-width: 0;
|
||||
}
|
||||
.cdm .footer .left > * {
|
||||
margin-right: 4px;
|
||||
|
@ -1318,6 +1325,12 @@ body.ttrss_utility hr {
|
|||
.cdm .footer .right > * {
|
||||
margin-left: 4px;
|
||||
}
|
||||
.cdm .footer .tags {
|
||||
max-width: 50%;
|
||||
overflow: hidden;
|
||||
white-space: nowrap;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
.cdm .content-inner {
|
||||
margin: 10px;
|
||||
line-height: 1.5;
|
||||
|
|
|
@ -100,6 +100,7 @@
|
|||
|
||||
.left {
|
||||
flex-grow : 2;
|
||||
min-width : 0;
|
||||
|
||||
> * {
|
||||
margin-right : 4px;
|
||||
|
@ -111,6 +112,13 @@
|
|||
margin-left : 4px;
|
||||
}
|
||||
}
|
||||
|
||||
.tags {
|
||||
max-width : 50%;
|
||||
overflow : hidden;
|
||||
white-space : nowrap;
|
||||
text-overflow : ellipsis;
|
||||
}
|
||||
}
|
||||
|
||||
.content-inner {
|
||||
|
|
|
@ -56,6 +56,13 @@ body.ttrss_main {
|
|||
font-family : @fonts-ui;
|
||||
word-break : break-all;
|
||||
}
|
||||
|
||||
.tags {
|
||||
max-width : 25%;
|
||||
overflow : hidden;
|
||||
white-space : nowrap;
|
||||
text-overflow : ellipsis;
|
||||
}
|
||||
}
|
||||
|
||||
div.content {
|
||||
|
|
|
@ -74,6 +74,12 @@ body.ttrss_main .post .header .title {
|
|||
font-family: system-ui, "Helvetica Neue", Helvetica, Arial, sans-serif;
|
||||
word-break: break-all;
|
||||
}
|
||||
body.ttrss_main .post .header .tags {
|
||||
max-width: 25%;
|
||||
overflow: hidden;
|
||||
white-space: nowrap;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
body.ttrss_main .post div.content {
|
||||
padding: 10px;
|
||||
font-size: 16px;
|
||||
|
@ -1312,6 +1318,7 @@ body.ttrss_utility hr {
|
|||
}
|
||||
.cdm .footer .left {
|
||||
flex-grow: 2;
|
||||
min-width: 0;
|
||||
}
|
||||
.cdm .footer .left > * {
|
||||
margin-right: 4px;
|
||||
|
@ -1319,6 +1326,12 @@ body.ttrss_utility hr {
|
|||
.cdm .footer .right > * {
|
||||
margin-left: 4px;
|
||||
}
|
||||
.cdm .footer .tags {
|
||||
max-width: 50%;
|
||||
overflow: hidden;
|
||||
white-space: nowrap;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
.cdm .content-inner {
|
||||
margin: 10px;
|
||||
line-height: 1.5;
|
||||
|
|
|
@ -74,6 +74,12 @@ body.ttrss_main .post .header .title {
|
|||
font-family: system-ui, "Helvetica Neue", Helvetica, Arial, sans-serif;
|
||||
word-break: break-all;
|
||||
}
|
||||
body.ttrss_main .post .header .tags {
|
||||
max-width: 25%;
|
||||
overflow: hidden;
|
||||
white-space: nowrap;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
body.ttrss_main .post div.content {
|
||||
padding: 10px;
|
||||
font-size: 16px;
|
||||
|
@ -1312,6 +1318,7 @@ body.ttrss_utility hr {
|
|||
}
|
||||
.cdm .footer .left {
|
||||
flex-grow: 2;
|
||||
min-width: 0;
|
||||
}
|
||||
.cdm .footer .left > * {
|
||||
margin-right: 4px;
|
||||
|
@ -1319,6 +1326,12 @@ body.ttrss_utility hr {
|
|||
.cdm .footer .right > * {
|
||||
margin-left: 4px;
|
||||
}
|
||||
.cdm .footer .tags {
|
||||
max-width: 50%;
|
||||
overflow: hidden;
|
||||
white-space: nowrap;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
.cdm .content-inner {
|
||||
margin: 10px;
|
||||
line-height: 1.5;
|
||||
|
|
|
@ -2,6 +2,24 @@
|
|||
|
||||
// autoload.php @generated by Composer
|
||||
|
||||
if (PHP_VERSION_ID < 50600) {
|
||||
if (!headers_sent()) {
|
||||
header('HTTP/1.1 500 Internal Server Error');
|
||||
}
|
||||
$err = 'Composer 2.3.0 dropped support for autoloading on PHP <5.6 and you are running '.PHP_VERSION.', please upgrade PHP or use Composer 2.2 LTS via "composer self-update --2.2". Aborting.'.PHP_EOL;
|
||||
if (!ini_get('display_errors')) {
|
||||
if (PHP_SAPI === 'cli' || PHP_SAPI === 'phpdbg') {
|
||||
fwrite(STDERR, $err);
|
||||
} elseif (!headers_sent()) {
|
||||
echo $err;
|
||||
}
|
||||
}
|
||||
trigger_error(
|
||||
$err,
|
||||
E_USER_ERROR
|
||||
);
|
||||
}
|
||||
|
||||
require_once __DIR__ . '/composer/autoload_real.php';
|
||||
|
||||
return ComposerAutoloaderInit19fc2ff1c0f9a92279c7979386bb2056::getLoader();
|
||||
|
|
|
@ -1 +0,0 @@
|
|||
../nikic/php-parser/bin/php-parse
|
|
@ -0,0 +1,120 @@
|
|||
#!/usr/bin/env php
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Proxy PHP file generated by Composer
|
||||
*
|
||||
* This file includes the referenced bin path (../nikic/php-parser/bin/php-parse)
|
||||
* using a stream wrapper to prevent the shebang from being output on PHP<8
|
||||
*
|
||||
* @generated
|
||||
*/
|
||||
|
||||
namespace Composer;
|
||||
|
||||
$GLOBALS['_composer_bin_dir'] = __DIR__;
|
||||
$GLOBALS['_composer_autoload_path'] = __DIR__ . '/..'.'/autoload.php';
|
||||
|
||||
if (PHP_VERSION_ID < 80000) {
|
||||
if (!class_exists('Composer\BinProxyWrapper')) {
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
final class BinProxyWrapper
|
||||
{
|
||||
private $handle;
|
||||
private $position;
|
||||
private $realpath;
|
||||
|
||||
public function stream_open($path, $mode, $options, &$opened_path)
|
||||
{
|
||||
// get rid of phpvfscomposer:// prefix for __FILE__ & __DIR__ resolution
|
||||
$opened_path = substr($path, 17);
|
||||
$this->realpath = realpath($opened_path) ?: $opened_path;
|
||||
$opened_path = $this->realpath;
|
||||
$this->handle = fopen($this->realpath, $mode);
|
||||
$this->position = 0;
|
||||
|
||||
return (bool) $this->handle;
|
||||
}
|
||||
|
||||
public function stream_read($count)
|
||||
{
|
||||
$data = fread($this->handle, $count);
|
||||
|
||||
if ($this->position === 0) {
|
||||
$data = preg_replace('{^#!.*\r?\n}', '', $data);
|
||||
}
|
||||
|
||||
$this->position += strlen($data);
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
public function stream_cast($castAs)
|
||||
{
|
||||
return $this->handle;
|
||||
}
|
||||
|
||||
public function stream_close()
|
||||
{
|
||||
fclose($this->handle);
|
||||
}
|
||||
|
||||
public function stream_lock($operation)
|
||||
{
|
||||
return $operation ? flock($this->handle, $operation) : true;
|
||||
}
|
||||
|
||||
public function stream_seek($offset, $whence)
|
||||
{
|
||||
if (0 === fseek($this->handle, $offset, $whence)) {
|
||||
$this->position = ftell($this->handle);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public function stream_tell()
|
||||
{
|
||||
return $this->position;
|
||||
}
|
||||
|
||||
public function stream_eof()
|
||||
{
|
||||
return feof($this->handle);
|
||||
}
|
||||
|
||||
public function stream_stat()
|
||||
{
|
||||
return array();
|
||||
}
|
||||
|
||||
public function stream_set_option($option, $arg1, $arg2)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
public function url_stat($path, $flags)
|
||||
{
|
||||
$path = substr($path, 17);
|
||||
if (file_exists($path)) {
|
||||
return stat($path);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (
|
||||
(function_exists('stream_get_wrappers') && in_array('phpvfscomposer', stream_get_wrappers(), true))
|
||||
|| (function_exists('stream_wrapper_register') && stream_wrapper_register('phpvfscomposer', 'Composer\BinProxyWrapper'))
|
||||
) {
|
||||
include("phpvfscomposer://" . __DIR__ . '/..'.'/nikic/php-parser/bin/php-parse');
|
||||
exit(0);
|
||||
}
|
||||
}
|
||||
|
||||
include __DIR__ . '/..'.'/nikic/php-parser/bin/php-parse';
|
|
@ -1 +0,0 @@
|
|||
../phpstan/phpstan/phpstan
|
|
@ -0,0 +1,120 @@
|
|||
#!/usr/bin/env php
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Proxy PHP file generated by Composer
|
||||
*
|
||||
* This file includes the referenced bin path (../phpstan/phpstan/phpstan)
|
||||
* using a stream wrapper to prevent the shebang from being output on PHP<8
|
||||
*
|
||||
* @generated
|
||||
*/
|
||||
|
||||
namespace Composer;
|
||||
|
||||
$GLOBALS['_composer_bin_dir'] = __DIR__;
|
||||
$GLOBALS['_composer_autoload_path'] = __DIR__ . '/..'.'/autoload.php';
|
||||
|
||||
if (PHP_VERSION_ID < 80000) {
|
||||
if (!class_exists('Composer\BinProxyWrapper')) {
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
final class BinProxyWrapper
|
||||
{
|
||||
private $handle;
|
||||
private $position;
|
||||
private $realpath;
|
||||
|
||||
public function stream_open($path, $mode, $options, &$opened_path)
|
||||
{
|
||||
// get rid of phpvfscomposer:// prefix for __FILE__ & __DIR__ resolution
|
||||
$opened_path = substr($path, 17);
|
||||
$this->realpath = realpath($opened_path) ?: $opened_path;
|
||||
$opened_path = $this->realpath;
|
||||
$this->handle = fopen($this->realpath, $mode);
|
||||
$this->position = 0;
|
||||
|
||||
return (bool) $this->handle;
|
||||
}
|
||||
|
||||
public function stream_read($count)
|
||||
{
|
||||
$data = fread($this->handle, $count);
|
||||
|
||||
if ($this->position === 0) {
|
||||
$data = preg_replace('{^#!.*\r?\n}', '', $data);
|
||||
}
|
||||
|
||||
$this->position += strlen($data);
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
public function stream_cast($castAs)
|
||||
{
|
||||
return $this->handle;
|
||||
}
|
||||
|
||||
public function stream_close()
|
||||
{
|
||||
fclose($this->handle);
|
||||
}
|
||||
|
||||
public function stream_lock($operation)
|
||||
{
|
||||
return $operation ? flock($this->handle, $operation) : true;
|
||||
}
|
||||
|
||||
public function stream_seek($offset, $whence)
|
||||
{
|
||||
if (0 === fseek($this->handle, $offset, $whence)) {
|
||||
$this->position = ftell($this->handle);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public function stream_tell()
|
||||
{
|
||||
return $this->position;
|
||||
}
|
||||
|
||||
public function stream_eof()
|
||||
{
|
||||
return feof($this->handle);
|
||||
}
|
||||
|
||||
public function stream_stat()
|
||||
{
|
||||
return array();
|
||||
}
|
||||
|
||||
public function stream_set_option($option, $arg1, $arg2)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
public function url_stat($path, $flags)
|
||||
{
|
||||
$path = substr($path, 17);
|
||||
if (file_exists($path)) {
|
||||
return stat($path);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (
|
||||
(function_exists('stream_get_wrappers') && in_array('phpvfscomposer', stream_get_wrappers(), true))
|
||||
|| (function_exists('stream_wrapper_register') && stream_wrapper_register('phpvfscomposer', 'Composer\BinProxyWrapper'))
|
||||
) {
|
||||
include("phpvfscomposer://" . __DIR__ . '/..'.'/phpstan/phpstan/phpstan');
|
||||
exit(0);
|
||||
}
|
||||
}
|
||||
|
||||
include __DIR__ . '/..'.'/phpstan/phpstan/phpstan';
|
|
@ -1 +0,0 @@
|
|||
../phpstan/phpstan/phpstan.phar
|
|
@ -0,0 +1,120 @@
|
|||
#!/usr/bin/env php
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Proxy PHP file generated by Composer
|
||||
*
|
||||
* This file includes the referenced bin path (../phpstan/phpstan/phpstan.phar)
|
||||
* using a stream wrapper to prevent the shebang from being output on PHP<8
|
||||
*
|
||||
* @generated
|
||||
*/
|
||||
|
||||
namespace Composer;
|
||||
|
||||
$GLOBALS['_composer_bin_dir'] = __DIR__;
|
||||
$GLOBALS['_composer_autoload_path'] = __DIR__ . '/..'.'/autoload.php';
|
||||
|
||||
if (PHP_VERSION_ID < 80000) {
|
||||
if (!class_exists('Composer\BinProxyWrapper')) {
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
final class BinProxyWrapper
|
||||
{
|
||||
private $handle;
|
||||
private $position;
|
||||
private $realpath;
|
||||
|
||||
public function stream_open($path, $mode, $options, &$opened_path)
|
||||
{
|
||||
// get rid of phpvfscomposer:// prefix for __FILE__ & __DIR__ resolution
|
||||
$opened_path = substr($path, 17);
|
||||
$this->realpath = realpath($opened_path) ?: $opened_path;
|
||||
$opened_path = $this->realpath;
|
||||
$this->handle = fopen($this->realpath, $mode);
|
||||
$this->position = 0;
|
||||
|
||||
return (bool) $this->handle;
|
||||
}
|
||||
|
||||
public function stream_read($count)
|
||||
{
|
||||
$data = fread($this->handle, $count);
|
||||
|
||||
if ($this->position === 0) {
|
||||
$data = preg_replace('{^#!.*\r?\n}', '', $data);
|
||||
}
|
||||
|
||||
$this->position += strlen($data);
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
public function stream_cast($castAs)
|
||||
{
|
||||
return $this->handle;
|
||||
}
|
||||
|
||||
public function stream_close()
|
||||
{
|
||||
fclose($this->handle);
|
||||
}
|
||||
|
||||
public function stream_lock($operation)
|
||||
{
|
||||
return $operation ? flock($this->handle, $operation) : true;
|
||||
}
|
||||
|
||||
public function stream_seek($offset, $whence)
|
||||
{
|
||||
if (0 === fseek($this->handle, $offset, $whence)) {
|
||||
$this->position = ftell($this->handle);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public function stream_tell()
|
||||
{
|
||||
return $this->position;
|
||||
}
|
||||
|
||||
public function stream_eof()
|
||||
{
|
||||
return feof($this->handle);
|
||||
}
|
||||
|
||||
public function stream_stat()
|
||||
{
|
||||
return array();
|
||||
}
|
||||
|
||||
public function stream_set_option($option, $arg1, $arg2)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
public function url_stat($path, $flags)
|
||||
{
|
||||
$path = substr($path, 17);
|
||||
if (file_exists($path)) {
|
||||
return stat($path);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (
|
||||
(function_exists('stream_get_wrappers') && in_array('phpvfscomposer', stream_get_wrappers(), true))
|
||||
|| (function_exists('stream_wrapper_register') && stream_wrapper_register('phpvfscomposer', 'Composer\BinProxyWrapper'))
|
||||
) {
|
||||
include("phpvfscomposer://" . __DIR__ . '/..'.'/phpstan/phpstan/phpstan.phar');
|
||||
exit(0);
|
||||
}
|
||||
}
|
||||
|
||||
include __DIR__ . '/..'.'/phpstan/phpstan/phpstan.phar';
|
|
@ -42,30 +42,79 @@ namespace Composer\Autoload;
|
|||
*/
|
||||
class ClassLoader
|
||||
{
|
||||
/** @var \Closure(string):void */
|
||||
private static $includeFile;
|
||||
|
||||
/** @var ?string */
|
||||
private $vendorDir;
|
||||
|
||||
// PSR-4
|
||||
/**
|
||||
* @var array[]
|
||||
* @psalm-var array<string, array<string, int>>
|
||||
*/
|
||||
private $prefixLengthsPsr4 = array();
|
||||
/**
|
||||
* @var array[]
|
||||
* @psalm-var array<string, array<int, string>>
|
||||
*/
|
||||
private $prefixDirsPsr4 = array();
|
||||
/**
|
||||
* @var array[]
|
||||
* @psalm-var array<string, string>
|
||||
*/
|
||||
private $fallbackDirsPsr4 = array();
|
||||
|
||||
// PSR-0
|
||||
/**
|
||||
* @var array[]
|
||||
* @psalm-var array<string, array<string, string[]>>
|
||||
*/
|
||||
private $prefixesPsr0 = array();
|
||||
/**
|
||||
* @var array[]
|
||||
* @psalm-var array<string, string>
|
||||
*/
|
||||
private $fallbackDirsPsr0 = array();
|
||||
|
||||
/** @var bool */
|
||||
private $useIncludePath = false;
|
||||
|
||||
/**
|
||||
* @var string[]
|
||||
* @psalm-var array<string, string>
|
||||
*/
|
||||
private $classMap = array();
|
||||
|
||||
/** @var bool */
|
||||
private $classMapAuthoritative = false;
|
||||
|
||||
/**
|
||||
* @var bool[]
|
||||
* @psalm-var array<string, bool>
|
||||
*/
|
||||
private $missingClasses = array();
|
||||
|
||||
/** @var ?string */
|
||||
private $apcuPrefix;
|
||||
|
||||
/**
|
||||
* @var self[]
|
||||
*/
|
||||
private static $registeredLoaders = array();
|
||||
|
||||
/**
|
||||
* @param ?string $vendorDir
|
||||
*/
|
||||
public function __construct($vendorDir = null)
|
||||
{
|
||||
$this->vendorDir = $vendorDir;
|
||||
self::initializeIncludeClosure();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string[]
|
||||
*/
|
||||
public function getPrefixes()
|
||||
{
|
||||
if (!empty($this->prefixesPsr0)) {
|
||||
|
@ -75,28 +124,47 @@ class ClassLoader
|
|||
return array();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array[]
|
||||
* @psalm-return array<string, array<int, string>>
|
||||
*/
|
||||
public function getPrefixesPsr4()
|
||||
{
|
||||
return $this->prefixDirsPsr4;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array[]
|
||||
* @psalm-return array<string, string>
|
||||
*/
|
||||
public function getFallbackDirs()
|
||||
{
|
||||
return $this->fallbackDirsPsr0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array[]
|
||||
* @psalm-return array<string, string>
|
||||
*/
|
||||
public function getFallbackDirsPsr4()
|
||||
{
|
||||
return $this->fallbackDirsPsr4;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string[] Array of classname => path
|
||||
* @psalm-return array<string, string>
|
||||
*/
|
||||
public function getClassMap()
|
||||
{
|
||||
return $this->classMap;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $classMap Class to filename map
|
||||
* @param string[] $classMap Class to filename map
|
||||
* @psalm-param array<string, string> $classMap
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function addClassMap(array $classMap)
|
||||
{
|
||||
|
@ -112,8 +180,10 @@ class ClassLoader
|
|||
* appending or prepending to the ones previously set for this prefix.
|
||||
*
|
||||
* @param string $prefix The prefix
|
||||
* @param array|string $paths The PSR-0 root directories
|
||||
* @param string[]|string $paths The PSR-0 root directories
|
||||
* @param bool $prepend Whether to prepend the directories
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function add($prefix, $paths, $prepend = false)
|
||||
{
|
||||
|
@ -157,10 +227,12 @@ class ClassLoader
|
|||
* appending or prepending to the ones previously set for this namespace.
|
||||
*
|
||||
* @param string $prefix The prefix/namespace, with trailing '\\'
|
||||
* @param array|string $paths The PSR-4 base directories
|
||||
* @param string[]|string $paths The PSR-4 base directories
|
||||
* @param bool $prepend Whether to prepend the directories
|
||||
*
|
||||
* @throws \InvalidArgumentException
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function addPsr4($prefix, $paths, $prepend = false)
|
||||
{
|
||||
|
@ -205,7 +277,9 @@ class ClassLoader
|
|||
* replacing any others previously set for this prefix.
|
||||
*
|
||||
* @param string $prefix The prefix
|
||||
* @param array|string $paths The PSR-0 base directories
|
||||
* @param string[]|string $paths The PSR-0 base directories
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function set($prefix, $paths)
|
||||
{
|
||||
|
@ -221,9 +295,11 @@ class ClassLoader
|
|||
* replacing any others previously set for this namespace.
|
||||
*
|
||||
* @param string $prefix The prefix/namespace, with trailing '\\'
|
||||
* @param array|string $paths The PSR-4 base directories
|
||||
* @param string[]|string $paths The PSR-4 base directories
|
||||
*
|
||||
* @throws \InvalidArgumentException
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function setPsr4($prefix, $paths)
|
||||
{
|
||||
|
@ -243,6 +319,8 @@ class ClassLoader
|
|||
* Turns on searching the include path for class files.
|
||||
*
|
||||
* @param bool $useIncludePath
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function setUseIncludePath($useIncludePath)
|
||||
{
|
||||
|
@ -265,6 +343,8 @@ class ClassLoader
|
|||
* that have not been registered with the class map.
|
||||
*
|
||||
* @param bool $classMapAuthoritative
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function setClassMapAuthoritative($classMapAuthoritative)
|
||||
{
|
||||
|
@ -285,6 +365,8 @@ class ClassLoader
|
|||
* APCu prefix to use to cache found/not-found classes, if the extension is enabled.
|
||||
*
|
||||
* @param string|null $apcuPrefix
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function setApcuPrefix($apcuPrefix)
|
||||
{
|
||||
|
@ -305,14 +387,18 @@ class ClassLoader
|
|||
* Registers this instance as an autoloader.
|
||||
*
|
||||
* @param bool $prepend Whether to prepend the autoloader or not
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function register($prepend = false)
|
||||
{
|
||||
spl_autoload_register(array($this, 'loadClass'), true, $prepend);
|
||||
|
||||
if (null === $this->vendorDir) {
|
||||
//no-op
|
||||
} elseif ($prepend) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ($prepend) {
|
||||
self::$registeredLoaders = array($this->vendorDir => $this) + self::$registeredLoaders;
|
||||
} else {
|
||||
unset(self::$registeredLoaders[$this->vendorDir]);
|
||||
|
@ -322,6 +408,8 @@ class ClassLoader
|
|||
|
||||
/**
|
||||
* Unregisters this instance as an autoloader.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function unregister()
|
||||
{
|
||||
|
@ -336,15 +424,18 @@ class ClassLoader
|
|||
* Loads the given class or interface.
|
||||
*
|
||||
* @param string $class The name of the class
|
||||
* @return bool|null True if loaded, null otherwise
|
||||
* @return true|null True if loaded, null otherwise
|
||||
*/
|
||||
public function loadClass($class)
|
||||
{
|
||||
if ($file = $this->findFile($class)) {
|
||||
includeFile($file);
|
||||
$includeFile = self::$includeFile;
|
||||
$includeFile($file);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -399,6 +490,11 @@ class ClassLoader
|
|||
return self::$registeredLoaders;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $class
|
||||
* @param string $ext
|
||||
* @return string|false
|
||||
*/
|
||||
private function findFileWithExtension($class, $ext)
|
||||
{
|
||||
// PSR-4 lookup
|
||||
|
@ -464,14 +560,26 @@ class ClassLoader
|
|||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
/**
|
||||
* @return void
|
||||
*/
|
||||
private static function initializeIncludeClosure()
|
||||
{
|
||||
if (self::$includeFile !== null) {
|
||||
return;
|
||||
}
|
||||
|
||||
/**
|
||||
* Scope isolated include.
|
||||
*
|
||||
* Prevents access to $this/self from included files.
|
||||
*
|
||||
* @param string $file
|
||||
* @return void
|
||||
*/
|
||||
function includeFile($file)
|
||||
{
|
||||
self::$includeFile = \Closure::bind(static function($file) {
|
||||
include $file;
|
||||
}, null, null);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -18,414 +18,29 @@ use Composer\Semver\VersionParser;
|
|||
/**
|
||||
* This class is copied in every Composer installed project and available to all
|
||||
*
|
||||
* To require it's presence, you can require `composer-runtime-api ^2.0`
|
||||
* See also https://getcomposer.org/doc/07-runtime.md#installed-versions
|
||||
*
|
||||
* To require its presence, you can require `composer-runtime-api ^2.0`
|
||||
*
|
||||
* @final
|
||||
*/
|
||||
class InstalledVersions
|
||||
{
|
||||
private static $installed = array (
|
||||
'root' =>
|
||||
array (
|
||||
'pretty_version' => 'dev-master',
|
||||
'version' => 'dev-master',
|
||||
'aliases' =>
|
||||
array (
|
||||
),
|
||||
'reference' => '26c67dba776e1e6f8ac40eed70fe79995325863d',
|
||||
'name' => '__root__',
|
||||
),
|
||||
'versions' =>
|
||||
array (
|
||||
'__root__' =>
|
||||
array (
|
||||
'pretty_version' => 'dev-master',
|
||||
'version' => 'dev-master',
|
||||
'aliases' =>
|
||||
array (
|
||||
),
|
||||
'reference' => '26c67dba776e1e6f8ac40eed70fe79995325863d',
|
||||
),
|
||||
'beberlei/assert' =>
|
||||
array (
|
||||
'pretty_version' => 'v3.3.2',
|
||||
'version' => '3.3.2.0',
|
||||
'aliases' =>
|
||||
array (
|
||||
),
|
||||
'reference' => 'cb70015c04be1baee6f5f5c953703347c0ac1655',
|
||||
),
|
||||
'chillerlan/php-qrcode' =>
|
||||
array (
|
||||
'pretty_version' => '4.3.4',
|
||||
'version' => '4.3.4.0',
|
||||
'aliases' =>
|
||||
array (
|
||||
),
|
||||
'reference' => '2ca4bf5ae048af1981d1023ee42a0a2a9d51e51d',
|
||||
),
|
||||
'chillerlan/php-settings-container' =>
|
||||
array (
|
||||
'pretty_version' => '2.1.4',
|
||||
'version' => '2.1.4.0',
|
||||
'aliases' =>
|
||||
array (
|
||||
),
|
||||
'reference' => '1beb7df3c14346d4344b0b2e12f6f9a74feabd4a',
|
||||
),
|
||||
'doctrine/instantiator' =>
|
||||
array (
|
||||
'pretty_version' => '1.4.1',
|
||||
'version' => '1.4.1.0',
|
||||
'aliases' =>
|
||||
array (
|
||||
),
|
||||
'reference' => '10dcfce151b967d20fde1b34ae6640712c3891bc',
|
||||
),
|
||||
'j4mie/idiorm' =>
|
||||
array (
|
||||
'pretty_version' => 'dev-master',
|
||||
'version' => 'dev-master',
|
||||
'aliases' =>
|
||||
array (
|
||||
0 => '9999999-dev',
|
||||
),
|
||||
'reference' => 'efc8ea06698f53e2c479c7696f2b154c47c3a3cb',
|
||||
),
|
||||
'mervick/material-design-icons' =>
|
||||
array (
|
||||
'pretty_version' => '2.2.0',
|
||||
'version' => '2.2.0.0',
|
||||
'aliases' =>
|
||||
array (
|
||||
),
|
||||
'reference' => '635435c8d3df3a6da3241648caf8a65d1c07cc1a',
|
||||
),
|
||||
'myclabs/deep-copy' =>
|
||||
array (
|
||||
'pretty_version' => '1.11.0',
|
||||
'version' => '1.11.0.0',
|
||||
'aliases' =>
|
||||
array (
|
||||
),
|
||||
'reference' => '14daed4296fae74d9e3201d2c4925d1acb7aa614',
|
||||
),
|
||||
'nikic/php-parser' =>
|
||||
array (
|
||||
'pretty_version' => 'v4.14.0',
|
||||
'version' => '4.14.0.0',
|
||||
'aliases' =>
|
||||
array (
|
||||
),
|
||||
'reference' => '34bea19b6e03d8153165d8f30bba4c3be86184c1',
|
||||
),
|
||||
'paragonie/constant_time_encoding' =>
|
||||
array (
|
||||
'pretty_version' => 'v2.6.3',
|
||||
'version' => '2.6.3.0',
|
||||
'aliases' =>
|
||||
array (
|
||||
),
|
||||
'reference' => '58c3f47f650c94ec05a151692652a868995d2938',
|
||||
),
|
||||
'phar-io/manifest' =>
|
||||
array (
|
||||
'pretty_version' => '2.0.3',
|
||||
'version' => '2.0.3.0',
|
||||
'aliases' =>
|
||||
array (
|
||||
),
|
||||
'reference' => '97803eca37d319dfa7826cc2437fc020857acb53',
|
||||
),
|
||||
'phar-io/version' =>
|
||||
array (
|
||||
'pretty_version' => '3.2.1',
|
||||
'version' => '3.2.1.0',
|
||||
'aliases' =>
|
||||
array (
|
||||
),
|
||||
'reference' => '4f7fd7836c6f332bb2933569e566a0d6c4cbed74',
|
||||
),
|
||||
'phpdocumentor/reflection-common' =>
|
||||
array (
|
||||
'pretty_version' => '2.2.0',
|
||||
'version' => '2.2.0.0',
|
||||
'aliases' =>
|
||||
array (
|
||||
),
|
||||
'reference' => '1d01c49d4ed62f25aa84a747ad35d5a16924662b',
|
||||
),
|
||||
'phpdocumentor/reflection-docblock' =>
|
||||
array (
|
||||
'pretty_version' => '5.3.0',
|
||||
'version' => '5.3.0.0',
|
||||
'aliases' =>
|
||||
array (
|
||||
),
|
||||
'reference' => '622548b623e81ca6d78b721c5e029f4ce664f170',
|
||||
),
|
||||
'phpdocumentor/type-resolver' =>
|
||||
array (
|
||||
'pretty_version' => '1.6.1',
|
||||
'version' => '1.6.1.0',
|
||||
'aliases' =>
|
||||
array (
|
||||
),
|
||||
'reference' => '77a32518733312af16a44300404e945338981de3',
|
||||
),
|
||||
'phpspec/prophecy' =>
|
||||
array (
|
||||
'pretty_version' => 'v1.15.0',
|
||||
'version' => '1.15.0.0',
|
||||
'aliases' =>
|
||||
array (
|
||||
),
|
||||
'reference' => 'bbcd7380b0ebf3961ee21409db7b38bc31d69a13',
|
||||
),
|
||||
'phpstan/phpstan' =>
|
||||
array (
|
||||
'pretty_version' => '1.8.2',
|
||||
'version' => '1.8.2.0',
|
||||
'aliases' =>
|
||||
array (
|
||||
),
|
||||
'reference' => 'c53312ecc575caf07b0e90dee43883fdf90ca67c',
|
||||
),
|
||||
'phpunit/php-code-coverage' =>
|
||||
array (
|
||||
'pretty_version' => '9.2.15',
|
||||
'version' => '9.2.15.0',
|
||||
'aliases' =>
|
||||
array (
|
||||
),
|
||||
'reference' => '2e9da11878c4202f97915c1cb4bb1ca318a63f5f',
|
||||
),
|
||||
'phpunit/php-file-iterator' =>
|
||||
array (
|
||||
'pretty_version' => '3.0.6',
|
||||
'version' => '3.0.6.0',
|
||||
'aliases' =>
|
||||
array (
|
||||
),
|
||||
'reference' => 'cf1c2e7c203ac650e352f4cc675a7021e7d1b3cf',
|
||||
),
|
||||
'phpunit/php-invoker' =>
|
||||
array (
|
||||
'pretty_version' => '3.1.1',
|
||||
'version' => '3.1.1.0',
|
||||
'aliases' =>
|
||||
array (
|
||||
),
|
||||
'reference' => '5a10147d0aaf65b58940a0b72f71c9ac0423cc67',
|
||||
),
|
||||
'phpunit/php-text-template' =>
|
||||
array (
|
||||
'pretty_version' => '2.0.4',
|
||||
'version' => '2.0.4.0',
|
||||
'aliases' =>
|
||||
array (
|
||||
),
|
||||
'reference' => '5da5f67fc95621df9ff4c4e5a84d6a8a2acf7c28',
|
||||
),
|
||||
'phpunit/php-timer' =>
|
||||
array (
|
||||
'pretty_version' => '5.0.3',
|
||||
'version' => '5.0.3.0',
|
||||
'aliases' =>
|
||||
array (
|
||||
),
|
||||
'reference' => '5a63ce20ed1b5bf577850e2c4e87f4aa902afbd2',
|
||||
),
|
||||
'phpunit/phpunit' =>
|
||||
array (
|
||||
'pretty_version' => '9.5.16',
|
||||
'version' => '9.5.16.0',
|
||||
'aliases' =>
|
||||
array (
|
||||
),
|
||||
'reference' => '5ff8c545a50226c569310a35f4fa89d79f1ddfdc',
|
||||
),
|
||||
'sebastian/cli-parser' =>
|
||||
array (
|
||||
'pretty_version' => '1.0.1',
|
||||
'version' => '1.0.1.0',
|
||||
'aliases' =>
|
||||
array (
|
||||
),
|
||||
'reference' => '442e7c7e687e42adc03470c7b668bc4b2402c0b2',
|
||||
),
|
||||
'sebastian/code-unit' =>
|
||||
array (
|
||||
'pretty_version' => '1.0.8',
|
||||
'version' => '1.0.8.0',
|
||||
'aliases' =>
|
||||
array (
|
||||
),
|
||||
'reference' => '1fc9f64c0927627ef78ba436c9b17d967e68e120',
|
||||
),
|
||||
'sebastian/code-unit-reverse-lookup' =>
|
||||
array (
|
||||
'pretty_version' => '2.0.3',
|
||||
'version' => '2.0.3.0',
|
||||
'aliases' =>
|
||||
array (
|
||||
),
|
||||
'reference' => 'ac91f01ccec49fb77bdc6fd1e548bc70f7faa3e5',
|
||||
),
|
||||
'sebastian/comparator' =>
|
||||
array (
|
||||
'pretty_version' => '4.0.6',
|
||||
'version' => '4.0.6.0',
|
||||
'aliases' =>
|
||||
array (
|
||||
),
|
||||
'reference' => '55f4261989e546dc112258c7a75935a81a7ce382',
|
||||
),
|
||||
'sebastian/complexity' =>
|
||||
array (
|
||||
'pretty_version' => '2.0.2',
|
||||
'version' => '2.0.2.0',
|
||||
'aliases' =>
|
||||
array (
|
||||
),
|
||||
'reference' => '739b35e53379900cc9ac327b2147867b8b6efd88',
|
||||
),
|
||||
'sebastian/diff' =>
|
||||
array (
|
||||
'pretty_version' => '4.0.4',
|
||||
'version' => '4.0.4.0',
|
||||
'aliases' =>
|
||||
array (
|
||||
),
|
||||
'reference' => '3461e3fccc7cfdfc2720be910d3bd73c69be590d',
|
||||
),
|
||||
'sebastian/environment' =>
|
||||
array (
|
||||
'pretty_version' => '5.1.4',
|
||||
'version' => '5.1.4.0',
|
||||
'aliases' =>
|
||||
array (
|
||||
),
|
||||
'reference' => '1b5dff7bb151a4db11d49d90e5408e4e938270f7',
|
||||
),
|
||||
'sebastian/exporter' =>
|
||||
array (
|
||||
'pretty_version' => '4.0.4',
|
||||
'version' => '4.0.4.0',
|
||||
'aliases' =>
|
||||
array (
|
||||
),
|
||||
'reference' => '65e8b7db476c5dd267e65eea9cab77584d3cfff9',
|
||||
),
|
||||
'sebastian/global-state' =>
|
||||
array (
|
||||
'pretty_version' => '5.0.5',
|
||||
'version' => '5.0.5.0',
|
||||
'aliases' =>
|
||||
array (
|
||||
),
|
||||
'reference' => '0ca8db5a5fc9c8646244e629625ac486fa286bf2',
|
||||
),
|
||||
'sebastian/lines-of-code' =>
|
||||
array (
|
||||
'pretty_version' => '1.0.3',
|
||||
'version' => '1.0.3.0',
|
||||
'aliases' =>
|
||||
array (
|
||||
),
|
||||
'reference' => 'c1c2e997aa3146983ed888ad08b15470a2e22ecc',
|
||||
),
|
||||
'sebastian/object-enumerator' =>
|
||||
array (
|
||||
'pretty_version' => '4.0.4',
|
||||
'version' => '4.0.4.0',
|
||||
'aliases' =>
|
||||
array (
|
||||
),
|
||||
'reference' => '5c9eeac41b290a3712d88851518825ad78f45c71',
|
||||
),
|
||||
'sebastian/object-reflector' =>
|
||||
array (
|
||||
'pretty_version' => '2.0.4',
|
||||
'version' => '2.0.4.0',
|
||||
'aliases' =>
|
||||
array (
|
||||
),
|
||||
'reference' => 'b4f479ebdbf63ac605d183ece17d8d7fe49c15c7',
|
||||
),
|
||||
'sebastian/recursion-context' =>
|
||||
array (
|
||||
'pretty_version' => '4.0.4',
|
||||
'version' => '4.0.4.0',
|
||||
'aliases' =>
|
||||
array (
|
||||
),
|
||||
'reference' => 'cd9d8cf3c5804de4341c283ed787f099f5506172',
|
||||
),
|
||||
'sebastian/resource-operations' =>
|
||||
array (
|
||||
'pretty_version' => '3.0.3',
|
||||
'version' => '3.0.3.0',
|
||||
'aliases' =>
|
||||
array (
|
||||
),
|
||||
'reference' => '0f4443cb3a1d92ce809899753bc0d5d5a8dd19a8',
|
||||
),
|
||||
'sebastian/type' =>
|
||||
array (
|
||||
'pretty_version' => '2.3.4',
|
||||
'version' => '2.3.4.0',
|
||||
'aliases' =>
|
||||
array (
|
||||
),
|
||||
'reference' => 'b8cd8a1c753c90bc1a0f5372170e3e489136f914',
|
||||
),
|
||||
'sebastian/version' =>
|
||||
array (
|
||||
'pretty_version' => '3.0.2',
|
||||
'version' => '3.0.2.0',
|
||||
'aliases' =>
|
||||
array (
|
||||
),
|
||||
'reference' => 'c6c1022351a901512170118436c764e473f6de8c',
|
||||
),
|
||||
'spomky-labs/otphp' =>
|
||||
array (
|
||||
'pretty_version' => 'v10.0.3',
|
||||
'version' => '10.0.3.0',
|
||||
'aliases' =>
|
||||
array (
|
||||
),
|
||||
'reference' => '9784d9f7c790eed26e102d6c78f12c754036c366',
|
||||
),
|
||||
'thecodingmachine/safe' =>
|
||||
array (
|
||||
'pretty_version' => 'v2.2.2',
|
||||
'version' => '2.2.2.0',
|
||||
'aliases' =>
|
||||
array (
|
||||
),
|
||||
'reference' => '440284f9592c9df402832452a6871a8b3c48d97e',
|
||||
),
|
||||
'theseer/tokenizer' =>
|
||||
array (
|
||||
'pretty_version' => '1.2.1',
|
||||
'version' => '1.2.1.0',
|
||||
'aliases' =>
|
||||
array (
|
||||
),
|
||||
'reference' => '34a41e998c2183e22995f158c581e7b5e755ab9e',
|
||||
),
|
||||
'webmozart/assert' =>
|
||||
array (
|
||||
'pretty_version' => '1.11.0',
|
||||
'version' => '1.11.0.0',
|
||||
'aliases' =>
|
||||
array (
|
||||
),
|
||||
'reference' => '11cb2199493b2f8a3b53e7f19068fc6aac760991',
|
||||
),
|
||||
),
|
||||
);
|
||||
/**
|
||||
* @var mixed[]|null
|
||||
* @psalm-var array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array<string, array{pretty_version?: string, version?: string, reference?: string|null, type?: string, install_path?: string, aliases?: string[], dev_requirement: bool, replaced?: string[], provided?: string[]}>}|array{}|null
|
||||
*/
|
||||
private static $installed;
|
||||
|
||||
/**
|
||||
* @var bool|null
|
||||
*/
|
||||
private static $canGetVendors;
|
||||
|
||||
/**
|
||||
* @var array[]
|
||||
* @psalm-var array<string, array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array<string, array{pretty_version?: string, version?: string, reference?: string|null, type?: string, install_path?: string, aliases?: string[], dev_requirement: bool, replaced?: string[], provided?: string[]}>}>
|
||||
*/
|
||||
private static $installedByVendor = array();
|
||||
|
||||
/**
|
||||
|
@ -441,7 +56,6 @@ class InstalledVersions
|
|||
$packages[] = array_keys($installed['versions']);
|
||||
}
|
||||
|
||||
|
||||
if (1 === \count($packages)) {
|
||||
return $packages[0];
|
||||
}
|
||||
|
@ -449,19 +63,42 @@ class InstalledVersions
|
|||
return array_keys(array_flip(\call_user_func_array('array_merge', $packages)));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a list of all package names with a specific type e.g. 'library'
|
||||
*
|
||||
* @param string $type
|
||||
* @return string[]
|
||||
* @psalm-return list<string>
|
||||
*/
|
||||
public static function getInstalledPackagesByType($type)
|
||||
{
|
||||
$packagesByType = array();
|
||||
|
||||
foreach (self::getInstalled() as $installed) {
|
||||
foreach ($installed['versions'] as $name => $package) {
|
||||
if (isset($package['type']) && $package['type'] === $type) {
|
||||
$packagesByType[] = $name;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $packagesByType;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether the given package is installed
|
||||
*
|
||||
* This also returns true if the package name is provided or replaced by another package
|
||||
*
|
||||
* @param string $packageName
|
||||
* @param bool $includeDevRequirements
|
||||
* @return bool
|
||||
*/
|
||||
public static function isInstalled($packageName)
|
||||
public static function isInstalled($packageName, $includeDevRequirements = true)
|
||||
{
|
||||
foreach (self::getInstalled() as $installed) {
|
||||
if (isset($installed['versions'][$packageName])) {
|
||||
return true;
|
||||
return $includeDevRequirements || empty($installed['versions'][$packageName]['dev_requirement']);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -478,7 +115,6 @@ class InstalledVersions
|
|||
* @param VersionParser $parser Install composer/semver to have access to this class and functionality
|
||||
* @param string $packageName
|
||||
* @param string|null $constraint A version constraint to check for, if you pass one you have to make sure composer/semver is required by your package
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public static function satisfies(VersionParser $parser, $packageName, $constraint)
|
||||
|
@ -588,9 +224,26 @@ class InstalledVersions
|
|||
throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed');
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $packageName
|
||||
* @return string|null If the package is being replaced or provided but is not really installed, null will be returned as install path. Packages of type metapackages also have a null install path.
|
||||
*/
|
||||
public static function getInstallPath($packageName)
|
||||
{
|
||||
foreach (self::getInstalled() as $installed) {
|
||||
if (!isset($installed['versions'][$packageName])) {
|
||||
continue;
|
||||
}
|
||||
|
||||
return isset($installed['versions'][$packageName]['install_path']) ? $installed['versions'][$packageName]['install_path'] : null;
|
||||
}
|
||||
|
||||
throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed');
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
* @psalm-return array{name: string, version: string, reference: string, pretty_version: string, aliases: string[]}
|
||||
* @psalm-return array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}
|
||||
*/
|
||||
public static function getRootPackage()
|
||||
{
|
||||
|
@ -602,14 +255,38 @@ class InstalledVersions
|
|||
/**
|
||||
* Returns the raw installed.php data for custom implementations
|
||||
*
|
||||
* @deprecated Use getAllRawData() instead which returns all datasets for all autoloaders present in the process. getRawData only returns the first dataset loaded, which may not be what you expect.
|
||||
* @return array[]
|
||||
* @psalm-return array{root: array{name: string, version: string, reference: string, pretty_version: string, aliases: string[]}, versions: list<string, array{pretty_version: ?string, version: ?string, aliases: ?string[], reference: ?string, replaced: ?string[], provided: ?string[]}>}
|
||||
* @psalm-return array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array<string, array{pretty_version?: string, version?: string, reference?: string|null, type?: string, install_path?: string, aliases?: string[], dev_requirement: bool, replaced?: string[], provided?: string[]}>}
|
||||
*/
|
||||
public static function getRawData()
|
||||
{
|
||||
@trigger_error('getRawData only returns the first dataset loaded, which may not be what you expect. Use getAllRawData() instead which returns all datasets for all autoloaders present in the process.', E_USER_DEPRECATED);
|
||||
|
||||
if (null === self::$installed) {
|
||||
// only require the installed.php file if this file is loaded from its dumped location,
|
||||
// and not from its source location in the composer/composer package, see https://github.com/composer/composer/issues/9937
|
||||
if (substr(__DIR__, -8, 1) !== 'C') {
|
||||
self::$installed = include __DIR__ . '/installed.php';
|
||||
} else {
|
||||
self::$installed = array();
|
||||
}
|
||||
}
|
||||
|
||||
return self::$installed;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the raw data of all installed.php which are currently loaded for custom implementations
|
||||
*
|
||||
* @return array[]
|
||||
* @psalm-return list<array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array<string, array{pretty_version?: string, version?: string, reference?: string|null, type?: string, install_path?: string, aliases?: string[], dev_requirement: bool, replaced?: string[], provided?: string[]}>}>
|
||||
*/
|
||||
public static function getAllRawData()
|
||||
{
|
||||
return self::getInstalled();
|
||||
}
|
||||
|
||||
/**
|
||||
* Lets you reload the static array from another file
|
||||
*
|
||||
|
@ -626,7 +303,7 @@ class InstalledVersions
|
|||
* @param array[] $data A vendor/composer/installed.php data set
|
||||
* @return void
|
||||
*
|
||||
* @psalm-param array{root: array{name: string, version: string, reference: string, pretty_version: string, aliases: string[]}, versions: list<string, array{pretty_version: ?string, version: ?string, aliases: ?string[], reference: ?string, replaced: ?string[], provided: ?string[]}>} $data
|
||||
* @psalm-param array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array<string, array{pretty_version?: string, version?: string, reference?: string|null, type?: string, install_path?: string, aliases?: string[], dev_requirement: bool, replaced?: string[], provided?: string[]}>} $data
|
||||
*/
|
||||
public static function reload($data)
|
||||
{
|
||||
|
@ -636,6 +313,7 @@ class InstalledVersions
|
|||
|
||||
/**
|
||||
* @return array[]
|
||||
* @psalm-return list<array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array<string, array{pretty_version?: string, version?: string, reference?: string|null, type?: string, install_path?: string, aliases?: string[], dev_requirement: bool, replaced?: string[], provided?: string[]}>}>
|
||||
*/
|
||||
private static function getInstalled()
|
||||
{
|
||||
|
@ -646,16 +324,27 @@ class InstalledVersions
|
|||
$installed = array();
|
||||
|
||||
if (self::$canGetVendors) {
|
||||
// @phpstan-ignore-next-line
|
||||
foreach (ClassLoader::getRegisteredLoaders() as $vendorDir => $loader) {
|
||||
if (isset(self::$installedByVendor[$vendorDir])) {
|
||||
$installed[] = self::$installedByVendor[$vendorDir];
|
||||
} elseif (is_file($vendorDir.'/composer/installed.php')) {
|
||||
$installed[] = self::$installedByVendor[$vendorDir] = require $vendorDir.'/composer/installed.php';
|
||||
if (null === self::$installed && strtr($vendorDir.'/composer', '\\', '/') === strtr(__DIR__, '\\', '/')) {
|
||||
self::$installed = $installed[count($installed) - 1];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (null === self::$installed) {
|
||||
// only require the installed.php file if this file is loaded from its dumped location,
|
||||
// and not from its source location in the composer/composer package, see https://github.com/composer/composer/issues/9937
|
||||
if (substr(__DIR__, -8, 1) !== 'C') {
|
||||
self::$installed = require __DIR__ . '/installed.php';
|
||||
} else {
|
||||
self::$installed = array();
|
||||
}
|
||||
}
|
||||
$installed[] = self::$installed;
|
||||
|
||||
return $installed;
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
|
||||
Copyright (c) Nils Adermann, Jordi Boggiano
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
|
@ -17,3 +18,4 @@ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
// autoload_classmap.php @generated by Composer
|
||||
|
||||
$vendorDir = dirname(dirname(__FILE__));
|
||||
$vendorDir = dirname(__DIR__);
|
||||
$baseDir = dirname($vendorDir);
|
||||
|
||||
return array(
|
||||
|
|
|
@ -2,12 +2,10 @@
|
|||
|
||||
// autoload_files.php @generated by Composer
|
||||
|
||||
$vendorDir = dirname(dirname(__FILE__));
|
||||
$vendorDir = dirname(__DIR__);
|
||||
$baseDir = dirname($vendorDir);
|
||||
|
||||
return array(
|
||||
'9b38cf48e83f5d8f60375221cd213eee' => $vendorDir . '/phpstan/phpstan/bootstrap.php',
|
||||
'ec07570ca5a812141189b1fa81503674' => $vendorDir . '/phpunit/phpunit/src/Framework/Assert/Functions.php',
|
||||
'a4ecaeafb8cfb009ad0e052c90355e98' => $vendorDir . '/beberlei/assert/lib/Assert/functions.php',
|
||||
'6124b4c8570aa390c21fafd04a26c69f' => $vendorDir . '/myclabs/deep-copy/src/DeepCopy/deep_copy.php',
|
||||
'51fcf4e06c07cc00c920b44bcd900e7a' => $vendorDir . '/thecodingmachine/safe/deprecated/apc.php',
|
||||
|
@ -97,4 +95,6 @@ return array(
|
|||
'4af1dca6db8c527c6eed27bff85ff0e5' => $vendorDir . '/thecodingmachine/safe/generated/yaz.php',
|
||||
'fe43ca06499ac37bc2dedd823af71eb5' => $vendorDir . '/thecodingmachine/safe/generated/zip.php',
|
||||
'356736db98a6834f0a886b8d509b0ecd' => $vendorDir . '/thecodingmachine/safe/generated/zlib.php',
|
||||
'9b38cf48e83f5d8f60375221cd213eee' => $vendorDir . '/phpstan/phpstan/bootstrap.php',
|
||||
'ec07570ca5a812141189b1fa81503674' => $vendorDir . '/phpunit/phpunit/src/Framework/Assert/Functions.php',
|
||||
);
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
// autoload_namespaces.php @generated by Composer
|
||||
|
||||
$vendorDir = dirname(dirname(__FILE__));
|
||||
$vendorDir = dirname(__DIR__);
|
||||
$baseDir = dirname($vendorDir);
|
||||
|
||||
return array(
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
// autoload_psr4.php @generated by Composer
|
||||
|
||||
$vendorDir = dirname(dirname(__FILE__));
|
||||
$vendorDir = dirname(__DIR__);
|
||||
$baseDir = dirname($vendorDir);
|
||||
|
||||
return array(
|
||||
|
|
|
@ -23,51 +23,26 @@ class ComposerAutoloaderInit19fc2ff1c0f9a92279c7979386bb2056
|
|||
}
|
||||
|
||||
spl_autoload_register(array('ComposerAutoloaderInit19fc2ff1c0f9a92279c7979386bb2056', 'loadClassLoader'), true, true);
|
||||
self::$loader = $loader = new \Composer\Autoload\ClassLoader(\dirname(\dirname(__FILE__)));
|
||||
self::$loader = $loader = new \Composer\Autoload\ClassLoader(\dirname(__DIR__));
|
||||
spl_autoload_unregister(array('ComposerAutoloaderInit19fc2ff1c0f9a92279c7979386bb2056', 'loadClassLoader'));
|
||||
|
||||
$useStaticLoader = PHP_VERSION_ID >= 50600 && !defined('HHVM_VERSION') && (!function_exists('zend_loader_file_encoded') || !zend_loader_file_encoded());
|
||||
if ($useStaticLoader) {
|
||||
require __DIR__ . '/autoload_static.php';
|
||||
|
||||
call_user_func(\Composer\Autoload\ComposerStaticInit19fc2ff1c0f9a92279c7979386bb2056::getInitializer($loader));
|
||||
} else {
|
||||
$map = require __DIR__ . '/autoload_namespaces.php';
|
||||
foreach ($map as $namespace => $path) {
|
||||
$loader->set($namespace, $path);
|
||||
}
|
||||
|
||||
$map = require __DIR__ . '/autoload_psr4.php';
|
||||
foreach ($map as $namespace => $path) {
|
||||
$loader->setPsr4($namespace, $path);
|
||||
}
|
||||
|
||||
$classMap = require __DIR__ . '/autoload_classmap.php';
|
||||
if ($classMap) {
|
||||
$loader->addClassMap($classMap);
|
||||
}
|
||||
}
|
||||
|
||||
$loader->register(true);
|
||||
|
||||
if ($useStaticLoader) {
|
||||
$includeFiles = Composer\Autoload\ComposerStaticInit19fc2ff1c0f9a92279c7979386bb2056::$files;
|
||||
} else {
|
||||
$includeFiles = require __DIR__ . '/autoload_files.php';
|
||||
$filesToLoad = \Composer\Autoload\ComposerStaticInit19fc2ff1c0f9a92279c7979386bb2056::$files;
|
||||
$requireFile = \Closure::bind(static function ($fileIdentifier, $file) {
|
||||
if (empty($GLOBALS['__composer_autoload_files'][$fileIdentifier])) {
|
||||
$GLOBALS['__composer_autoload_files'][$fileIdentifier] = true;
|
||||
|
||||
require $file;
|
||||
}
|
||||
foreach ($includeFiles as $fileIdentifier => $file) {
|
||||
composerRequire19fc2ff1c0f9a92279c7979386bb2056($fileIdentifier, $file);
|
||||
}, null, null);
|
||||
foreach ($filesToLoad as $fileIdentifier => $file) {
|
||||
$requireFile($fileIdentifier, $file);
|
||||
}
|
||||
|
||||
return $loader;
|
||||
}
|
||||
}
|
||||
|
||||
function composerRequire19fc2ff1c0f9a92279c7979386bb2056($fileIdentifier, $file)
|
||||
{
|
||||
if (empty($GLOBALS['__composer_autoload_files'][$fileIdentifier])) {
|
||||
require $file;
|
||||
|
||||
$GLOBALS['__composer_autoload_files'][$fileIdentifier] = true;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -7,8 +7,6 @@ namespace Composer\Autoload;
|
|||
class ComposerStaticInit19fc2ff1c0f9a92279c7979386bb2056
|
||||
{
|
||||
public static $files = array (
|
||||
'9b38cf48e83f5d8f60375221cd213eee' => __DIR__ . '/..' . '/phpstan/phpstan/bootstrap.php',
|
||||
'ec07570ca5a812141189b1fa81503674' => __DIR__ . '/..' . '/phpunit/phpunit/src/Framework/Assert/Functions.php',
|
||||
'a4ecaeafb8cfb009ad0e052c90355e98' => __DIR__ . '/..' . '/beberlei/assert/lib/Assert/functions.php',
|
||||
'6124b4c8570aa390c21fafd04a26c69f' => __DIR__ . '/..' . '/myclabs/deep-copy/src/DeepCopy/deep_copy.php',
|
||||
'51fcf4e06c07cc00c920b44bcd900e7a' => __DIR__ . '/..' . '/thecodingmachine/safe/deprecated/apc.php',
|
||||
|
@ -98,6 +96,8 @@ class ComposerStaticInit19fc2ff1c0f9a92279c7979386bb2056
|
|||
'4af1dca6db8c527c6eed27bff85ff0e5' => __DIR__ . '/..' . '/thecodingmachine/safe/generated/yaz.php',
|
||||
'fe43ca06499ac37bc2dedd823af71eb5' => __DIR__ . '/..' . '/thecodingmachine/safe/generated/zip.php',
|
||||
'356736db98a6834f0a886b8d509b0ecd' => __DIR__ . '/..' . '/thecodingmachine/safe/generated/zlib.php',
|
||||
'9b38cf48e83f5d8f60375221cd213eee' => __DIR__ . '/..' . '/phpstan/phpstan/bootstrap.php',
|
||||
'ec07570ca5a812141189b1fa81503674' => __DIR__ . '/..' . '/phpunit/phpunit/src/Framework/Assert/Functions.php',
|
||||
);
|
||||
|
||||
public static $prefixLengthsPsr4 = array (
|
||||
|
|
|
@ -954,17 +954,17 @@
|
|||
},
|
||||
{
|
||||
"name": "phpstan/phpstan",
|
||||
"version": "1.8.2",
|
||||
"version_normalized": "1.8.2.0",
|
||||
"version": "1.10.3",
|
||||
"version_normalized": "1.10.3.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/phpstan/phpstan.git",
|
||||
"reference": "c53312ecc575caf07b0e90dee43883fdf90ca67c"
|
||||
"reference": "5419375b5891add97dc74be71e6c1c34baaddf64"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/phpstan/phpstan/zipball/c53312ecc575caf07b0e90dee43883fdf90ca67c",
|
||||
"reference": "c53312ecc575caf07b0e90dee43883fdf90ca67c",
|
||||
"url": "https://api.github.com/repos/phpstan/phpstan/zipball/5419375b5891add97dc74be71e6c1c34baaddf64",
|
||||
"reference": "5419375b5891add97dc74be71e6c1c34baaddf64",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
|
@ -973,7 +973,7 @@
|
|||
"conflict": {
|
||||
"phpstan/phpstan-shim": "*"
|
||||
},
|
||||
"time": "2022-07-20T09:57:31+00:00",
|
||||
"time": "2023-02-25T14:47:13+00:00",
|
||||
"bin": [
|
||||
"phpstan",
|
||||
"phpstan.phar"
|
||||
|
@ -990,9 +990,13 @@
|
|||
"MIT"
|
||||
],
|
||||
"description": "PHPStan - PHP Static Analysis Tool",
|
||||
"keywords": [
|
||||
"dev",
|
||||
"static analysis"
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/phpstan/phpstan/issues",
|
||||
"source": "https://github.com/phpstan/phpstan/tree/1.8.2"
|
||||
"source": "https://github.com/phpstan/phpstan/tree/1.10.3"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
|
@ -1003,10 +1007,6 @@
|
|||
"url": "https://github.com/phpstan",
|
||||
"type": "github"
|
||||
},
|
||||
{
|
||||
"url": "https://www.patreon.com/phpstan",
|
||||
"type": "patreon"
|
||||
},
|
||||
{
|
||||
"url": "https://tidelift.com/funding/github/packagist/phpstan/phpstan",
|
||||
"type": "tidelift"
|
||||
|
|
|
@ -1,403 +1,403 @@
|
|||
<?php return array (
|
||||
'root' =>
|
||||
array (
|
||||
'pretty_version' => 'dev-master',
|
||||
'version' => 'dev-master',
|
||||
'aliases' =>
|
||||
array (
|
||||
),
|
||||
'reference' => '26c67dba776e1e6f8ac40eed70fe79995325863d',
|
||||
<?php return array(
|
||||
'root' => array(
|
||||
'name' => '__root__',
|
||||
),
|
||||
'versions' =>
|
||||
array (
|
||||
'__root__' =>
|
||||
array (
|
||||
'pretty_version' => 'dev-master',
|
||||
'version' => 'dev-master',
|
||||
'aliases' =>
|
||||
array (
|
||||
'reference' => 'b7a6c948d078a59739f14de8454e0e7237d0722e',
|
||||
'type' => 'library',
|
||||
'install_path' => __DIR__ . '/../../',
|
||||
'aliases' => array(),
|
||||
'dev' => true,
|
||||
),
|
||||
'reference' => '26c67dba776e1e6f8ac40eed70fe79995325863d',
|
||||
'versions' => array(
|
||||
'__root__' => array(
|
||||
'pretty_version' => 'dev-master',
|
||||
'version' => 'dev-master',
|
||||
'reference' => 'b7a6c948d078a59739f14de8454e0e7237d0722e',
|
||||
'type' => 'library',
|
||||
'install_path' => __DIR__ . '/../../',
|
||||
'aliases' => array(),
|
||||
'dev_requirement' => false,
|
||||
),
|
||||
'beberlei/assert' =>
|
||||
array (
|
||||
'beberlei/assert' => array(
|
||||
'pretty_version' => 'v3.3.2',
|
||||
'version' => '3.3.2.0',
|
||||
'aliases' =>
|
||||
array (
|
||||
),
|
||||
'reference' => 'cb70015c04be1baee6f5f5c953703347c0ac1655',
|
||||
'type' => 'library',
|
||||
'install_path' => __DIR__ . '/../beberlei/assert',
|
||||
'aliases' => array(),
|
||||
'dev_requirement' => false,
|
||||
),
|
||||
'chillerlan/php-qrcode' =>
|
||||
array (
|
||||
'chillerlan/php-qrcode' => array(
|
||||
'pretty_version' => '4.3.4',
|
||||
'version' => '4.3.4.0',
|
||||
'aliases' =>
|
||||
array (
|
||||
),
|
||||
'reference' => '2ca4bf5ae048af1981d1023ee42a0a2a9d51e51d',
|
||||
'type' => 'library',
|
||||
'install_path' => __DIR__ . '/../chillerlan/php-qrcode',
|
||||
'aliases' => array(),
|
||||
'dev_requirement' => false,
|
||||
),
|
||||
'chillerlan/php-settings-container' =>
|
||||
array (
|
||||
'chillerlan/php-settings-container' => array(
|
||||
'pretty_version' => '2.1.4',
|
||||
'version' => '2.1.4.0',
|
||||
'aliases' =>
|
||||
array (
|
||||
),
|
||||
'reference' => '1beb7df3c14346d4344b0b2e12f6f9a74feabd4a',
|
||||
'type' => 'library',
|
||||
'install_path' => __DIR__ . '/../chillerlan/php-settings-container',
|
||||
'aliases' => array(),
|
||||
'dev_requirement' => false,
|
||||
),
|
||||
'doctrine/instantiator' =>
|
||||
array (
|
||||
'doctrine/instantiator' => array(
|
||||
'pretty_version' => '1.4.1',
|
||||
'version' => '1.4.1.0',
|
||||
'aliases' =>
|
||||
array (
|
||||
),
|
||||
'reference' => '10dcfce151b967d20fde1b34ae6640712c3891bc',
|
||||
'type' => 'library',
|
||||
'install_path' => __DIR__ . '/../doctrine/instantiator',
|
||||
'aliases' => array(),
|
||||
'dev_requirement' => true,
|
||||
),
|
||||
'j4mie/idiorm' =>
|
||||
array (
|
||||
'j4mie/idiorm' => array(
|
||||
'pretty_version' => 'dev-master',
|
||||
'version' => 'dev-master',
|
||||
'aliases' =>
|
||||
array (
|
||||
'reference' => 'efc8ea06698f53e2c479c7696f2b154c47c3a3cb',
|
||||
'type' => 'library',
|
||||
'install_path' => __DIR__ . '/../j4mie/idiorm',
|
||||
'aliases' => array(
|
||||
0 => '9999999-dev',
|
||||
),
|
||||
'reference' => 'efc8ea06698f53e2c479c7696f2b154c47c3a3cb',
|
||||
'dev_requirement' => false,
|
||||
),
|
||||
'mervick/material-design-icons' =>
|
||||
array (
|
||||
'mervick/material-design-icons' => array(
|
||||
'pretty_version' => '2.2.0',
|
||||
'version' => '2.2.0.0',
|
||||
'aliases' =>
|
||||
array (
|
||||
),
|
||||
'reference' => '635435c8d3df3a6da3241648caf8a65d1c07cc1a',
|
||||
'type' => 'library',
|
||||
'install_path' => __DIR__ . '/../mervick/material-design-icons',
|
||||
'aliases' => array(),
|
||||
'dev_requirement' => false,
|
||||
),
|
||||
'myclabs/deep-copy' =>
|
||||
array (
|
||||
'myclabs/deep-copy' => array(
|
||||
'pretty_version' => '1.11.0',
|
||||
'version' => '1.11.0.0',
|
||||
'aliases' =>
|
||||
array (
|
||||
),
|
||||
'reference' => '14daed4296fae74d9e3201d2c4925d1acb7aa614',
|
||||
'type' => 'library',
|
||||
'install_path' => __DIR__ . '/../myclabs/deep-copy',
|
||||
'aliases' => array(),
|
||||
'dev_requirement' => true,
|
||||
),
|
||||
'nikic/php-parser' =>
|
||||
array (
|
||||
'nikic/php-parser' => array(
|
||||
'pretty_version' => 'v4.14.0',
|
||||
'version' => '4.14.0.0',
|
||||
'aliases' =>
|
||||
array (
|
||||
),
|
||||
'reference' => '34bea19b6e03d8153165d8f30bba4c3be86184c1',
|
||||
'type' => 'library',
|
||||
'install_path' => __DIR__ . '/../nikic/php-parser',
|
||||
'aliases' => array(),
|
||||
'dev_requirement' => true,
|
||||
),
|
||||
'paragonie/constant_time_encoding' =>
|
||||
array (
|
||||
'paragonie/constant_time_encoding' => array(
|
||||
'pretty_version' => 'v2.6.3',
|
||||
'version' => '2.6.3.0',
|
||||
'aliases' =>
|
||||
array (
|
||||
),
|
||||
'reference' => '58c3f47f650c94ec05a151692652a868995d2938',
|
||||
'type' => 'library',
|
||||
'install_path' => __DIR__ . '/../paragonie/constant_time_encoding',
|
||||
'aliases' => array(),
|
||||
'dev_requirement' => false,
|
||||
),
|
||||
'phar-io/manifest' =>
|
||||
array (
|
||||
'phar-io/manifest' => array(
|
||||
'pretty_version' => '2.0.3',
|
||||
'version' => '2.0.3.0',
|
||||
'aliases' =>
|
||||
array (
|
||||
),
|
||||
'reference' => '97803eca37d319dfa7826cc2437fc020857acb53',
|
||||
'type' => 'library',
|
||||
'install_path' => __DIR__ . '/../phar-io/manifest',
|
||||
'aliases' => array(),
|
||||
'dev_requirement' => true,
|
||||
),
|
||||
'phar-io/version' =>
|
||||
array (
|
||||
'phar-io/version' => array(
|
||||
'pretty_version' => '3.2.1',
|
||||
'version' => '3.2.1.0',
|
||||
'aliases' =>
|
||||
array (
|
||||
),
|
||||
'reference' => '4f7fd7836c6f332bb2933569e566a0d6c4cbed74',
|
||||
'type' => 'library',
|
||||
'install_path' => __DIR__ . '/../phar-io/version',
|
||||
'aliases' => array(),
|
||||
'dev_requirement' => true,
|
||||
),
|
||||
'phpdocumentor/reflection-common' =>
|
||||
array (
|
||||
'phpdocumentor/reflection-common' => array(
|
||||
'pretty_version' => '2.2.0',
|
||||
'version' => '2.2.0.0',
|
||||
'aliases' =>
|
||||
array (
|
||||
),
|
||||
'reference' => '1d01c49d4ed62f25aa84a747ad35d5a16924662b',
|
||||
'type' => 'library',
|
||||
'install_path' => __DIR__ . '/../phpdocumentor/reflection-common',
|
||||
'aliases' => array(),
|
||||
'dev_requirement' => true,
|
||||
),
|
||||
'phpdocumentor/reflection-docblock' =>
|
||||
array (
|
||||
'phpdocumentor/reflection-docblock' => array(
|
||||
'pretty_version' => '5.3.0',
|
||||
'version' => '5.3.0.0',
|
||||
'aliases' =>
|
||||
array (
|
||||
),
|
||||
'reference' => '622548b623e81ca6d78b721c5e029f4ce664f170',
|
||||
'type' => 'library',
|
||||
'install_path' => __DIR__ . '/../phpdocumentor/reflection-docblock',
|
||||
'aliases' => array(),
|
||||
'dev_requirement' => true,
|
||||
),
|
||||
'phpdocumentor/type-resolver' =>
|
||||
array (
|
||||
'phpdocumentor/type-resolver' => array(
|
||||
'pretty_version' => '1.6.1',
|
||||
'version' => '1.6.1.0',
|
||||
'aliases' =>
|
||||
array (
|
||||
),
|
||||
'reference' => '77a32518733312af16a44300404e945338981de3',
|
||||
'type' => 'library',
|
||||
'install_path' => __DIR__ . '/../phpdocumentor/type-resolver',
|
||||
'aliases' => array(),
|
||||
'dev_requirement' => true,
|
||||
),
|
||||
'phpspec/prophecy' =>
|
||||
array (
|
||||
'phpspec/prophecy' => array(
|
||||
'pretty_version' => 'v1.15.0',
|
||||
'version' => '1.15.0.0',
|
||||
'aliases' =>
|
||||
array (
|
||||
),
|
||||
'reference' => 'bbcd7380b0ebf3961ee21409db7b38bc31d69a13',
|
||||
'type' => 'library',
|
||||
'install_path' => __DIR__ . '/../phpspec/prophecy',
|
||||
'aliases' => array(),
|
||||
'dev_requirement' => true,
|
||||
),
|
||||
'phpstan/phpstan' =>
|
||||
array (
|
||||
'pretty_version' => '1.8.2',
|
||||
'version' => '1.8.2.0',
|
||||
'aliases' =>
|
||||
array (
|
||||
'phpstan/phpstan' => array(
|
||||
'pretty_version' => '1.10.3',
|
||||
'version' => '1.10.3.0',
|
||||
'reference' => '5419375b5891add97dc74be71e6c1c34baaddf64',
|
||||
'type' => 'library',
|
||||
'install_path' => __DIR__ . '/../phpstan/phpstan',
|
||||
'aliases' => array(),
|
||||
'dev_requirement' => true,
|
||||
),
|
||||
'reference' => 'c53312ecc575caf07b0e90dee43883fdf90ca67c',
|
||||
),
|
||||
'phpunit/php-code-coverage' =>
|
||||
array (
|
||||
'phpunit/php-code-coverage' => array(
|
||||
'pretty_version' => '9.2.15',
|
||||
'version' => '9.2.15.0',
|
||||
'aliases' =>
|
||||
array (
|
||||
),
|
||||
'reference' => '2e9da11878c4202f97915c1cb4bb1ca318a63f5f',
|
||||
'type' => 'library',
|
||||
'install_path' => __DIR__ . '/../phpunit/php-code-coverage',
|
||||
'aliases' => array(),
|
||||
'dev_requirement' => true,
|
||||
),
|
||||
'phpunit/php-file-iterator' =>
|
||||
array (
|
||||
'phpunit/php-file-iterator' => array(
|
||||
'pretty_version' => '3.0.6',
|
||||
'version' => '3.0.6.0',
|
||||
'aliases' =>
|
||||
array (
|
||||
),
|
||||
'reference' => 'cf1c2e7c203ac650e352f4cc675a7021e7d1b3cf',
|
||||
'type' => 'library',
|
||||
'install_path' => __DIR__ . '/../phpunit/php-file-iterator',
|
||||
'aliases' => array(),
|
||||
'dev_requirement' => true,
|
||||
),
|
||||
'phpunit/php-invoker' =>
|
||||
array (
|
||||
'phpunit/php-invoker' => array(
|
||||
'pretty_version' => '3.1.1',
|
||||
'version' => '3.1.1.0',
|
||||
'aliases' =>
|
||||
array (
|
||||
),
|
||||
'reference' => '5a10147d0aaf65b58940a0b72f71c9ac0423cc67',
|
||||
'type' => 'library',
|
||||
'install_path' => __DIR__ . '/../phpunit/php-invoker',
|
||||
'aliases' => array(),
|
||||
'dev_requirement' => true,
|
||||
),
|
||||
'phpunit/php-text-template' =>
|
||||
array (
|
||||
'phpunit/php-text-template' => array(
|
||||
'pretty_version' => '2.0.4',
|
||||
'version' => '2.0.4.0',
|
||||
'aliases' =>
|
||||
array (
|
||||
),
|
||||
'reference' => '5da5f67fc95621df9ff4c4e5a84d6a8a2acf7c28',
|
||||
'type' => 'library',
|
||||
'install_path' => __DIR__ . '/../phpunit/php-text-template',
|
||||
'aliases' => array(),
|
||||
'dev_requirement' => true,
|
||||
),
|
||||
'phpunit/php-timer' =>
|
||||
array (
|
||||
'phpunit/php-timer' => array(
|
||||
'pretty_version' => '5.0.3',
|
||||
'version' => '5.0.3.0',
|
||||
'aliases' =>
|
||||
array (
|
||||
),
|
||||
'reference' => '5a63ce20ed1b5bf577850e2c4e87f4aa902afbd2',
|
||||
'type' => 'library',
|
||||
'install_path' => __DIR__ . '/../phpunit/php-timer',
|
||||
'aliases' => array(),
|
||||
'dev_requirement' => true,
|
||||
),
|
||||
'phpunit/phpunit' =>
|
||||
array (
|
||||
'phpunit/phpunit' => array(
|
||||
'pretty_version' => '9.5.16',
|
||||
'version' => '9.5.16.0',
|
||||
'aliases' =>
|
||||
array (
|
||||
),
|
||||
'reference' => '5ff8c545a50226c569310a35f4fa89d79f1ddfdc',
|
||||
'type' => 'library',
|
||||
'install_path' => __DIR__ . '/../phpunit/phpunit',
|
||||
'aliases' => array(),
|
||||
'dev_requirement' => true,
|
||||
),
|
||||
'sebastian/cli-parser' =>
|
||||
array (
|
||||
'sebastian/cli-parser' => array(
|
||||
'pretty_version' => '1.0.1',
|
||||
'version' => '1.0.1.0',
|
||||
'aliases' =>
|
||||
array (
|
||||
),
|
||||
'reference' => '442e7c7e687e42adc03470c7b668bc4b2402c0b2',
|
||||
'type' => 'library',
|
||||
'install_path' => __DIR__ . '/../sebastian/cli-parser',
|
||||
'aliases' => array(),
|
||||
'dev_requirement' => true,
|
||||
),
|
||||
'sebastian/code-unit' =>
|
||||
array (
|
||||
'sebastian/code-unit' => array(
|
||||
'pretty_version' => '1.0.8',
|
||||
'version' => '1.0.8.0',
|
||||
'aliases' =>
|
||||
array (
|
||||
),
|
||||
'reference' => '1fc9f64c0927627ef78ba436c9b17d967e68e120',
|
||||
'type' => 'library',
|
||||
'install_path' => __DIR__ . '/../sebastian/code-unit',
|
||||
'aliases' => array(),
|
||||
'dev_requirement' => true,
|
||||
),
|
||||
'sebastian/code-unit-reverse-lookup' =>
|
||||
array (
|
||||
'sebastian/code-unit-reverse-lookup' => array(
|
||||
'pretty_version' => '2.0.3',
|
||||
'version' => '2.0.3.0',
|
||||
'aliases' =>
|
||||
array (
|
||||
),
|
||||
'reference' => 'ac91f01ccec49fb77bdc6fd1e548bc70f7faa3e5',
|
||||
'type' => 'library',
|
||||
'install_path' => __DIR__ . '/../sebastian/code-unit-reverse-lookup',
|
||||
'aliases' => array(),
|
||||
'dev_requirement' => true,
|
||||
),
|
||||
'sebastian/comparator' =>
|
||||
array (
|
||||
'sebastian/comparator' => array(
|
||||
'pretty_version' => '4.0.6',
|
||||
'version' => '4.0.6.0',
|
||||
'aliases' =>
|
||||
array (
|
||||
),
|
||||
'reference' => '55f4261989e546dc112258c7a75935a81a7ce382',
|
||||
'type' => 'library',
|
||||
'install_path' => __DIR__ . '/../sebastian/comparator',
|
||||
'aliases' => array(),
|
||||
'dev_requirement' => true,
|
||||
),
|
||||
'sebastian/complexity' =>
|
||||
array (
|
||||
'sebastian/complexity' => array(
|
||||
'pretty_version' => '2.0.2',
|
||||
'version' => '2.0.2.0',
|
||||
'aliases' =>
|
||||
array (
|
||||
),
|
||||
'reference' => '739b35e53379900cc9ac327b2147867b8b6efd88',
|
||||
'type' => 'library',
|
||||
'install_path' => __DIR__ . '/../sebastian/complexity',
|
||||
'aliases' => array(),
|
||||
'dev_requirement' => true,
|
||||
),
|
||||
'sebastian/diff' =>
|
||||
array (
|
||||
'sebastian/diff' => array(
|
||||
'pretty_version' => '4.0.4',
|
||||
'version' => '4.0.4.0',
|
||||
'aliases' =>
|
||||
array (
|
||||
),
|
||||
'reference' => '3461e3fccc7cfdfc2720be910d3bd73c69be590d',
|
||||
'type' => 'library',
|
||||
'install_path' => __DIR__ . '/../sebastian/diff',
|
||||
'aliases' => array(),
|
||||
'dev_requirement' => true,
|
||||
),
|
||||
'sebastian/environment' =>
|
||||
array (
|
||||
'sebastian/environment' => array(
|
||||
'pretty_version' => '5.1.4',
|
||||
'version' => '5.1.4.0',
|
||||
'aliases' =>
|
||||
array (
|
||||
),
|
||||
'reference' => '1b5dff7bb151a4db11d49d90e5408e4e938270f7',
|
||||
'type' => 'library',
|
||||
'install_path' => __DIR__ . '/../sebastian/environment',
|
||||
'aliases' => array(),
|
||||
'dev_requirement' => true,
|
||||
),
|
||||
'sebastian/exporter' =>
|
||||
array (
|
||||
'sebastian/exporter' => array(
|
||||
'pretty_version' => '4.0.4',
|
||||
'version' => '4.0.4.0',
|
||||
'aliases' =>
|
||||
array (
|
||||
),
|
||||
'reference' => '65e8b7db476c5dd267e65eea9cab77584d3cfff9',
|
||||
'type' => 'library',
|
||||
'install_path' => __DIR__ . '/../sebastian/exporter',
|
||||
'aliases' => array(),
|
||||
'dev_requirement' => true,
|
||||
),
|
||||
'sebastian/global-state' =>
|
||||
array (
|
||||
'sebastian/global-state' => array(
|
||||
'pretty_version' => '5.0.5',
|
||||
'version' => '5.0.5.0',
|
||||
'aliases' =>
|
||||
array (
|
||||
),
|
||||
'reference' => '0ca8db5a5fc9c8646244e629625ac486fa286bf2',
|
||||
'type' => 'library',
|
||||
'install_path' => __DIR__ . '/../sebastian/global-state',
|
||||
'aliases' => array(),
|
||||
'dev_requirement' => true,
|
||||
),
|
||||
'sebastian/lines-of-code' =>
|
||||
array (
|
||||
'sebastian/lines-of-code' => array(
|
||||
'pretty_version' => '1.0.3',
|
||||
'version' => '1.0.3.0',
|
||||
'aliases' =>
|
||||
array (
|
||||
),
|
||||
'reference' => 'c1c2e997aa3146983ed888ad08b15470a2e22ecc',
|
||||
'type' => 'library',
|
||||
'install_path' => __DIR__ . '/../sebastian/lines-of-code',
|
||||
'aliases' => array(),
|
||||
'dev_requirement' => true,
|
||||
),
|
||||
'sebastian/object-enumerator' =>
|
||||
array (
|
||||
'sebastian/object-enumerator' => array(
|
||||
'pretty_version' => '4.0.4',
|
||||
'version' => '4.0.4.0',
|
||||
'aliases' =>
|
||||
array (
|
||||
),
|
||||
'reference' => '5c9eeac41b290a3712d88851518825ad78f45c71',
|
||||
'type' => 'library',
|
||||
'install_path' => __DIR__ . '/../sebastian/object-enumerator',
|
||||
'aliases' => array(),
|
||||
'dev_requirement' => true,
|
||||
),
|
||||
'sebastian/object-reflector' =>
|
||||
array (
|
||||
'sebastian/object-reflector' => array(
|
||||
'pretty_version' => '2.0.4',
|
||||
'version' => '2.0.4.0',
|
||||
'aliases' =>
|
||||
array (
|
||||
),
|
||||
'reference' => 'b4f479ebdbf63ac605d183ece17d8d7fe49c15c7',
|
||||
'type' => 'library',
|
||||
'install_path' => __DIR__ . '/../sebastian/object-reflector',
|
||||
'aliases' => array(),
|
||||
'dev_requirement' => true,
|
||||
),
|
||||
'sebastian/recursion-context' =>
|
||||
array (
|
||||
'sebastian/recursion-context' => array(
|
||||
'pretty_version' => '4.0.4',
|
||||
'version' => '4.0.4.0',
|
||||
'aliases' =>
|
||||
array (
|
||||
),
|
||||
'reference' => 'cd9d8cf3c5804de4341c283ed787f099f5506172',
|
||||
'type' => 'library',
|
||||
'install_path' => __DIR__ . '/../sebastian/recursion-context',
|
||||
'aliases' => array(),
|
||||
'dev_requirement' => true,
|
||||
),
|
||||
'sebastian/resource-operations' =>
|
||||
array (
|
||||
'sebastian/resource-operations' => array(
|
||||
'pretty_version' => '3.0.3',
|
||||
'version' => '3.0.3.0',
|
||||
'aliases' =>
|
||||
array (
|
||||
),
|
||||
'reference' => '0f4443cb3a1d92ce809899753bc0d5d5a8dd19a8',
|
||||
'type' => 'library',
|
||||
'install_path' => __DIR__ . '/../sebastian/resource-operations',
|
||||
'aliases' => array(),
|
||||
'dev_requirement' => true,
|
||||
),
|
||||
'sebastian/type' =>
|
||||
array (
|
||||
'sebastian/type' => array(
|
||||
'pretty_version' => '2.3.4',
|
||||
'version' => '2.3.4.0',
|
||||
'aliases' =>
|
||||
array (
|
||||
),
|
||||
'reference' => 'b8cd8a1c753c90bc1a0f5372170e3e489136f914',
|
||||
'type' => 'library',
|
||||
'install_path' => __DIR__ . '/../sebastian/type',
|
||||
'aliases' => array(),
|
||||
'dev_requirement' => true,
|
||||
),
|
||||
'sebastian/version' =>
|
||||
array (
|
||||
'sebastian/version' => array(
|
||||
'pretty_version' => '3.0.2',
|
||||
'version' => '3.0.2.0',
|
||||
'aliases' =>
|
||||
array (
|
||||
),
|
||||
'reference' => 'c6c1022351a901512170118436c764e473f6de8c',
|
||||
'type' => 'library',
|
||||
'install_path' => __DIR__ . '/../sebastian/version',
|
||||
'aliases' => array(),
|
||||
'dev_requirement' => true,
|
||||
),
|
||||
'spomky-labs/otphp' =>
|
||||
array (
|
||||
'spomky-labs/otphp' => array(
|
||||
'pretty_version' => 'v10.0.3',
|
||||
'version' => '10.0.3.0',
|
||||
'aliases' =>
|
||||
array (
|
||||
),
|
||||
'reference' => '9784d9f7c790eed26e102d6c78f12c754036c366',
|
||||
'type' => 'library',
|
||||
'install_path' => __DIR__ . '/../spomky-labs/otphp',
|
||||
'aliases' => array(),
|
||||
'dev_requirement' => false,
|
||||
),
|
||||
'thecodingmachine/safe' =>
|
||||
array (
|
||||
'thecodingmachine/safe' => array(
|
||||
'pretty_version' => 'v2.2.2',
|
||||
'version' => '2.2.2.0',
|
||||
'aliases' =>
|
||||
array (
|
||||
),
|
||||
'reference' => '440284f9592c9df402832452a6871a8b3c48d97e',
|
||||
'type' => 'library',
|
||||
'install_path' => __DIR__ . '/../thecodingmachine/safe',
|
||||
'aliases' => array(),
|
||||
'dev_requirement' => false,
|
||||
),
|
||||
'theseer/tokenizer' =>
|
||||
array (
|
||||
'theseer/tokenizer' => array(
|
||||
'pretty_version' => '1.2.1',
|
||||
'version' => '1.2.1.0',
|
||||
'aliases' =>
|
||||
array (
|
||||
),
|
||||
'reference' => '34a41e998c2183e22995f158c581e7b5e755ab9e',
|
||||
'type' => 'library',
|
||||
'install_path' => __DIR__ . '/../theseer/tokenizer',
|
||||
'aliases' => array(),
|
||||
'dev_requirement' => true,
|
||||
),
|
||||
'webmozart/assert' =>
|
||||
array (
|
||||
'webmozart/assert' => array(
|
||||
'pretty_version' => '1.11.0',
|
||||
'version' => '1.11.0.0',
|
||||
'aliases' =>
|
||||
array (
|
||||
),
|
||||
'reference' => '11cb2199493b2f8a3b53e7f19068fc6aac760991',
|
||||
'type' => 'library',
|
||||
'install_path' => __DIR__ . '/../webmozart/assert',
|
||||
'aliases' => array(),
|
||||
'dev_requirement' => true,
|
||||
),
|
||||
),
|
||||
);
|
||||
|
|
|
@ -18,9 +18,9 @@ PHPStan focuses on finding errors in your code without actually running it. It c
|
|||
even before you write tests for the code. It moves PHP closer to compiled languages in the sense that the correctness of each line of the code
|
||||
can be checked before you run the actual line.
|
||||
|
||||
**[Read more about PHPStan in an introductory article »](https://phpstan.org/blog/find-bugs-in-your-code-without-writing-tests)**
|
||||
**[Read more about PHPStan »](https://phpstan.org/)**
|
||||
|
||||
**[Try out PHPStan on the on-line playground! »](https://phpstan.org/)**
|
||||
**[Try out PHPStan on the on-line playground! »](https://phpstan.org/try)**
|
||||
|
||||
## Sponsors
|
||||
|
||||
|
@ -46,7 +46,7 @@ can be checked before you run the actual line.
|
|||
<br>
|
||||
<a href="https://zol.fr?utm_source=phpstan"><img src="https://i.imgur.com/dzDgd4s.png" alt="ZOL" width="283" height="64"></a>
|
||||
|
||||
<a href="https://kocourek.uk/"><img src="https://i.imgur.com/EX29z98.png" alt="Stepan Kocourek" width="294" height="64"></a>
|
||||
<a href="https://www.psyonix.com/"><img src="https://i.imgur.com/p8svxQZ.png" alt="Psyonix" width="254" height="65"></a>
|
||||
<br>
|
||||
<a href="https://www.shopware.com/en/"><img src="https://i.imgur.com/L4X5w9s.png" alt="Shopware" width="284" height="64"></a>
|
||||
|
||||
|
@ -60,7 +60,8 @@ can be checked before you run the actual line.
|
|||
|
||||
<a href="https://inviqa.com/"><img src="https://i.imgur.com/G99rj45.png" alt="Inviqa" width="254" height="65"></a>
|
||||
<br>
|
||||
<a href="https://www.psyonix.com/"><img src="https://i.imgur.com/p8svxQZ.png" alt="Psyonix" width="254" height="65"></a>
|
||||
<a href="https://www.cdn77.com/"><img src="https://i.imgur.com/Oo3wA3m.png" alt="CDN77" width="283" height="64"></a>
|
||||
|
||||
|
||||
[**You can now sponsor my open-source work on PHPStan through GitHub Sponsors.**](https://github.com/sponsors/ondrejmirtes)
|
||||
|
||||
|
@ -85,7 +86,6 @@ PHPStan Pro is a paid add-on on top of open-source PHPStan Static Analysis Tool
|
|||
|
||||
* Web UI for browsing found errors, you can click and open your editor of choice on the offending line.
|
||||
* Continuous analysis (watch mode): scans changed files in the background, refreshes the UI automatically.
|
||||
* Interactive fixer: lets you choose the right fix for found errors :blush:
|
||||
|
||||
Try it on PHPStan 0.12.45 or later by running it with the `--pro` option. You can create an account either by following the on-screen instructions, or by visiting [account.phpstan.com](https://account.phpstan.com/).
|
||||
|
||||
|
|
|
@ -21,8 +21,8 @@ final class PharAutoloader
|
|||
|
||||
if (self::$composerAutoloader === null) {
|
||||
self::$composerAutoloader = require 'phar://' . __DIR__ . '/phpstan.phar/vendor/autoload.php';
|
||||
require_once 'phar://' . __DIR__ . '/phpstan.phar/vendor/clue/block-react/src/functions_include.php';
|
||||
require_once 'phar://' . __DIR__ . '/phpstan.phar/vendor/jetbrains/phpstorm-stubs/PhpStormStubsMap.php';
|
||||
require_once 'phar://' . __DIR__ . '/phpstan.phar/vendor/react/async/src/functions_include.php';
|
||||
require_once 'phar://' . __DIR__ . '/phpstan.phar/vendor/react/promise-stream/src/functions_include.php';
|
||||
require_once 'phar://' . __DIR__ . '/phpstan.phar/vendor/react/promise-timer/src/functions_include.php';
|
||||
require_once 'phar://' . __DIR__ . '/phpstan.phar/vendor/react/promise/src/functions_include.php';
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
"name": "phpstan/phpstan",
|
||||
"description": "PHPStan - PHP Static Analysis Tool",
|
||||
"license": ["MIT"],
|
||||
"keywords": ["dev", "static analysis"],
|
||||
"require": {
|
||||
"php": "^7.2|^8.0"
|
||||
},
|
||||
|
|
Binary file not shown.
|
@ -1,16 +1,16 @@
|
|||
-----BEGIN PGP SIGNATURE-----
|
||||
|
||||
iQIzBAABCgAdFiEE0yaA1ZV9xxFr4pwUzxoQjQ565yAFAmLX0XwACgkQzxoQjQ56
|
||||
5yAmDw/+KPoaY+vsYXrYjbNcYmXyH+9ca8Yl1WkgqMOAAiojQBAdN+PIeXqdM4P1
|
||||
ODJq7SGPqhR5j9dK3k4wxvTkmAVlFHWCbOQS0eCueoV2s0w0Sg9xkut7zTMwwBTp
|
||||
I+0TbU9W7DdnDk6k6xoNCNhT8OYpMElmwhS9nChoY2+cwdWJNZ0Lr5JeXwvb5R7W
|
||||
YnHUqO/zTIAjwJNdKwb27J9szwL3GQ4nB9gSoKXCFQTIONszfMYNwboy3VlD8m/F
|
||||
irh9ZZeZsMlCpEO9Rsqx4QyOvbLy0D2jEOKNYzXPQea9dx9gQvDiWJrVETsQBwkc
|
||||
iWJ/HJVhs3ng7iyUfMr8VAPn7rf+3fSqYeQUs5Z5/ubqABF2ZI9/4DIPGsXtqH7q
|
||||
b5OTOvSucvRpsxudnJElKWhkCjZUyjYzBqGdZ6erCh+GTiM4uFNB/en/QObfHmP2
|
||||
z4D41Dk9peLxstqlrwoLL0sJCHR4fQZFvPKrQ6sKlTKliu1zBc0HcEqq3BFalKF+
|
||||
XO2PT1QVNXx/9IqOruKm+M5siY63VKDwE/DXJZZTUPz7GN/Cr9j5Jz3pjq8jL0CR
|
||||
e4D+sEu7xXzlJa7MFqg2odZhLTRYuM/DHZCj3cOyQGlYUQ+tZMGsAiix9JyO7XhB
|
||||
1jzEMugtAglPAsmHr0HR/+oz+YDgwQEmQA4VO4l0swCNmjzLITA=
|
||||
=LM6h
|
||||
iQIzBAABCgAdFiEE0yaA1ZV9xxFr4pwUzxoQjQ565yAFAmP6H1oACgkQzxoQjQ56
|
||||
5yCVhxAAlXqhfvKCITSAJjkaIhncEBHpT5Ogby65BX1O5+SkKyc/OO7JnjlN8cLB
|
||||
DKbJpdc8P2Dbfo/uBHVR5YiNX5CWYzgdMzCpLQI20Ffa7qkeRbA5ZS2AfdIfLqhD
|
||||
PswlQIYxg0F3lj0L+joTxfBiHgmR5wnOUx1sLXnEbqGtFzzGstPGDg9gjKKh5EnO
|
||||
g207jrm1we05+k3kKzr233/ENvQD6bBWLr2yngyMoirOuDpurAuPjkBL7vN6PDbx
|
||||
DlyGDazsgU/R7aE2FtqmFC8KIU/BgnpbCSWTHBEJAqtncHbwTgneyEm+88lT6cUt
|
||||
YM72Rh1+QTvS3WgJ/q7AQRik2aE83Kz2rc3XOl1ADd45J3Oan1rqQXdnKtH6qZeT
|
||||
wMk6PE8SQPJ8NMHy3LT048PfMOakAtgBL5xonbVqX0IFAvKAMRijwBCNKat2yRsB
|
||||
0VGnoeH7klf1fSSo0xOD20Pd0uIILAWZlBjb2e/1NRytFQkokAr1bsLD/VJHiNYh
|
||||
lPQ4OztCT/uumJOAgTKm10T56CK1u0VxhIVtQ+/NkTvAwrmpX0KKqbYPP/1hZqVO
|
||||
vFaWJR4iLFNt+il7dlv56jmTAneUrGrWkQdVFbz5FVpqz7abIo+/cevbSSndFZCI
|
||||
K1mn42aFdYXSqVTFpkzeOQeJPPysEYDysFk7ClhE+F48HN7WAtw=
|
||||
=A7BG
|
||||
-----END PGP SIGNATURE-----
|
||||
|
|
Loading…
Reference in New Issue