├── .gitignore ├── config ├── php_set_memory_limit.ini ├── php_set_timezone.ini ├── php_set_jit.ini ├── _h5ai │ ├── public │ │ ├── images │ │ │ ├── fallback │ │ │ │ ├── file.png │ │ │ │ ├── folder.png │ │ │ │ └── folder-parent.png │ │ │ ├── favicon │ │ │ │ ├── favicon-152.png │ │ │ │ ├── favicon-16.png │ │ │ │ ├── favicon-32.png │ │ │ │ ├── favicon-16-32.ico │ │ │ │ └── favicon.svg │ │ │ ├── themes │ │ │ │ ├── default │ │ │ │ │ ├── aud.svg │ │ │ │ │ ├── vid.svg │ │ │ │ │ ├── folder.svg │ │ │ │ │ ├── file.svg │ │ │ │ │ ├── x.svg │ │ │ │ │ ├── ar.svg │ │ │ │ │ ├── folder-page.svg │ │ │ │ │ ├── txt.svg │ │ │ │ │ ├── folder-parent.svg │ │ │ │ │ ├── img.svg │ │ │ │ │ └── bin.svg │ │ │ │ ├── comity │ │ │ │ │ ├── txt-md.svg │ │ │ │ │ ├── txt-rb.svg │ │ │ │ │ ├── ar-apk.svg │ │ │ │ │ ├── txt-script.svg │ │ │ │ │ ├── txt-php.svg │ │ │ │ │ ├── txt-html.svg │ │ │ │ │ ├── txt-css.svg │ │ │ │ │ ├── txt-py.svg │ │ │ │ │ ├── txt-js.svg │ │ │ │ │ ├── x-pdf.svg │ │ │ │ │ ├── txt-less.svg │ │ │ │ │ ├── txt-rust.svg │ │ │ │ │ ├── ar-rpm.svg │ │ │ │ │ ├── ar-deb.svg │ │ │ │ │ └── txt-go.svg │ │ │ │ └── README.md │ │ │ └── ui │ │ │ │ ├── filter.svg │ │ │ │ ├── crumb.svg │ │ │ │ ├── sort.svg │ │ │ │ ├── download.svg │ │ │ │ ├── preview-next.svg │ │ │ │ ├── preview-prev.svg │ │ │ │ ├── selected.svg │ │ │ │ ├── preview-raw.svg │ │ │ │ ├── sidebar.svg │ │ │ │ ├── tree-indicator.svg │ │ │ │ ├── view-details.svg │ │ │ │ ├── back.svg │ │ │ │ ├── view-icons.svg │ │ │ │ ├── preview-fullscreen.svg │ │ │ │ ├── preview-no-fullscreen.svg │ │ │ │ ├── preview-close.svg │ │ │ │ ├── view-grid.svg │ │ │ │ ├── tree-toggle.svg │ │ │ │ ├── info-toggle.svg │ │ │ │ ├── spinner.svg │ │ │ │ ├── search.svg │ │ │ │ └── paypal.svg │ │ ├── ext │ │ │ └── README.md │ │ ├── cache │ │ │ └── README.md │ │ ├── .htaccess │ │ └── index.php │ ├── private │ │ ├── cache │ │ │ └── README.md │ │ ├── conf │ │ │ ├── l10n │ │ │ │ ├── sk.json │ │ │ │ ├── tr.json │ │ │ │ ├── nb.json │ │ │ │ ├── ro.json │ │ │ │ ├── sr.json │ │ │ │ ├── hu.json │ │ │ │ ├── sv.json │ │ │ │ ├── he.json │ │ │ │ ├── af.json │ │ │ │ ├── da.json │ │ │ │ ├── hi.json │ │ │ │ ├── fi.json │ │ │ │ ├── hr.json │ │ │ │ ├── ja.json │ │ │ │ ├── sl.json │ │ │ │ ├── bg.json │ │ │ │ ├── uk.json │ │ │ │ ├── cs.json │ │ │ │ ├── el.json │ │ │ │ ├── ko.json │ │ │ │ ├── ru.json │ │ │ │ ├── zh-cn.json │ │ │ │ ├── zh-tw.json │ │ │ │ ├── et.json │ │ │ │ ├── id.json │ │ │ │ ├── de.json │ │ │ │ ├── it.json │ │ │ │ ├── nl.json │ │ │ │ ├── pl.json │ │ │ │ ├── lv.json │ │ │ │ ├── es.json │ │ │ │ ├── fr.json │ │ │ │ ├── pt-br.json │ │ │ │ ├── pt-pt.json │ │ │ │ └── en.json │ │ │ ├── types.json │ │ │ └── options.json │ │ └── php │ │ │ ├── core │ │ │ ├── class-session.php │ │ │ ├── class-logger.php │ │ │ ├── class-theme.php │ │ │ ├── class-request.php │ │ │ ├── class-fallback.php │ │ │ ├── class-json.php │ │ │ ├── class-filesize.php │ │ │ ├── class-item.php │ │ │ ├── class-util.php │ │ │ ├── class-api.php │ │ │ ├── class-setup.php │ │ │ └── class-context.php │ │ │ ├── pages │ │ │ ├── info.php │ │ │ └── index.php │ │ │ ├── ext │ │ │ ├── class-search.php │ │ │ ├── class-custom.php │ │ │ ├── class-archive.php │ │ │ └── class-thumb.php │ │ │ └── class-bootstrap.php │ ├── README.md │ ├── .htaccess │ └── CHANGELOG.md ├── h5ai.conf.htpasswd.patch ├── supervisord.conf ├── h5ai.conf └── init.sh ├── docs ├── docker-h5ai-demo.png ├── docker-h5ai-functions.png └── docker-h5ai-php-jit.png ├── .github └── workflows │ └── buildx.yml ├── Dockerfile ├── LICENSE └── README.md /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store -------------------------------------------------------------------------------- /config/php_set_memory_limit.ini: -------------------------------------------------------------------------------- 1 | memory_limit = -1 2 | -------------------------------------------------------------------------------- /config/php_set_timezone.ini: -------------------------------------------------------------------------------- 1 | [Date] 2 | date.timezone=" -------------------------------------------------------------------------------- /docs/docker-h5ai-demo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/awesometic/docker-h5ai/HEAD/docs/docker-h5ai-demo.png -------------------------------------------------------------------------------- /config/php_set_jit.ini: -------------------------------------------------------------------------------- 1 | [opcache] 2 | opcache.enable=1 3 | opcache.jit_buffer_size=100M 4 | opcache.jit=tracing 5 | -------------------------------------------------------------------------------- /docs/docker-h5ai-functions.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/awesometic/docker-h5ai/HEAD/docs/docker-h5ai-functions.png -------------------------------------------------------------------------------- /docs/docker-h5ai-php-jit.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/awesometic/docker-h5ai/HEAD/docs/docker-h5ai-php-jit.png -------------------------------------------------------------------------------- /config/_h5ai/public/images/fallback/file.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/awesometic/docker-h5ai/HEAD/config/_h5ai/public/images/fallback/file.png -------------------------------------------------------------------------------- /config/_h5ai/public/images/fallback/folder.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/awesometic/docker-h5ai/HEAD/config/_h5ai/public/images/fallback/folder.png -------------------------------------------------------------------------------- /config/_h5ai/public/images/favicon/favicon-152.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/awesometic/docker-h5ai/HEAD/config/_h5ai/public/images/favicon/favicon-152.png -------------------------------------------------------------------------------- /config/_h5ai/public/images/favicon/favicon-16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/awesometic/docker-h5ai/HEAD/config/_h5ai/public/images/favicon/favicon-16.png -------------------------------------------------------------------------------- /config/_h5ai/public/images/favicon/favicon-32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/awesometic/docker-h5ai/HEAD/config/_h5ai/public/images/favicon/favicon-32.png -------------------------------------------------------------------------------- /config/_h5ai/public/images/favicon/favicon-16-32.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/awesometic/docker-h5ai/HEAD/config/_h5ai/public/images/favicon/favicon-16-32.ico -------------------------------------------------------------------------------- /config/_h5ai/public/images/fallback/folder-parent.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/awesometic/docker-h5ai/HEAD/config/_h5ai/public/images/fallback/folder-parent.png -------------------------------------------------------------------------------- /config/_h5ai/public/images/themes/default/aud.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /config/_h5ai/public/images/themes/default/vid.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /config/_h5ai/public/images/themes/default/folder.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /config/_h5ai/public/images/favicon/favicon.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /config/_h5ai/public/images/themes/default/file.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /config/_h5ai/public/images/themes/default/x.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /config/_h5ai/public/images/themes/default/ar.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /config/_h5ai/public/images/themes/default/folder-page.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /config/_h5ai/public/ext/README.md: -------------------------------------------------------------------------------- 1 | # Extensions 2 | 3 | This directory is used for additional script and style files. You have to add 4 | them manualy to the `resources` section in `_h5ai/private/conf/options.json`. 5 | -------------------------------------------------------------------------------- /config/_h5ai/public/images/themes/default/txt.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /config/_h5ai/public/images/ui/filter.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /config/_h5ai/public/images/themes/default/folder-parent.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /config/_h5ai/public/images/themes/default/img.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /config/_h5ai/public/images/ui/crumb.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /config/_h5ai/public/images/ui/sort.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /config/_h5ai/public/images/ui/download.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /config/_h5ai/public/images/ui/preview-next.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /config/_h5ai/public/images/ui/preview-prev.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /config/_h5ai/public/images/ui/selected.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /config/_h5ai/public/images/ui/preview-raw.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /config/_h5ai/public/images/ui/sidebar.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /config/_h5ai/public/images/ui/tree-indicator.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /config/_h5ai/public/images/ui/view-details.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /config/_h5ai/public/images/ui/back.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /config/_h5ai/public/images/ui/view-icons.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /config/_h5ai/private/cache/README.md: -------------------------------------------------------------------------------- 1 | # Cache 2 | 3 | Private cache. 4 | 5 | This directory is used for server side caching. To use caching make this 6 | directory writable for your webserver. 7 | 8 | There is no critical data in here. You can savely remove any content. This 9 | will clear the cache. 10 | -------------------------------------------------------------------------------- /config/_h5ai/public/cache/README.md: -------------------------------------------------------------------------------- 1 | # Cache 2 | 3 | Public cache. 4 | 5 | This directory is used for server side caching. To use caching make this 6 | directory writable for your webserver. 7 | 8 | There is no critical data in here. You can savely remove any content. This 9 | will clear the cache. 10 | -------------------------------------------------------------------------------- /config/_h5ai/public/images/ui/preview-fullscreen.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /config/_h5ai/public/images/ui/preview-no-fullscreen.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /config/_h5ai/public/.htaccess: -------------------------------------------------------------------------------- 1 | ## make this folder accessible 2 | 3 | # Apache < 2.3 4 | 5 | Order allow,deny 6 | Allow from all 7 | Satisfy All 8 | 9 | 10 | # Apache ≥ 2.3 11 | 12 | Require all granted 13 | 14 | -------------------------------------------------------------------------------- /config/_h5ai/public/images/themes/comity/txt-md.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /config/_h5ai/public/images/ui/preview-close.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /config/_h5ai/public/images/ui/view-grid.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /config/_h5ai/public/images/ui/tree-toggle.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /config/_h5ai/private/conf/l10n/sk.json: -------------------------------------------------------------------------------- 1 | { 2 | "lang": "slovenčina", 3 | 4 | "details": "podrobnosti", 5 | "empty": "prázdny", 6 | "files": "súborov", 7 | "folders": "priečinkov", 8 | "icons": "ikony", 9 | "lastModified": "Upravené", 10 | "name": "Názov", 11 | "parentDirectory": "Nadriadený priečinok", 12 | "size": "Velkosť" 13 | } 14 | -------------------------------------------------------------------------------- /config/_h5ai/public/images/ui/info-toggle.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /config/_h5ai/private/conf/l10n/tr.json: -------------------------------------------------------------------------------- 1 | { 2 | "lang": "türkçe", 3 | 4 | "details": "detaylar", 5 | "download": "indir", 6 | "empty": "boş", 7 | "files": "dosyalar", 8 | "folders": "klasörler", 9 | "icons": "ikonlar", 10 | "lastModified": "Son Düzenleme", 11 | "name": "İsim", 12 | "parentDirectory": "Üst Dizin", 13 | "size": "Boyut" 14 | } 15 | -------------------------------------------------------------------------------- /config/_h5ai/private/conf/l10n/nb.json: -------------------------------------------------------------------------------- 1 | { 2 | "lang": "norwegian", 3 | 4 | "details": "detaljer", 5 | "download": "last ned", 6 | "empty": "tom", 7 | "files": "filer", 8 | "folders": "mapper", 9 | "icons": "ikoner", 10 | "lastModified": "Sist endret", 11 | "name": "Navn", 12 | "noMatch": "ingen treff", 13 | "parentDirectory": "Overordnet mappe", 14 | "size": "Størrelse" 15 | } 16 | -------------------------------------------------------------------------------- /config/_h5ai/private/conf/l10n/ro.json: -------------------------------------------------------------------------------- 1 | { 2 | "lang": "română", 3 | 4 | "details": "detalii", 5 | "download": "descarcă", 6 | "empty": "gol", 7 | "files": "fişiere", 8 | "folders": "dosar", 9 | "icons": "pictograme", 10 | "lastModified": "ultima modificare", 11 | "name": "nume", 12 | "noMatch": "0 rezultate", 13 | "parentDirectory": "dosar părinte", 14 | "size": "mărime" 15 | } 16 | -------------------------------------------------------------------------------- /config/_h5ai/private/conf/l10n/sr.json: -------------------------------------------------------------------------------- 1 | { 2 | "lang": "srpski", 3 | 4 | "details": "detalji", 5 | "download": "download", 6 | "empty": "prazno", 7 | "files": "fajlovi", 8 | "folders": "direktorijum", 9 | "icons": "ikone", 10 | "lastModified": "Poslednja modifikacija", 11 | "name": "Ime", 12 | "noMatch": "bez poklapanja", 13 | "parentDirectory": "Roditeljski direktorijum", 14 | "size": "Veličina" 15 | } 16 | -------------------------------------------------------------------------------- /config/_h5ai/public/images/themes/README.md: -------------------------------------------------------------------------------- 1 | # Themes 2 | 3 | This directory will contain any themes you add. At the moment there are only 4 | icon themes supported. The folder structure is: `/.`, 5 | with `` one of `svg`, `png` or `jpg`. 6 | 7 | To select a theme use the option `view > theme` in file `conf/options.json`. 8 | 9 | You will find the previously included icon themes [here](https://github.com/lrsjng/h5ai-themes). 10 | -------------------------------------------------------------------------------- /config/h5ai.conf.htpasswd.patch: -------------------------------------------------------------------------------- 1 | --- h5ai.conf 2018-12-13 18:57:35.000000000 +0900 2 | +++ h5ai.conf.htpasswd 2018-12-13 18:57:30.000000000 +0900 3 | @@ -6,6 +6,9 @@ 4 | root /h5ai; 5 | index index.html index.htm index.php /_h5ai/public/index.php; 6 | 7 | + auth_basic "Hello! Welcome to my download page."; 8 | + auth_basic_user_file /config/nginx/.htpasswd; 9 | + 10 | # h5ai 11 | location /_h5ai/ { 12 | root /usr/share/h5ai/; 13 | -------------------------------------------------------------------------------- /config/_h5ai/private/conf/l10n/hu.json: -------------------------------------------------------------------------------- 1 | { 2 | "lang": "magyar", 3 | 4 | "dateFormat": "YYYY-MM-DD HH:mm", 5 | "details": "részletek", 6 | "download": "letöltés", 7 | "empty": "üres", 8 | "files": "fájlok", 9 | "folders": "mappák", 10 | "icons": "ikonok", 11 | "lastModified": "Utoljára módosítva", 12 | "name": "Név", 13 | "noMatch": "nincs találat", 14 | "parentDirectory": "Szülő könyvtár", 15 | "size": "Méret" 16 | } 17 | -------------------------------------------------------------------------------- /config/_h5ai/private/conf/l10n/sv.json: -------------------------------------------------------------------------------- 1 | { 2 | "lang": "svenska", 3 | 4 | "details": "detaljerad", 5 | "download": "ladda ner", 6 | "empty": "tom", 7 | "files": "filer", 8 | "folders": "kataloger", 9 | "grid": "rutnät", 10 | "icons": "ikoner", 11 | "lastModified": "Senast ändrad", 12 | "name": "Filnamn", 13 | "noMatch": "ingen matchning", 14 | "parentDirectory": "Till överordnad mapp", 15 | "size": "Filstorlek" 16 | } 17 | -------------------------------------------------------------------------------- /config/_h5ai/public/images/ui/spinner.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /config/_h5ai/private/conf/l10n/he.json: -------------------------------------------------------------------------------- 1 | { 2 | "lang": "עברית", 3 | 4 | "dateFormat": "DD.MM.YYYY HH:mm", 5 | "details": "פרטים", 6 | "download": "הורדה", 7 | "empty": "ריק", 8 | "files": "קבצים", 9 | "filter": "סינון", 10 | "folders": "תיקיות", 11 | "icons": "צלמיות", 12 | "lastModified": "שינוי אחרון", 13 | "name": "שם", 14 | "noMatch": "אין תוצאות", 15 | "parentDirectory": "תיקיית הורה", 16 | "size": "גודל" 17 | } 18 | -------------------------------------------------------------------------------- /config/_h5ai/public/images/ui/search.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /config/supervisord.conf: -------------------------------------------------------------------------------- 1 | [supervisord] 2 | nodaemon=true 3 | user=root 4 | 5 | [program:php-fpm] 6 | command=php-fpm82 -F 7 | stdout_logfile=/dev/stdout 8 | stdout_logfile_maxbytes=0 9 | stderr_logfile=/dev/stderr 10 | stderr_logfile_maxbytes=0 11 | autorestart=false 12 | startretries=0 13 | 14 | [program:nginx] 15 | command=nginx -g 'daemon off;' 16 | stdout_logfile=/dev/stdout 17 | stdout_logfile_maxbytes=0 18 | stderr_logfile=/dev/stderr 19 | stderr_logfile_maxbytes=0 20 | autorestart=false 21 | startretries=0 22 | -------------------------------------------------------------------------------- /config/_h5ai/private/conf/l10n/af.json: -------------------------------------------------------------------------------- 1 | { 2 | "lang": "afrikaans", 3 | 4 | "dateFormat": "YYYY-MM-DD HH:mm", 5 | "details": "besonderhede", 6 | "download": "aflaai", 7 | "empty": "leeg", 8 | "files": "lêers", 9 | "filter": "filter", 10 | "folders": "gidse", 11 | "grid": "rooster", 12 | "icons": "ikone", 13 | "lastModified": "Laas verander", 14 | "name": "Naam", 15 | "noMatch": "geen resultaat", 16 | "parentDirectory": "Hoër Vlak", 17 | "size": "Grootte" 18 | } 19 | -------------------------------------------------------------------------------- /config/_h5ai/private/conf/l10n/da.json: -------------------------------------------------------------------------------- 1 | { 2 | "lang": "dansk", 3 | 4 | "dateFormat": "DD-MM-YYYY HH:mm", 5 | "details": "detaljer", 6 | "download": "download", 7 | "empty": "tom", 8 | "files": "filer", 9 | "filter": "filter", 10 | "folders": "mapper", 11 | "grid": "grid", 12 | "icons": "ikoner", 13 | "lastModified": "Sidst ændret", 14 | "name": "Navn", 15 | "noMatch": "ingen match", 16 | "parentDirectory": "Overordnet mappe", 17 | "size": "Størrelse" 18 | } 19 | -------------------------------------------------------------------------------- /config/_h5ai/private/conf/l10n/hi.json: -------------------------------------------------------------------------------- 1 | { 2 | "lang": "हिंदी", 3 | 4 | "dateFormat": "DD.MM.YYYY HH:mm", 5 | "details": "विस्तार", 6 | "download": "डाउनलोड", 7 | "empty": "खाली", 8 | "files": "फ़ाइलें", 9 | "filter": "फ़िल्टर", 10 | "folders": "फोल्डर", 11 | "grid": "ग्रिड", 12 | "icons": "आइकॉन", 13 | "lastModified": "पिछला परिवर्तन", 14 | "name": "नाम", 15 | "noMatch": "कोई समानता नहीं", 16 | "parentDirectory": "मूल डायरेक्टरी", 17 | "size": "माप" 18 | } 19 | -------------------------------------------------------------------------------- /config/_h5ai/private/conf/l10n/fi.json: -------------------------------------------------------------------------------- 1 | { 2 | "lang": "finnish", 3 | 4 | "dateFormat": "DD.MM.YYYY HH:mm", 5 | "details": "tiedot", 6 | "download": "lataa", 7 | "empty": "tyhjä", 8 | "files": "tiedostoa", 9 | "filter": "suodata", 10 | "folders": "hakemistoa", 11 | "grid": "ruudukko", 12 | "icons": "ikonit", 13 | "lastModified": "Viimeksi muokattu", 14 | "name": "Nimi", 15 | "noMatch": "ei osumia", 16 | "parentDirectory": "Ylähakemisto", 17 | "size": "Koko" 18 | } 19 | -------------------------------------------------------------------------------- /config/_h5ai/private/conf/l10n/hr.json: -------------------------------------------------------------------------------- 1 | { 2 | "lang": "hrvatski", 3 | 4 | "dateFormat": "YYYY-MM-DD HH:mm", 5 | "details": "detalji", 6 | "download": "preuzmi", 7 | "empty": "prazno", 8 | "files": "datoteka", 9 | "filter": "filter", 10 | "folders": "direktorij(a)", 11 | "grid": "mreža", 12 | "icons": "ikone", 13 | "lastModified": "Posljednja izmjena", 14 | "name": "Naziv", 15 | "noMatch": "nema rezultata", 16 | "parentDirectory": "Natrag", 17 | "size": "Veličina" 18 | } 19 | -------------------------------------------------------------------------------- /config/_h5ai/private/conf/l10n/ja.json: -------------------------------------------------------------------------------- 1 | { 2 | "lang": "日本語", 3 | 4 | "dateFormat": "YYYY-MM-DD HH:mm", 5 | "details": "詳細", 6 | "download": "ダウンロード", 7 | "empty": "(空)", 8 | "files": "ファイル", 9 | "filter": "フィルター", 10 | "folders": "フォルダー", 11 | "grid": "グリッド", 12 | "icons": "アイコン", 13 | "language": "言語", 14 | "lastModified": "最終変更日時", 15 | "name": "名前", 16 | "noMatch": "一致する項目が見つかりません", 17 | "parentDirectory": "親ディレクトリへ", 18 | "size": "サイズ", 19 | "view": "ビュー" 20 | } 21 | -------------------------------------------------------------------------------- /config/_h5ai/private/conf/l10n/sl.json: -------------------------------------------------------------------------------- 1 | { 2 | "lang": "slovenščina", 3 | 4 | "dateFormat": "DD. MM. YYYY HH:mm", 5 | "details": "podrobnosti", 6 | "download": "prenesi", 7 | "empty": "prazno", 8 | "files": "datoteke", 9 | "filter": "filter", 10 | "folders": "mape", 11 | "grid": "mreža", 12 | "icons": "ikone", 13 | "lastModified": "Zadnja sprememba", 14 | "name": "Ime", 15 | "noMatch": "ni zadetkov", 16 | "parentDirectory": "Nadrejena mapa", 17 | "size": "Velikost" 18 | } 19 | -------------------------------------------------------------------------------- /config/_h5ai/private/conf/l10n/bg.json: -------------------------------------------------------------------------------- 1 | { 2 | "lang": "български", 3 | 4 | "dateFormat": "DD-MM-YYYY HH:mm", 5 | "details": "детайли", 6 | "download": "изтегляне", 7 | "empty": "празна", 8 | "files": "файлове", 9 | "filter": "филтър", 10 | "folders": "директории", 11 | "grid": "мрежа", 12 | "icons": "икони", 13 | "lastModified": "Последна промяна", 14 | "name": "Име", 15 | "noMatch": "няма съвпадение", 16 | "parentDirectory": "Предходна директория", 17 | "size": "Размер" 18 | } 19 | -------------------------------------------------------------------------------- /config/_h5ai/private/conf/l10n/uk.json: -------------------------------------------------------------------------------- 1 | { 2 | "lang": "українська", 3 | 4 | "dateFormat": "YYYY-MM-DD HH:mm", 5 | "details": "Деталі", 6 | "download": "Завантажити", 7 | "empty": "Порожньо", 8 | "files": "Файли(ів)", 9 | "filter": "Фільтр", 10 | "folders": "Тек(и)", 11 | "grid": "Гратка", 12 | "icons": "Піктограми", 13 | "lastModified": "Останні зміни", 14 | "name": "Ім'я", 15 | "noMatch": "Немає співпадінь", 16 | "parentDirectory": "Головна тека", 17 | "size": "Розмір" 18 | } 19 | -------------------------------------------------------------------------------- /config/_h5ai/private/conf/l10n/cs.json: -------------------------------------------------------------------------------- 1 | { 2 | "lang": "čeština", 3 | 4 | "dateFormat": "DD.MM.YYYY HH:mm", 5 | "details": "Podrobnosti", 6 | "download": "Stáhnout", 7 | "empty": "Prázdná složka", 8 | "files": "souborů", 9 | "filter": "Filtr", 10 | "folders": "složek", 11 | "grid": "Seznam", 12 | "icons": "Velké ikony", 13 | "lastModified": "Datum změny", 14 | "name": "Název", 15 | "noMatch": "Žádná shoda", 16 | "parentDirectory": "Nadřazený adresář", 17 | "size": "Velikost" 18 | } 19 | -------------------------------------------------------------------------------- /config/_h5ai/private/conf/l10n/el.json: -------------------------------------------------------------------------------- 1 | { 2 | "lang": "ελληνικά", 3 | 4 | "dateFormat": "DD/MM/YYYY HH:mm", 5 | "details": "λεπτομέρειες", 6 | "download": "μεταμόρφωση", 7 | "empty": "κενό", 8 | "files": "αρχεία", 9 | "filter": "φίλτρο", 10 | "folders": "φάκελοι", 11 | "grid": "πλέγμα", 12 | "icons": "εικονίδια", 13 | "lastModified": "Τελευταία τροποποίηση", 14 | "name": "Όνομα", 15 | "noMatch": "κανένα αποτέλεσμα", 16 | "parentDirectory": "Προηγούμενος Κατάλογος", 17 | "size": "Μέγεθος" 18 | } 19 | -------------------------------------------------------------------------------- /config/_h5ai/private/conf/l10n/ko.json: -------------------------------------------------------------------------------- 1 | { 2 | "lang": "한국어", 3 | 4 | "dateFormat": "YYYY-MM-DD HH:mm", 5 | "details": "자세히", 6 | "download": "다운로드", 7 | "empty": "빈 폴더", 8 | "files": "파일", 9 | "filter": "필터", 10 | "folders": "폴더", 11 | "grid": "그리드", 12 | "icons": "아이콘", 13 | "language": "언어", 14 | "lastModified": "최근 수정일", 15 | "name": "파일명", 16 | "noMatch": "해당파일이 없습니다.", 17 | "parentDirectory": "상위폴더", 18 | "search": "검색", 19 | "size": "크기", 20 | "tree": "트리", 21 | "view": "보기" 22 | } 23 | -------------------------------------------------------------------------------- /config/_h5ai/private/conf/l10n/ru.json: -------------------------------------------------------------------------------- 1 | { 2 | "lang": "русский", 3 | 4 | "dateFormat": "YYYY-MM-DD HH:mm", 5 | "details": "Детали", 6 | "download": "Скачать", 7 | "empty": "Пусто", 8 | "files": "Файлы", 9 | "filter": "Фильтр", 10 | "folders": "Папки", 11 | "grid": "Сетка", 12 | "icons": "Иконки", 13 | "language": "Язык", 14 | "lastModified": "Последние изменения", 15 | "name": "Имя", 16 | "noMatch": "Нет совпадений", 17 | "parentDirectory": "Главная директория", 18 | "size": "Размер", 19 | "view": "Вид" 20 | } 21 | -------------------------------------------------------------------------------- /config/_h5ai/private/conf/l10n/zh-cn.json: -------------------------------------------------------------------------------- 1 | { 2 | "lang": "简体中文", 3 | 4 | "dateFormat": "YYYY-MM-DD HH:mm", 5 | "details": "详情", 6 | "download": "下载", 7 | "empty": "空文件夹", 8 | "files": "文件", 9 | "filter": "过滤", 10 | "folders": "文件夹", 11 | "grid": "网格", 12 | "icons": "图标", 13 | "language": "语言", 14 | "lastModified": "修改时间", 15 | "name": "文件名", 16 | "noMatch": "无匹配项", 17 | "parentDirectory": "父文件夹", 18 | "search": "搜索", 19 | "size": "大小", 20 | "tree": "树形目录", 21 | "view": "视图", 22 | "info": "信息" 23 | } 24 | -------------------------------------------------------------------------------- /config/_h5ai/private/conf/l10n/zh-tw.json: -------------------------------------------------------------------------------- 1 | { 2 | "lang": "正體中文", 3 | 4 | "dateFormat": "YYYY-MM-DD HH:mm", 5 | "details": "詳細資料", 6 | "download": "下載", 7 | "empty": "空資料夾", 8 | "files": "檔案", 9 | "filter": "過濾", 10 | "folders": "資料夾", 11 | "grid": "網格", 12 | "icons": "圖示", 13 | "language": "語言", 14 | "lastModified": "上次修改", 15 | "name": "檔名", 16 | "noMatch": "沒有符合的檔案", 17 | "parentDirectory": "上層目錄", 18 | "search": "搜尋", 19 | "size": "大小", 20 | "tree": "樹形目錄", 21 | "view": "檢視", 22 | "info": "資訊" 23 | } 24 | -------------------------------------------------------------------------------- /config/_h5ai/private/php/core/class-session.php: -------------------------------------------------------------------------------- 1 | store = &$store; 9 | } 10 | 11 | public function set($key, $value) { 12 | $key = Session::$KEY_PREFIX . $key; 13 | $this->store[$key] = $value; 14 | } 15 | 16 | public function get($key, $default = null) { 17 | $key = Session::$KEY_PREFIX . $key; 18 | return array_key_exists($key, $this->store) ? $this->store[$key] : $default; 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /config/_h5ai/private/conf/l10n/et.json: -------------------------------------------------------------------------------- 1 | { 2 | "lang": "estonian", 3 | 4 | "dateFormat": "DD-MM-YYYY HH.mm", 5 | "details": "täpsem info", 6 | "download": "laadi alla", 7 | "empty": "tühi", 8 | "files": "failid", 9 | "filter": "filter", 10 | "folders": "kataloogid", 11 | "grid": "võre", 12 | "icons": "ikoonid", 13 | "language": "Keel", 14 | "lastModified": "Viimati muudetud", 15 | "name": "Nimi", 16 | "noMatch": "ei leitud sobivat", 17 | "parentDirectory": "Emakataloog", 18 | "search": "otsi", 19 | "size": "Suurus", 20 | "tree": "Puu", 21 | "view": "Vaade" 22 | } 23 | -------------------------------------------------------------------------------- /config/_h5ai/private/conf/l10n/id.json: -------------------------------------------------------------------------------- 1 | { 2 | "lang": "Bahasa Indonesia", 3 | 4 | "dateFormat": "DD-MM-YYYY HH:mm", 5 | "details": "rincian", 6 | "download": "unduh", 7 | "empty": "kosong", 8 | "files": "berkas", 9 | "filter": "saring", 10 | "folders": "pelipat", 11 | "grid": "jaring", 12 | "icons": "ikon", 13 | "language": "Bahasa", 14 | "lastModified": "Di modifikasi", 15 | "name": "Nama", 16 | "noMatch": "tidak cocok", 17 | "parentDirectory": "Direktori induk", 18 | "search": "cari", 19 | "size": "Ukuran", 20 | "tree": "Pohon", 21 | "view": "Tampil" 22 | } 23 | -------------------------------------------------------------------------------- /config/_h5ai/private/conf/l10n/de.json: -------------------------------------------------------------------------------- 1 | { 2 | "lang": "deutsch", 3 | 4 | "dateFormat": "DD.MM.YYYY HH:mm", 5 | "details": "Details", 6 | "download": "Download", 7 | "empty": "leer", 8 | "files": "Dateien", 9 | "filter": "filtern", 10 | "folders": "Ordner", 11 | "grid": "Gitter", 12 | "icons": "Icons", 13 | "language": "Sprache", 14 | "lastModified": "Geändert", 15 | "name": "Name", 16 | "noMatch": "keine Treffer", 17 | "parentDirectory": "Übergeordnetes Verzeichnis", 18 | "search": "suchen", 19 | "size": "Größe", 20 | "tree": "Baum", 21 | "view": "Ansicht" 22 | } 23 | -------------------------------------------------------------------------------- /config/_h5ai/private/conf/l10n/it.json: -------------------------------------------------------------------------------- 1 | { 2 | "lang": "italiano", 3 | 4 | "dateFormat": "DD-MM-YYYY HH:mm", 5 | "details": "dettagli", 6 | "download": "download", 7 | "empty": "vuota", 8 | "files": "file", 9 | "filter": "filtra", 10 | "folders": "cartelle", 11 | "grid": "griglia", 12 | "icons": "icone", 13 | "language": "Linugua", 14 | "lastModified": "Ultima modifica", 15 | "name": "Nome", 16 | "noMatch": "nessun risultato", 17 | "parentDirectory": "Cartella Superiore", 18 | "search": "cerca", 19 | "size": "Dimensione", 20 | "tree": "Albero", 21 | "view": "Vista" 22 | } 23 | -------------------------------------------------------------------------------- /config/_h5ai/private/conf/l10n/nl.json: -------------------------------------------------------------------------------- 1 | { 2 | "lang": "nederlands", 3 | 4 | "dateFormat": "YYYY-MM-DD HH:mm", 5 | "details": "details", 6 | "download": "download", 7 | "empty": "leeg", 8 | "files": "bestanden", 9 | "filter": "filter", 10 | "folders": "mappen", 11 | "grid": "grid", 12 | "icons": "iconen", 13 | "language": "Taal", 14 | "lastModified": "Laatste wijziging", 15 | "name": "Naam", 16 | "noMatch": "geen overeenkomst", 17 | "parentDirectory": "Bovenliggende map", 18 | "search": "zoeken", 19 | "size": "Grootte", 20 | "tree": "Boom", 21 | "view": "Bekijk" 22 | } 23 | -------------------------------------------------------------------------------- /config/_h5ai/private/conf/l10n/pl.json: -------------------------------------------------------------------------------- 1 | { 2 | "lang": "polski", 3 | 4 | "dateFormat": "YYYY-MM-DD HH:mm", 5 | "details": "szczegóły", 6 | "download": "pobierz", 7 | "empty": "pusty", 8 | "files": "plików", 9 | "filter": "filtr", 10 | "folders": "folderów", 11 | "grid": "kafelki", 12 | "icons": "ikony", 13 | "language": "Język", 14 | "lastModified": "Ostatnia modyfikacja", 15 | "name": "Nazwa", 16 | "noMatch": "nie znaleziono", 17 | "parentDirectory": "Katalog nadrzędny", 18 | "search": "szukaj", 19 | "size": "Rozmiar", 20 | "tree": "Drzewo", 21 | "view": "Układ" 22 | } 23 | -------------------------------------------------------------------------------- /config/_h5ai/private/conf/l10n/lv.json: -------------------------------------------------------------------------------- 1 | { 2 | "lang": "latviešu", 3 | 4 | "dateFormat": "YYYY-MM-DD HH:mm", 5 | "details": "detaļas", 6 | "download": "lejupielādēt", 7 | "empty": "tukšs", 8 | "files": "faili", 9 | "filter": "filtrēt", 10 | "folders": "mapes", 11 | "grid": "režģis", 12 | "icons": "ikonas", 13 | "language": "Valoda", 14 | "lastModified": "Pēdējoreiz modificēts", 15 | "name": "Nosaukums", 16 | "noMatch": "nav sakritības", 17 | "parentDirectory": "Vecākdirektorijs", 18 | "search": "meklēt", 19 | "size": "Izmērs", 20 | "tree": "Koks", 21 | "view": "Skats" 22 | } 23 | -------------------------------------------------------------------------------- /config/_h5ai/private/conf/l10n/es.json: -------------------------------------------------------------------------------- 1 | { 2 | "lang": "español", 3 | 4 | "dateFormat": "DD/MM/YYYY HH:mm", 5 | "details": "Detalles", 6 | "download": "Descargar", 7 | "empty": "vacío", 8 | "files": "Archivos", 9 | "filter": "Filtrar", 10 | "folders": "Directorios", 11 | "grid": "Cuadrícula", 12 | "icons": "Íconos", 13 | "language": "Idioma", 14 | "lastModified": "Última modificación", 15 | "name": "Nombre", 16 | "noMatch": "Sin coincidencias", 17 | "parentDirectory": "Directorio superior", 18 | "search": "buscar", 19 | "size": "Tamaño", 20 | "tree": "Arbol", 21 | "view": "Vista" 22 | } 23 | -------------------------------------------------------------------------------- /config/_h5ai/private/conf/l10n/fr.json: -------------------------------------------------------------------------------- 1 | { 2 | "lang": "français", 3 | 4 | "dateFormat": "DD/MM/YYYY HH:mm", 5 | "details": "détails", 6 | "download": "télécharger", 7 | "empty": "vide", 8 | "files": "Fichiers", 9 | "filter": "filtrer", 10 | "folders": "Répertoires", 11 | "grid": "grille", 12 | "icons": "icônes", 13 | "language": "Langue", 14 | "lastModified": "Dernière modification", 15 | "name": "Nom", 16 | "noMatch": "rien trouvé", 17 | "parentDirectory": "Dossier parent", 18 | "search": "rechercher", 19 | "size": "Taille", 20 | "tree": "Arborescence", 21 | "view": "Disposition" 22 | } 23 | -------------------------------------------------------------------------------- /config/_h5ai/private/conf/l10n/pt-br.json: -------------------------------------------------------------------------------- 1 | { 2 | "lang": "português do Brasil", 3 | 4 | "dateFormat": "DD-MM-YYYY HH:mm", 5 | "details": "detalhes", 6 | "download": "download", 7 | "empty": "vazio", 8 | "files": "arquivos", 9 | "filter": "filtro", 10 | "folders": "pastas", 11 | "grid": "grade", 12 | "icons": "ícones", 13 | "language": "Idioma", 14 | "lastModified": "Última modificação", 15 | "name": "Nome", 16 | "noMatch": "sem resultados", 17 | "parentDirectory": "Diretório acima", 18 | "search": "pesquisa", 19 | "size": "Tamanho", 20 | "tree": "Árvore", 21 | "view": "Visualização" 22 | } 23 | -------------------------------------------------------------------------------- /config/_h5ai/private/conf/l10n/pt-pt.json: -------------------------------------------------------------------------------- 1 | { 2 | "lang": "português de Portugal", 3 | 4 | "dateFormat": "DD-MM-YYYY HH:mm", 5 | "details": "detalhes", 6 | "download": "descarregar", 7 | "empty": "vazio", 8 | "files": "arquivos", 9 | "filter": "filtro", 10 | "folders": "pastas", 11 | "grid": "grelha", 12 | "icons": "ícones", 13 | "language": "Idioma", 14 | "lastModified": "última modificação", 15 | "name": "Nome", 16 | "noMatch": "sem resultados", 17 | "parentDirectory": "Diretório acima", 18 | "search": "pesquisa", 19 | "size": "Tamanho", 20 | "tree": "Árvore", 21 | "view": "Visualização" 22 | } 23 | -------------------------------------------------------------------------------- /config/_h5ai/public/images/themes/comity/txt-rb.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /config/_h5ai/public/index.php: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /config/_h5ai/private/conf/l10n/en.json: -------------------------------------------------------------------------------- 1 | /* only here as a reference, these values are the hardcoded defaults */ 2 | { 3 | "lang": "english", 4 | 5 | "dateFormat": "YYYY-MM-DD HH:mm", 6 | "details": "details", 7 | "download": "download", 8 | "empty": "empty", 9 | "files": "files", 10 | "filter": "filter", 11 | "folders": "folders", 12 | "grid": "grid", 13 | "icons": "icons", 14 | "language": "Language", 15 | "lastModified": "Last modified", 16 | "name": "Name", 17 | "noMatch": "no match", 18 | "parentDirectory": "Parent Directory", 19 | "search": "search", 20 | "size": "Size", 21 | "tree": "Tree", 22 | "view": "View" 23 | } 24 | -------------------------------------------------------------------------------- /config/_h5ai/public/images/themes/default/bin.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /config/_h5ai/public/images/themes/comity/txt-script.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /config/_h5ai/private/php/core/class-logger.php: -------------------------------------------------------------------------------- 1 | context = $context; 9 | } 10 | 11 | public function get_icons() { 12 | $public_path = $this->context->get_setup()->get('PUBLIC_PATH'); 13 | $theme = $this->context->query_option('view.theme', '-NONE-'); 14 | $theme_path = $public_path . '/images/themes/' . $theme; 15 | 16 | $icons = []; 17 | 18 | if (is_dir($theme_path)) { 19 | if ($dir = opendir($theme_path)) { 20 | while (($name = readdir($dir)) !== false) { 21 | $path_parts = pathinfo($name); 22 | if (in_array(@$path_parts['extension'], Theme::$EXTENSIONS)) { 23 | $icons[$path_parts['filename']] = $theme . '/' . $name; 24 | } 25 | } 26 | closedir($dir); 27 | } 28 | } 29 | 30 | return $icons; 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /config/_h5ai/public/images/themes/comity/txt-php.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /config/_h5ai/public/images/themes/comity/txt-html.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /config/_h5ai/public/images/themes/comity/txt-css.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /config/_h5ai/private/php/pages/info.php: -------------------------------------------------------------------------------- 1 | h5ai info page - v0.30.0 2 |
Works best with JavaScript enabled!Works best in modern browsers!powered by h5ai
-------------------------------------------------------------------------------- /config/_h5ai/private/php/pages/index.php: -------------------------------------------------------------------------------- 1 | index - powered by h5ai v0.30.0 (https://larsjung.de/h5ai/) 2 |
Works best with JavaScript enabled!Works best in modern browsers!powered by h5ai
-------------------------------------------------------------------------------- /config/_h5ai/private/php/ext/class-search.php: -------------------------------------------------------------------------------- 1 | context = $context; 8 | } 9 | 10 | public function get_paths($root, $pattern = null, $ignorecase = false) { 11 | $paths = []; 12 | if ($pattern && $this->context->is_managed_path($root)) { 13 | $re = Util::wrap_pattern($pattern); 14 | if ($ignorecase) { 15 | $re .= 'i'; 16 | } 17 | $names = $this->context->read_dir($root); 18 | foreach ($names as $name) { 19 | $path = $root . '/' . $name; 20 | if (preg_match($re, @basename($path))) { 21 | $paths[] = $path; 22 | } 23 | if (@is_dir($path)) { 24 | $paths = array_merge($paths, $this->get_paths($path, $pattern, $ignorecase)); 25 | } 26 | } 27 | } 28 | return $paths; 29 | } 30 | 31 | public function get_items($href, $pattern = null, $ignorecase = false) { 32 | $cache = []; 33 | $root = $this->context->to_path($href); 34 | $paths = $this->get_paths($root, $pattern, $ignorecase); 35 | $items = array_map(function ($path) { 36 | return Item::get($this->context, $path, $cache)->to_json_object(); 37 | }, $paths); 38 | return $items; 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /config/_h5ai/private/php/core/class-request.php: -------------------------------------------------------------------------------- 1 | params = $data !== null ? $data : $params; 9 | } 10 | 11 | public function query($keypath = '', $default = Util::NO_DEFAULT) { 12 | $value = Util::array_query($this->params, $keypath, Util::NO_DEFAULT); 13 | 14 | if ($value === Util::NO_DEFAULT) { 15 | Util::json_fail(Util::ERR_MISSING_PARAM, 'parameter \'' . $keypath . '\' is missing', $default === Util::NO_DEFAULT); 16 | return $default; 17 | } 18 | 19 | return $value; 20 | } 21 | 22 | public function query_boolean($keypath = '', $default = Util::NO_DEFAULT) { 23 | $value = $this->query($keypath, $default); 24 | return filter_var($value, FILTER_VALIDATE_BOOLEAN); 25 | } 26 | 27 | public function query_numeric($keypath = '', $default = Util::NO_DEFAULT) { 28 | $value = $this->query($keypath, $default); 29 | Util::json_fail(Util::ERR_ILLIGAL_PARAM, 'parameter \'' . $keypath . '\' is not numeric', !is_numeric($value)); 30 | return intval($value, 10); 31 | } 32 | 33 | public function query_array($keypath = '', $default = Util::NO_DEFAULT) { 34 | $value = $this->query($keypath, $default); 35 | Util::json_fail(Util::ERR_ILLIGAL_PARAM, 'parameter \'' . $keypath . '\' is no array', !is_array($value)); 36 | return $value; 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM nginx:1.27-alpine3.19 2 | LABEL maintainer="Deokgyu Yang " \ 3 | description="Lightweight h5ai 0.30.0 container with Nginx 1.27 & PHP 8.2 based on Alpine Linux." 4 | 5 | RUN apk update 6 | RUN apk add --no-cache \ 7 | bash bash-completion supervisor tzdata shadow \ 8 | php82 php82-fpm php82-session php82-json php82-xml php82-mbstring php82-exif \ 9 | php82-intl php82-gd php82-pecl-imagick php82-zip php82-opcache \ 10 | ffmpeg imagemagick zip apache2-utils patch 11 | 12 | # Environments 13 | ENV PUID=911 14 | ENV PGID=911 15 | ENV TZ='Asia/Seoul' 16 | ENV HTPASSWD='false' 17 | ENV HTPASSWD_USER='guest' 18 | ENV HTPASSWD_PW='' 19 | 20 | # Copy configuration files 21 | COPY config/h5ai.conf /etc/nginx/conf.d/h5ai.conf 22 | COPY config/php_set_timezone.ini /etc/php82/conf.d/00_timezone.ini 23 | COPY config/php_set_jit.ini /etc/php82/conf.d/00_jit.ini 24 | COPY config/php_set_memory_limit.ini /etc/php82/conf.d/00_memlimit.ini 25 | COPY config/supervisord.conf /etc/supervisor/conf.d/supervisord.conf 26 | 27 | # Copy h5ai 28 | COPY config/_h5ai /usr/share/h5ai/_h5ai 29 | 30 | # Configure Nginx server 31 | RUN sed --in-place=.bak 's/worker_processes 1/worker_processes auto/g' /etc/nginx/nginx.conf 32 | RUN mv /etc/nginx/conf.d/default.conf /etc/nginx/conf.d/default.conf.bak 33 | 34 | # Add shell script, patch files 35 | ADD config/init.sh / 36 | ADD config/h5ai.conf.htpasswd.patch / 37 | # Set entry point file permission 38 | RUN chmod a+x /init.sh 39 | 40 | EXPOSE 80 41 | VOLUME [ "/config", "/h5ai" ] 42 | ENTRYPOINT [ "/init.sh" ] 43 | -------------------------------------------------------------------------------- /config/_h5ai/public/images/themes/comity/txt-py.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /config/_h5ai/private/php/class-bootstrap.php: -------------------------------------------------------------------------------- 1 | query_boolean('refresh', false)); 16 | $context = new Context($session, $request, $setup); 17 | 18 | if ($context->is_api_request()) { 19 | (new Api($context))->apply(); 20 | } elseif ($context->is_info_request()) { 21 | $public_href = $setup->get('PUBLIC_HREF'); 22 | $x_head_tags = $context->get_x_head_html(); 23 | $fallback_mode = false; 24 | require __DIR__ . '/pages/info.php'; 25 | } else { 26 | $public_href = $setup->get('PUBLIC_HREF'); 27 | $x_head_tags = $context->get_x_head_html(); 28 | $fallback_mode = $context->is_fallback_mode(); 29 | $fallback_html = (new Fallback($context))->get_html(); 30 | require __DIR__ . '/pages/index.php'; 31 | } 32 | } 33 | 34 | public static function autoload($class_name) { 35 | $filename = 'class-' . strtolower($class_name) . '.php'; 36 | 37 | foreach (Bootstrap::$autopaths as $path) { 38 | $file = __DIR__ . '/' . $path . '/' . $filename; 39 | if (file_exists($file)) { 40 | require_once $file; 41 | return true; 42 | } 43 | } 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /config/h5ai.conf: -------------------------------------------------------------------------------- 1 | server { 2 | listen 80 default_server; 3 | listen [::]:80 default_server; 4 | server_name _; 5 | 6 | root /h5ai; 7 | index index.html index.htm index.php /_h5ai/public/index.php; 8 | 9 | # h5ai 10 | location /_h5ai/ { 11 | root /usr/share/h5ai/; 12 | 13 | # pass the index.php to FastCGI server listening on 127.0.0.1:9000 14 | location ~ [^/]\.php(/|$) { 15 | fastcgi_split_path_info ^(.+?\.php)(/.*)$; 16 | 17 | fastcgi_pass 127.0.0.1:9000; 18 | fastcgi_index index.php; 19 | fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; 20 | fastcgi_param SCRIPT_NAME $fastcgi_script_name; 21 | fastcgi_param HTTP_PROXY ""; 22 | include fastcgi_params; 23 | } 24 | } 25 | 26 | # redirect server error pages to the static page /50x.html 27 | error_page 500 502 503 504 /50x.html; 28 | location = /50x.html { 29 | root /usr/share/nginx/html; 30 | } 31 | 32 | # pass the PHP scripts to FastCGI server listening on 127.0.0.1:9000 33 | # Remain this for compatibility of PHP sub pages 34 | location ~ [^/]\.php(/|$) { 35 | fastcgi_split_path_info ^(.+?\.php)(/.*)$; 36 | 37 | fastcgi_pass 127.0.0.1:9000; 38 | fastcgi_index index.php; 39 | fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; 40 | fastcgi_param SCRIPT_NAME $fastcgi_script_name; 41 | fastcgi_param HTTP_PROXY ""; 42 | include fastcgi_params; 43 | } 44 | 45 | # deny access to .htaccess files, if Apache's document root 46 | # concurs with nginx's one 47 | location ~ /\.ht { 48 | deny all; 49 | } 50 | 51 | # For letsencrypt 52 | location /.well-known/acme-challenge/ { 53 | alias /var/www/challenges/; 54 | try_files $uri =404; 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /config/_h5ai/private/php/core/class-fallback.php: -------------------------------------------------------------------------------- 1 | context = $context; 8 | } 9 | 10 | public function get_html($path = null) { 11 | if (!$path) { 12 | $path = $this->context->get_current_path(); 13 | } 14 | $fallback_images_href = $this->context->get_setup()->get('PUBLIC_HREF') . 'images/fallback/'; 15 | 16 | $cache = []; 17 | $folder = Item::get($this->context, $path, $cache); 18 | $items = $folder->get_content($cache); 19 | uasort($items, ['Item', 'cmp']); 20 | 21 | $html = ''; 22 | 23 | $html .= ''; 24 | $html .= ''; 25 | $html .= ''; 26 | $html .= ''; 27 | $html .= ''; 28 | $html .= ''; 29 | 30 | if ($folder->get_parent($cache)) { 31 | $html .= ''; 32 | $html .= ''; 33 | $html .= ''; 34 | $html .= ''; 35 | $html .= ''; 36 | $html .= ''; 37 | } 38 | 39 | foreach ($items as $item) { 40 | $type = $item->is_folder ? 'folder' : 'file'; 41 | 42 | $html .= ''; 43 | $html .= ''; 44 | $html .= ''; 45 | $html .= ''; 46 | $html .= ''; 47 | $html .= ''; 48 | } 49 | 50 | $html .= '
NameLast modifiedSize
folder-parentParent Directory
' . $type . '' . basename($item->path) . '' . date('Y-m-d H:i', $item->date) . '' . ($item->size !== null ? intval($item->size / 1000) . ' KB' : '' ) . '
'; 51 | 52 | return $html; 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018-2024 Deokgyu Yang 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | 23 | The MIT License (MIT) 24 | 25 | Copyright (c) 2016 Lars Jung (https://larsjung.de) 26 | 27 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 28 | 29 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 30 | 31 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 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. 32 | -------------------------------------------------------------------------------- /config/_h5ai/private/php/core/class-json.php: -------------------------------------------------------------------------------- 1 | context = $context; 9 | } 10 | 11 | private function read_custom_file($path, $name, &$content, &$type) { 12 | $file_prefix = $this->context->get_setup()->get('FILE_PREFIX'); 13 | 14 | foreach (Custom::$EXTENSIONS as $ext) { 15 | $file = $path . '/' . $file_prefix . '.' . $name . '.' . $ext; 16 | if (is_readable($file)) { 17 | $content = file_get_contents($file); 18 | $type = $ext; 19 | return; 20 | } 21 | } 22 | } 23 | 24 | public function get_customizations($href) { 25 | if (!$this->context->query_option('custom.enabled', false)) { 26 | return [ 27 | 'header' => ['content' => null, 'type' => null], 28 | 'footer' => ['content' => null, 'type' => null] 29 | ]; 30 | } 31 | 32 | $root_path = $this->context->get_setup()->get('FILE_PREFIX'); 33 | $path = $this->context->to_path($href); 34 | 35 | $header = null; 36 | $header_type = null; 37 | $footer = null; 38 | $footer_type = null; 39 | 40 | $this->read_custom_file($path, 'header', $header, $header_type); 41 | $this->read_custom_file($path, 'footer', $footer, $footer_type); 42 | 43 | while ($header === null || $footer === null) { 44 | if ($header === null) { 45 | $this->read_custom_file($path, 'headers', $header, $header_type); 46 | } 47 | if ($footer === null) { 48 | $this->read_custom_file($path, 'footers', $footer, $footer_type); 49 | } 50 | if ($path === $root_path) { 51 | break; 52 | } 53 | $parent_path = Util::normalize_path(dirname($path)); 54 | if ($parent_path === $path) { 55 | break; 56 | } 57 | 58 | // Stop once we reach the root 59 | if ( 60 | $this->context->query_option('custom.stopSearchingAtRoot', true) && 61 | $path === $this->context->get_setup()->get('ROOT_PATH') 62 | ) { 63 | break; 64 | } 65 | $path = $parent_path; 66 | } 67 | 68 | return [ 69 | 'header' => ['content' => $header, 'type' => $header_type], 70 | 'footer' => ['content' => $footer, 'type' => $footer_type] 71 | ]; 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /config/_h5ai/public/images/themes/comity/txt-js.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /config/_h5ai/public/images/themes/comity/x-pdf.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /config/_h5ai/private/php/core/class-filesize.php: -------------------------------------------------------------------------------- 1 | size($path, $withFoldersize, $withDu); 9 | } 10 | 11 | public static function getCachedSize($path, $withFoldersize, $withDu) { 12 | if (array_key_exists($path, Filesize::$cache)) { 13 | return Filesize::$cache[$path]; 14 | } 15 | 16 | $size = Filesize::getSize($path, $withFoldersize, $withDu); 17 | 18 | Filesize::$cache[$path] = $size; 19 | return $size; 20 | } 21 | 22 | 23 | private function __construct() {} 24 | 25 | private function read_dir($path) { 26 | $paths = []; 27 | if (is_dir($path)) { 28 | foreach (scandir($path) as $name) { 29 | if ($name !== '.' && $name !== '..') { 30 | $paths[] = $path . '/' . $name; 31 | } 32 | } 33 | } 34 | return $paths; 35 | } 36 | 37 | private function php_filesize($path, $recursive = false) { 38 | // if (PHP_INT_SIZE < 8) { 39 | // } 40 | $size = @filesize($path); 41 | 42 | if (!is_dir($path) || !$recursive) { 43 | return $size; 44 | } 45 | 46 | foreach ($this->read_dir($path) as $p) { 47 | $size += $this->php_filesize($p, true); 48 | } 49 | return $size; 50 | } 51 | 52 | 53 | private function exec($cmdv) { 54 | $cmd = implode(' ', array_map('escapeshellarg', $cmdv)); 55 | $lines = []; 56 | $rc = null; 57 | exec($cmd, $lines, $rc); 58 | return $lines; 59 | } 60 | 61 | private function exec_du_all($paths) { 62 | $cmdv = array_merge(['du', '-sbL'], $paths); 63 | $lines = $this->exec($cmdv); 64 | 65 | $sizes = []; 66 | foreach ($lines as $line) { 67 | $parts = preg_split('/[\s]+/', $line, 2); 68 | $size = intval($parts[0], 10); 69 | $path = $parts[1]; 70 | $sizes[$path] = $size; 71 | } 72 | return $sizes; 73 | } 74 | 75 | private function exec_du($path) { 76 | $sizes = $this->exec_du_all([$path]); 77 | return $sizes[$path]; 78 | } 79 | 80 | 81 | private function size($path, $withFoldersize = false, $withDu = false) { 82 | if (is_file($path)) { 83 | return $this->php_filesize($path); 84 | } 85 | 86 | if (is_dir($path) && $withFoldersize) { 87 | if ($withDu) { 88 | return $this->exec_du($path); 89 | } 90 | 91 | return $this->php_filesize($path, true); 92 | } 93 | 94 | return null; 95 | } 96 | } 97 | -------------------------------------------------------------------------------- /config/_h5ai/private/php/core/class-item.php: -------------------------------------------------------------------------------- 1 | is_folder && !$item2->is_folder) { 6 | return -1; 7 | } 8 | if (!$item1->is_folder && $item2->is_folder) { 9 | return 1; 10 | } 11 | 12 | return strcasecmp($item1->path, $item2->path); 13 | } 14 | 15 | public static function get($context, $path, &$cache) { 16 | if (!Util::starts_with($path, $context->get_setup()->get('ROOT_PATH'))) { 17 | return null; 18 | } 19 | 20 | if (is_array($cache) && array_key_exists($path, $cache)) { 21 | return $cache[$path]; 22 | } 23 | 24 | $item = new Item($context, $path); 25 | 26 | if (is_array($cache)) { 27 | $cache[$path] = $item; 28 | } 29 | return $item; 30 | } 31 | 32 | public $context; 33 | public $path; 34 | public $href; 35 | public $date; 36 | public $size; 37 | public $is_folder; 38 | public $is_content_fetched; 39 | 40 | private function __construct($context, $path) { 41 | $this->context = $context; 42 | 43 | $this->path = Util::normalize_path($path, false); 44 | $this->is_folder = is_dir($this->path); 45 | $this->href = $context->to_href($this->path, $this->is_folder); 46 | $this->date = @filemtime($this->path); 47 | $this->size = Util::filesize($context, $this->path); 48 | $this->is_content_fetched = false; 49 | } 50 | 51 | public function to_json_object() { 52 | $obj = [ 53 | 'href' => $this->href, 54 | 'time' => $this->date * 1000, // seconds (PHP) to milliseconds (JavaScript) 55 | 'size' => $this->size 56 | ]; 57 | 58 | if ($this->is_folder) { 59 | $obj['managed'] = $this->context->is_managed_href($this->href); 60 | $obj['fetched'] = $this->is_content_fetched; 61 | } 62 | 63 | return $obj; 64 | } 65 | 66 | public function get_parent(&$cache) { 67 | $parent_path = Util::normalize_path(dirname($this->path), false); 68 | if ($parent_path !== $this->path && Util::starts_with($parent_path, $this->context->get_setup()->get('ROOT_PATH'))) { 69 | return Item::get($this->context, $parent_path, $cache); 70 | } 71 | return null; 72 | } 73 | 74 | public function get_content(&$cache) { 75 | $items = []; 76 | 77 | if (!$this->context->is_managed_href($this->href)) { 78 | return $items; 79 | } 80 | 81 | $files = $this->context->read_dir($this->path); 82 | foreach ($files as $file) { 83 | $item = Item::get($this->context, $this->path . '/' . $file, $cache); 84 | $items[$item->path] = $item; 85 | } 86 | 87 | $this->is_content_fetched = true; 88 | 89 | return $items; 90 | } 91 | } 92 | -------------------------------------------------------------------------------- /config/_h5ai/README.md: -------------------------------------------------------------------------------- 1 | # h5ai 2 | 3 | [![license][license-img]][github] [![web][web-img]][web] [![github][github-img]][github] 4 | 5 | A modern HTTP web server index for Apache httpd, lighttpd, and nginx. 6 | 7 | 8 | ## Important 9 | 10 | * Do **not** install any files from the `src` folder, they need to be 11 | preprocessed to work correctly! 12 | * Find a preprocessed package and detailed install instructions on the 13 | [project page][web]. 14 | * For bug reports and feature requests please use [issues][github-issues]. 15 | 16 | 17 | ## Build 18 | 19 | There are installation ready packages for the latest [releases][release] and 20 | [dev builds][develop]. But to build **h5ai** yourself either `git clone` or 21 | download the repository. From within the root folder run the following 22 | commands to find a fresh zipball in folder `build` (tested on linux only, 23 | requires [`node 10.0+`][node] to be installed, might work on other 24 | configurations). 25 | 26 | ~~~sh 27 | > npm install 28 | > npm run build 29 | ~~~ 30 | 31 | 32 | ## License 33 | 34 | The MIT License (MIT) 35 | 36 | Copyright (c) 2020 Lars Jung (https://larsjung.de) 37 | 38 | Permission is hereby granted, free of charge, to any person obtaining a copy 39 | of this software and associated documentation files (the "Software"), to deal 40 | in the Software without restriction, including without limitation the rights 41 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 42 | copies of the Software, and to permit persons to whom the Software is 43 | furnished to do so, subject to the following conditions: 44 | 45 | The above copyright notice and this permission notice shall be included in 46 | all copies or substantial portions of the Software. 47 | 48 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 49 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 50 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 51 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 52 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 53 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 54 | THE SOFTWARE. 55 | 56 | 57 | ## References 58 | 59 | **h5ai** profits from other projects, all of them licensed under the MIT license 60 | too. Exceptions are some [Material Design icons][material-design-icons] (CC BY 4.0). 61 | 62 | 63 | [web]: https://larsjung.de/h5ai/ 64 | [github]: https://github.com/lrsjng/h5ai 65 | [github-issues]: https://github.com/lrsjng/h5ai/issues 66 | [release]: https://release.larsjung.de/h5ai/ 67 | [develop]: https://release.larsjung.de/h5ai/develop/ 68 | [node]: https://nodejs.org 69 | [material-design-icons]: https://github.com/google/material-design-icons 70 | 71 | [license-img]: https://img.shields.io/badge/license-MIT-a0a060.svg?style=flat-square 72 | [web-img]: https://img.shields.io/badge/web-larsjung.de/h5ai-a0a060.svg?style=flat-square 73 | [github-img]: https://img.shields.io/badge/github-lrsjng/h5ai-a0a060.svg?style=flat-square 74 | -------------------------------------------------------------------------------- /config/_h5ai/private/php/core/class-util.php: -------------------------------------------------------------------------------- 1 | $err, 'msg' => $msg]); 26 | } 27 | } 28 | 29 | public static function array_query($array, $keypath = '', $default = Util::NO_DEFAULT) { 30 | $value = $array; 31 | 32 | $keys = array_filter(explode('.', $keypath)); 33 | foreach ($keys as $key) { 34 | if (!is_array($value) || !array_key_exists($key, $value)) { 35 | return $default; 36 | } 37 | $value = $value[$key]; 38 | } 39 | 40 | return $value; 41 | } 42 | 43 | public static function starts_with($sequence, $head) { 44 | return substr($sequence, 0, strlen($head)) === $head; 45 | } 46 | 47 | public static function ends_with($sequence, $tail) { 48 | $len = strlen($tail); 49 | return $len === 0 ? true : substr($sequence, -$len) === $tail; 50 | } 51 | 52 | public static function wrap_pattern($pattern) { 53 | return Util::RE_DELIMITER . str_replace(Util::RE_DELIMITER, '\\' . Util::RE_DELIMITER, $pattern) . Util::RE_DELIMITER; 54 | } 55 | 56 | public static function passthru_cmd($cmd) { 57 | $rc = null; 58 | passthru($cmd, $rc); 59 | return $rc; 60 | } 61 | 62 | public static function exec_cmdv($cmdv) { 63 | if (!is_array($cmdv)) { 64 | $cmdv = func_get_args(); 65 | } 66 | $cmd = implode(' ', array_map('escapeshellarg', $cmdv)); 67 | 68 | $lines = []; 69 | $rc = null; 70 | exec($cmd, $lines, $rc); 71 | return implode("\n", $lines); 72 | } 73 | 74 | public static function exec_0($cmd) { 75 | $lines = []; 76 | $rc = null; 77 | try { 78 | @exec($cmd, $lines, $rc); 79 | return $rc === 0; 80 | } catch (Exception $e) {} 81 | return false; 82 | } 83 | 84 | public static function filesize($context, $path) { 85 | $withFoldersize = $context->query_option('foldersize.enabled', false); 86 | $withDu = $context->get_setup()->get('HAS_CMD_DU') && $context->query_option('foldersize.type', null) === 'shell-du'; 87 | return Filesize::getCachedSize($path, $withFoldersize, $withDu); 88 | } 89 | } 90 | -------------------------------------------------------------------------------- /config/_h5ai/public/images/themes/comity/txt-less.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /config/_h5ai/private/conf/types.json: -------------------------------------------------------------------------------- 1 | /* h5ai v0.30.0 - https://larsjung.de/h5ai/ */ 2 | { 3 | "ar": ["*.tar.bz2", "*.crx"], 4 | "ar-apk": ["*.apk"], 5 | "ar-deb": ["*.deb"], 6 | "ar-gz": ["*.gz", "*.tar.gz", "*.tgz"], 7 | "ar-rar": ["*.rar"], 8 | "ar-rpm": ["*.rpm"], 9 | "ar-tar": ["*.tar"], 10 | "ar-zip": ["*.7z", "*.bz2", "*.jar", "*.lzma", "*.war", "*.z", "*.Z", "*.zip"], 11 | "aud": ["*.aif", "*.aiff", "*.flac", "*.m4a", "*.mid", "*.mp3", "*.mpa", "*.ra", "*.ogg", "*.wav", "*.wma"], 12 | "aud-pls": ["*.m3u", "*.m3u8", "*.pls"], 13 | "bin": ["*.class", "*.o", "*.so"], 14 | "bin-exe": ["*.bat", "*.cmd", "*.exe"], 15 | "img": ["*.xpm"], 16 | "img-bmp": ["*.bmp"], 17 | "img-gif": ["*.gif"], 18 | "img-ico": ["*.ico"], 19 | "img-jpg": ["*.jpg", "*.jpeg"], 20 | "img-png": ["*.png"], 21 | "img-raw": ["*.cr2", "*.nef"], 22 | "img-svg": ["*.svg"], 23 | "img-tiff": ["*.tiff"], 24 | "txt": ["*.text", "*.txt"], 25 | "txt-build": ["*.pom", "build.xml", "pom.xml"], 26 | "txt-c": ["*.c"], 27 | "txt-cpp": ["*.cpp"], 28 | "txt-css": ["*.css"], 29 | "txt-diff": ["*.diff", "*.patch"], 30 | "txt-go": ["*.go"], 31 | "txt-h": ["*.h"], 32 | "txt-html": ["*.htm", "*.html", "*.shtml", "*.xhtml"], 33 | "txt-hpp": ["*.hpp"], 34 | "txt-java": ["*.java"], 35 | "txt-scala": ["*.scala"], 36 | "txt-js": ["*.js"], 37 | "txt-json": ["*.json"], 38 | "txt-less": ["*.less"], 39 | "txt-log": ["*.log", "changelog*"], 40 | "txt-md": ["*.markdown", "*.md"], 41 | "txt-php": ["*.php"], 42 | "txt-py": ["*.py"], 43 | "txt-rb": ["*.rb"], 44 | "txt-rss": ["*.rss"], 45 | "txt-rtf": ["*.rtf"], 46 | "txt-rust": ["*.rs", "*.rlib"], 47 | "txt-script": ["*.conf", "*.bsh", "*.csh", "*.ini", "*.ksh", "*.sh", "*.shar", "*.tcl", "*.zsh"], 48 | "txt-source": [], 49 | "txt-tex": ["*.tex"], 50 | "txt-vcal": ["*.vcal"], 51 | "txt-xml": ["*.xml"], 52 | "vid": [], 53 | "vid-avi": ["*.avi"], 54 | "vid-flv": ["*.flv"], 55 | "vid-mkv": ["*.mkv"], 56 | "vid-mov": ["*.mov"], 57 | "vid-mp4": ["*.mp4", "*.m4v"], 58 | "vid-mpg": ["*.mpg"], 59 | "vid-rm": ["*.rm"], 60 | "vid-swf": ["*.swf"], 61 | "vid-ts": ["*.ts"], 62 | "vid-vob": ["*.vob"], 63 | "vid-webm": ["*.webm"], 64 | "vid-wmv": ["*.wmv"], 65 | "x": [], 66 | "x-bak": ["*.bak", "*~"], 67 | "x-calc": ["*.ods", "*.ots", "*.xlr", "*.xls", "*.xlsx"], 68 | "x-disc": ["*.cue", "*.iso"], 69 | "x-doc": ["*.doc", "*.docx", "*.odm", "*.odt", "*.ott"], 70 | "x-draw": ["*.drw"], 71 | "x-eps": ["*.eps"], 72 | "x-pdf": ["*.pdf"], 73 | "x-pres": ["*.odp", "*.otp", "*.pps", "*.ppt", "*.pptx"], 74 | "x-ps": ["*.ps"], 75 | "x-psd": ["*.psd"] 76 | } 77 | -------------------------------------------------------------------------------- /config/_h5ai/public/images/themes/comity/txt-rust.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /config/_h5ai/public/images/themes/comity/ar-rpm.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /config/init.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | msg() { 4 | echo -E "$1" 5 | } 6 | 7 | # Display environment variables 8 | echo -e "Variables: 9 | \\t- PUID=${PUID} 10 | \\t- PGID=${PGID} 11 | \\t- TZ=${TZ} 12 | \\t- HTPASSWD=${HTPASSWD} 13 | \\t- HTPASSWD_USER=${HTPASSWD_USER} 14 | \\t- HTPASSWD_PW=${HTPASSWD_PW}" 15 | 16 | if [ "$( grep -rni "$TZ" /etc/php82/conf.d/00_timezone.ini | wc -l )" -eq 0 ]; then 17 | msg "Configure timezone for PHP..." 18 | echo "$TZ\"" >> /etc/php82/conf.d/00_timezone.ini 19 | fi 20 | 21 | msg "Make config directories..." 22 | mkdir -p /config/{nginx,h5ai} 23 | 24 | msg "Add dummy user for better handle permission..." 25 | useradd -u 911 -U -d /config -s /bin/false abc && usermod -G users abc 26 | groupmod -o -g "$PGID" abc 27 | usermod -o -u "$PUID" abc 28 | 29 | # Locations of configuration files 30 | orig_nginx="/etc/nginx/conf.d/h5ai.conf" 31 | orig_h5ai="/usr/share/h5ai/_h5ai" 32 | conf_nginx="/config/nginx/h5ai.conf" 33 | conf_h5ai="/config/h5ai/_h5ai" 34 | conf_htpwd="/config/nginx/.htpasswd" 35 | options_file="/private/conf/options.json" 36 | 37 | msg "Check configuration files for Nginx..." 38 | if [ ! -f "$conf_nginx" ]; then 39 | msg "Copy original setup files to /config folder..." 40 | cp -arf $orig_nginx $conf_nginx 41 | else 42 | msg "User setup files found: $conf_nginx" 43 | msg "Remove image's default setup files and copy the previous version..." 44 | fi 45 | rm -f $orig_nginx 46 | ln -s $conf_nginx $orig_nginx 47 | 48 | msg "Check configuration files for h5ai..." 49 | if [ ! -d "$conf_h5ai" ]; then 50 | msg "Copy original setup files to /config folder..." 51 | cp -arf $orig_h5ai $conf_h5ai 52 | else 53 | msg "User setup files found: $conf_h5ai" 54 | 55 | msg "Check if h5ai version updated..." 56 | new_ver=$(head -n 1 $orig_h5ai$options_file | awk '{print $3}' | sed 's/[^0-9]//g') 57 | pre_ver=$(head -n 1 $conf_h5ai$options_file | awk '{print $3}' | sed 's/[^0-9]//g') 58 | if [ $new_ver -gt $pre_ver ]; then 59 | msg "New version detected. Make existing options.json backup file..." 60 | cp $conf_h5ai$options_file /config/$(date '+%Y%m%d_%H%M%S')_options.json.bak 61 | 62 | msg "Remove existing h5ai files..." 63 | rm -rf $conf_h5ai 64 | 65 | msg "Copy the new version..." 66 | cp -arf $orig_h5ai $conf_h5ai 67 | fi 68 | 69 | msg "Remove image's default setup files and copy the existing version..." 70 | fi 71 | rm -rf $orig_h5ai 72 | ln -s $conf_h5ai $orig_h5ai 73 | 74 | msg "Set permission for caching..." 75 | chmod -R 777 $conf_h5ai/public/cache 76 | chmod -R 777 $conf_h5ai/private/cache 77 | 78 | # If an user wants to set htpasswd 79 | if [ "$HTPASSWD" = "true" ]; then 80 | if [ ! -f "$conf_htpwd" ]; then 81 | msg "Create an authenticate account for h5ai website..." 82 | 83 | if [ -z "$HTPASSWD_PW" ]; then 84 | msg "Please enter a password for user $HTPASSWD_USER" 85 | 86 | # Create a new htpasswd file with user's entered password 87 | htpasswd -c "$conf_htpwd" "$HTPASSWD_USER" 88 | else 89 | # Create a new htpasswd file with environment variables 90 | htpasswd -b -c "$conf_htpwd" "$HTPASSWD_USER" "$HTPASSWD_PW" 91 | fi 92 | else 93 | msg "User setup files found: $conf_htpwd" 94 | fi 95 | 96 | # Patch Nginx server instance 97 | if [ "$( grep -rni "auth" /config/nginx/h5ai.conf | wc -l )" -eq 0 ]; then 98 | patch -p1 /config/nginx/h5ai.conf -i /h5ai.conf.htpasswd.patch 99 | fi 100 | else 101 | if [ "$( grep -rni "auth" /config/nginx/h5ai.conf | wc -l )" -gt 0 ]; then 102 | msg "HTPASSWD not configured but Nginx server sets. Reverse the patch..." 103 | patch -R -p1 /config/nginx/h5ai.conf -i /h5ai.conf.htpasswd.patch 104 | fi 105 | fi 106 | 107 | msg "Fix ownership for Nginx and php-fpm..." 108 | sed -i "s#user nginx;.*#user abc;#g" /etc/nginx/nginx.conf 109 | sed -i "s#user = nobody.*#user = abc#g" /etc/php82/php-fpm.d/www.conf 110 | sed -i "s#group = nobody.*#group = abc#g" /etc/php82/php-fpm.d/www.conf 111 | 112 | msg "Set ownership to the configuration files..." 113 | chown -R abc:abc /config 114 | 115 | msg "Start supervisord..." 116 | supervisord -c /etc/supervisor/conf.d/supervisord.conf 117 | -------------------------------------------------------------------------------- /config/_h5ai/public/images/ui/paypal.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /config/_h5ai/private/php/core/class-api.php: -------------------------------------------------------------------------------- 1 | context = $context; 10 | $this->request = $context->get_request(); 11 | $this->setup = $context->get_setup(); 12 | } 13 | 14 | public function apply() { 15 | $action = $this->request->query('action'); 16 | $supported = ['download', 'get', 'login', 'logout']; 17 | Util::json_fail(Util::ERR_UNSUPPORTED, 'unsupported action', !in_array($action, $supported)); 18 | 19 | $methodname = 'on_' . $action; 20 | $this->$methodname(); 21 | } 22 | 23 | private function on_download() { 24 | Util::json_fail(Util::ERR_DISABLED, 'download disabled', !$this->context->query_option('download.enabled', false)); 25 | 26 | $as = $this->request->query('as'); 27 | $type = $this->request->query('type'); 28 | $base_href = $this->request->query('baseHref'); 29 | $hrefs = $this->request->query('hrefs', ''); 30 | 31 | $archive = new Archive($this->context); 32 | 33 | set_time_limit(0); 34 | session_write_close(); 35 | header('Content-Type: application/octet-stream'); 36 | header('Content-Disposition: attachment; filename="' . $as . '"'); 37 | header('Connection: close'); 38 | $ok = $archive->output($type, $base_href, $hrefs); 39 | 40 | Util::json_fail(Util::ERR_FAILED, 'packaging failed', !$ok); 41 | exit; 42 | } 43 | 44 | private function on_get() { 45 | $response = []; 46 | 47 | foreach (['langs', 'options', 'types'] as $name) { 48 | if ($this->request->query_boolean($name, false)) { 49 | $methodname = 'get_' . $name; 50 | $response[$name] = $this->context->$methodname(); 51 | } 52 | } 53 | 54 | if ($this->request->query_boolean('setup', false)) { 55 | $response['setup'] = $this->setup->to_jsono($this->context->is_admin()); 56 | } 57 | 58 | if ($this->request->query_boolean('theme', false)) { 59 | $theme = new Theme($this->context); 60 | $response['theme'] = $theme->get_icons(); 61 | } 62 | 63 | if ($this->request->query('items', false)) { 64 | $href = $this->request->query('items.href'); 65 | $what = $this->request->query_numeric('items.what'); 66 | $response['items'] = $this->context->get_items($href, $what); 67 | } 68 | 69 | if ($this->request->query('custom', false)) { 70 | Util::json_fail(Util::ERR_DISABLED, 'custom disabled', !$this->context->query_option('custom.enabled', false)); 71 | $href = $this->request->query('custom'); 72 | $custom = new Custom($this->context); 73 | $response['custom'] = $custom->get_customizations($href); 74 | } 75 | 76 | if ($this->request->query('l10n', false)) { 77 | Util::json_fail(Util::ERR_DISABLED, 'l10n disabled', !$this->context->query_option('l10n.enabled', false)); 78 | $iso_codes = $this->request->query_array('l10n'); 79 | $iso_codes = array_filter($iso_codes); 80 | $response['l10n'] = $this->context->get_l10n($iso_codes); 81 | } 82 | 83 | if ($this->request->query('search', false)) { 84 | Util::json_fail(Util::ERR_DISABLED, 'search disabled', !$this->context->query_option('search.enabled', false)); 85 | $href = $this->request->query('search.href'); 86 | $pattern = $this->request->query('search.pattern'); 87 | $ignorecase = $this->request->query_boolean('search.ignorecase', false); 88 | $search = new Search($this->context); 89 | $response['search'] = $search->get_items($href, $pattern, $ignorecase); 90 | } 91 | 92 | if ($this->request->query('thumbs', false)) { 93 | Util::json_fail(Util::ERR_DISABLED, 'thumbnails disabled', !$this->context->query_option('thumbnails.enabled', false)); 94 | Util::json_fail(Util::ERR_UNSUPPORTED, 'thumbnails not supported', !$this->setup->get('HAS_PHP_JPEG')); 95 | $thumbs = $this->request->query_array('thumbs'); 96 | $response['thumbs'] = $this->context->get_thumbs($thumbs); 97 | } 98 | 99 | Util::json_exit($response); 100 | } 101 | 102 | private function on_login() { 103 | $pass = $this->request->query('pass'); 104 | Util::json_exit(['asAdmin' => $this->context->login_admin($pass)]); 105 | } 106 | 107 | private function on_logout() { 108 | Util::json_exit(['asAdmin' => $this->context->logout_admin()]); 109 | } 110 | } 111 | -------------------------------------------------------------------------------- /config/_h5ai/public/images/themes/comity/ar-deb.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /config/_h5ai/public/images/themes/comity/txt-go.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | -------------------------------------------------------------------------------- /config/_h5ai/private/php/ext/class-archive.php: -------------------------------------------------------------------------------- 1 | context = $context; 17 | } 18 | 19 | public function output($type, $base_href, $hrefs) { 20 | $this->base_path = $this->context->to_path($base_href); 21 | if (!$this->context->is_managed_path($this->base_path)) { 22 | return false; 23 | } 24 | 25 | $this->dirs = []; 26 | $this->files = []; 27 | 28 | $this->add_hrefs($hrefs); 29 | 30 | if (count($this->dirs) === 0 && count($this->files) === 0) { 31 | if ($type === 'php-tar') { 32 | $this->add_dir($this->base_path, '/'); 33 | } else { 34 | $this->add_dir($this->base_path, '.'); 35 | } 36 | } 37 | 38 | if ($type === 'php-tar') { 39 | return $this->php_tar($this->dirs, $this->files); 40 | } elseif ($type === 'shell-tar') { 41 | return $this->shell_cmd(Archive::$TAR_PASSTHRU_CMD); 42 | } elseif ($type === 'shell-zip') { 43 | return $this->shell_cmd(Archive::$ZIP_PASSTHRU_CMD); 44 | } 45 | return false; 46 | } 47 | 48 | private function shell_cmd($cmd) { 49 | $cmd = str_replace('[ROOTDIR]', escapeshellarg($this->base_path), $cmd); 50 | $cmd = str_replace('[DIRS]', count($this->dirs) ? implode(' ', array_map('escapeshellarg', $this->dirs)) : '', $cmd); 51 | $cmd = str_replace('[FILES]', count($this->files) ? implode(' ', array_map('escapeshellarg', $this->files)) : '', $cmd); 52 | try { 53 | Util::passthru_cmd($cmd); 54 | } catch (Exeption $err) { 55 | return false; 56 | } 57 | return true; 58 | } 59 | 60 | private function php_tar($dirs, $files) { 61 | $filesizes = []; 62 | $total_size = 512 * count($dirs); 63 | foreach (array_keys($files) as $real_file) { 64 | $size = filesize($real_file); 65 | 66 | $filesizes[$real_file] = $size; 67 | $total_size += 512 + $size; 68 | if ($size % 512 != 0) { 69 | $total_size += 512 - ($size % 512); 70 | } 71 | } 72 | 73 | header('Content-Length: ' . $total_size); 74 | 75 | foreach ($dirs as $real_dir => $archived_dir) { 76 | echo $this->php_tar_header($archived_dir, 0, @filemtime($real_dir . DIRECTORY_SEPARATOR . '.'), 5); 77 | } 78 | 79 | foreach ($files as $real_file => $archived_file) { 80 | $size = $filesizes[$real_file]; 81 | 82 | echo $this->php_tar_header($archived_file, $size, @filemtime($real_file), 0); 83 | $this->print_file($real_file); 84 | 85 | if ($size % 512 != 0) { 86 | echo str_repeat(Archive::NULL_BYTE, 512 - ($size % 512)); 87 | } 88 | } 89 | 90 | return true; 91 | } 92 | 93 | private function php_tar_header($filename, $size, $mtime, $type) { 94 | $name = substr(basename($filename), -99); 95 | $prefix = substr(Util::normalize_path(dirname($filename)), -154); 96 | if ($prefix === '.') { 97 | $prefix = ''; 98 | } 99 | 100 | $header = 101 | str_pad($name, 100, Archive::NULL_BYTE) // filename [100] 102 | . '0000755' . Archive::NULL_BYTE // file mode [8] 103 | . '0000000' . Archive::NULL_BYTE // uid [8] 104 | . '0000000' . Archive::NULL_BYTE // gid [8] 105 | . str_pad(decoct($size), 11, '0', STR_PAD_LEFT) . Archive::NULL_BYTE // file size [12] 106 | . str_pad(decoct($mtime), 11, '0', STR_PAD_LEFT) . Archive::NULL_BYTE // file modification time [12] 107 | . ' ' // checksum [8] 108 | . str_pad($type, 1) // file type [1] 109 | . str_repeat(Archive::NULL_BYTE, 100) // linkname [100] 110 | . 'ustar' . Archive::NULL_BYTE // magic [6] 111 | . '00' // version [2] 112 | . str_repeat(Archive::NULL_BYTE, 80) // uname, gname, defmajor, devminor [32 + 32 + 8 + 8] 113 | . str_pad($prefix, 155, Archive::NULL_BYTE) // filename [155] 114 | . str_repeat(Archive::NULL_BYTE, 12); // fill [12] 115 | assert(strlen($header) === 512); 116 | 117 | // checksum 118 | $checksum = array_sum(array_map('ord', str_split($header))); 119 | $checksum = str_pad(decoct($checksum), 6, '0', STR_PAD_LEFT) . Archive::NULL_BYTE . ' '; 120 | $header = substr_replace($header, $checksum, 148, 8); 121 | 122 | return $header; 123 | } 124 | 125 | private function print_file($file) { 126 | // Send file content in segments to not hit PHP's memory limit (default: 128M) 127 | if ($fd = fopen($file, 'rb')) { 128 | while (!feof($fd)) { 129 | print fread($fd, Archive::$SEGMENT_SIZE); 130 | @ob_flush(); 131 | @flush(); 132 | } 133 | fclose($fd); 134 | } 135 | } 136 | 137 | private function add_hrefs($hrefs) { 138 | if (!is_array($hrefs)) { 139 | $hrefs = array($hrefs); 140 | } 141 | 142 | foreach ($hrefs as $href) { 143 | if (trim($href) === '') { 144 | continue; 145 | } 146 | 147 | $href = Util::normalize_path($href, false); 148 | $d = dirname($href); 149 | $n = basename($href); 150 | 151 | if ($this->context->is_managed_href($d) && !$this->context->is_hidden($n)) { 152 | 153 | $real_file = $this->context->to_path($href); 154 | $archived_file = preg_replace('!^' . preg_quote(Util::normalize_path($this->base_path, true)) . '!', '', $real_file); 155 | 156 | if (is_dir($real_file)) { 157 | $this->add_dir($real_file, $archived_file); 158 | } else { 159 | $this->add_file($real_file, $archived_file); 160 | } 161 | } 162 | } 163 | } 164 | 165 | private function add_file($real_file, $archived_file) { 166 | if (is_readable($real_file)) { 167 | $this->files[$real_file] = $archived_file; 168 | } 169 | } 170 | 171 | private function add_dir($real_dir, $archived_dir) { 172 | if ($this->context->is_managed_path($real_dir)) { 173 | $this->dirs[$real_dir] = $archived_dir; 174 | 175 | $files = $this->context->read_dir($real_dir); 176 | foreach ($files as $file) { 177 | $real_file = $real_dir . '/' . $file; 178 | $archived_file = $archived_dir . '/' . $file; 179 | 180 | if (is_dir($real_file)) { 181 | $this->add_dir($real_file, $archived_file); 182 | } else { 183 | $this->add_file($real_file, $archived_file); 184 | } 185 | } 186 | } 187 | } 188 | } 189 | -------------------------------------------------------------------------------- /config/_h5ai/private/php/core/class-setup.php: -------------------------------------------------------------------------------- 1 | store = []; 9 | $this->refresh = $refresh; 10 | 11 | $this->add_globals_and_envs(); 12 | $this->add_php_checks(); 13 | $this->add_app_metadata(); 14 | $this->add_server_metadata_and_check(); 15 | $this->add_paths(); 16 | $this->add_sys_cmd_checks(); 17 | } 18 | 19 | private function set($key, $value) { 20 | if (array_key_exists($key, $this->store)) { 21 | Logger::log('setup key already taken', [ 22 | 'key' => $key, 23 | 'value' => $value, 24 | 'found' => $this->store[$key] 25 | ]); 26 | exit; 27 | } 28 | if (!is_string($value) && !is_bool($value)) { 29 | Logger::log('setup value neither string nor boolean', [ 30 | 'key' => $key, 31 | 'value' => $value 32 | ]); 33 | exit; 34 | } 35 | 36 | $this->store[$key] = $value; 37 | } 38 | 39 | public function get($key) { 40 | if (!array_key_exists($key, $this->store)) { 41 | Logger::log('setup key not found', ['key' => $key]); 42 | exit; 43 | } 44 | 45 | return $this->store[$key]; 46 | } 47 | 48 | private function add_globals_and_envs() { 49 | $this->set('PHP_VERSION', PHP_VERSION); 50 | $this->set('MIN_PHP_VERSION', MIN_PHP_VERSION); 51 | $this->set('PHP_ARCH', (PHP_INT_SIZE * 8) . '-bit'); 52 | 53 | $this->set('REQUEST_METHOD', $_SERVER['REQUEST_METHOD']); 54 | $this->set('REQUEST_HREF', parse_url($_SERVER['REQUEST_URI'], PHP_URL_PATH)); 55 | $this->set('SCRIPT_NAME', $_SERVER['SCRIPT_NAME']); 56 | $this->set('SERVER_SOFTWARE', $_SERVER['SERVER_SOFTWARE']); 57 | $this->set('HTTP_USER_AGENT', $_SERVER['HTTP_USER_AGENT']); 58 | } 59 | 60 | private function add_php_checks() { 61 | $this->set('HAS_PHP_EXIF', function_exists('exif_thumbnail')); 62 | 63 | $has_php_jpeg = false; 64 | if (function_exists('gd_info')) { 65 | $infos = gd_info(); 66 | $has_php_jpeg = array_key_exists('JPEG Support', $infos) && $infos['JPEG Support']; 67 | } 68 | $this->set('HAS_PHP_JPEG', $has_php_jpeg); 69 | } 70 | 71 | private function add_app_metadata() { 72 | $this->set('NAME', 'h5ai'); 73 | $this->set('VERSION', H5AI_VERSION); 74 | $this->set('FILE_PREFIX', '_h5ai'); 75 | } 76 | 77 | private function add_server_metadata_and_check() { 78 | $server_software = $this->get('SERVER_SOFTWARE'); 79 | $server_name = null; 80 | $server_version = null; 81 | 82 | if ($server_software && preg_match('#^(.*?)(?:/(.*?))?(?: |$)#', strtolower($server_software), $matches)) { 83 | $server_name = $matches[1]; 84 | $server_version = count($matches) > 2 ? $matches[2] : ''; 85 | } 86 | 87 | $this->set('SERVER_NAME', $server_name); 88 | $this->set('SERVER_VERSION', $server_version); 89 | $this->set('HAS_SERVER', in_array($server_name, ['apache', 'lighttpd', 'nginx', 'cherokee'])); 90 | } 91 | 92 | private function add_paths() { 93 | $script_name = $this->get('SCRIPT_NAME'); 94 | if ($this->get('SERVER_NAME') === 'lighttpd') { 95 | $script_name = preg_replace('#^.*?//#', '/', $script_name); 96 | } 97 | 98 | $this->set('H5AI_HREF', Util::normalize_path(dirname(dirname($script_name)), true)); 99 | $this->set('H5AI_PATH', Util::normalize_path(dirname(dirname(dirname(dirname(__FILE__)))), false)); 100 | 101 | $this->set('ROOT_HREF', Util::normalize_path(dirname($this->get('H5AI_HREF')), true)); 102 | $this->set('ROOT_PATH', '/h5ai'); 103 | 104 | $this->set('PUBLIC_HREF', Util::normalize_path($this->get('H5AI_HREF') . '/public/', true)); 105 | $this->set('PUBLIC_PATH', Util::normalize_path($this->get('H5AI_PATH') . '/public/', false)); 106 | 107 | $this->set('INDEX_HREF', Util::normalize_path($this->get('PUBLIC_HREF') . '/index.php', false)); 108 | $this->set('CACHE_PUB_HREF', Util::normalize_path($this->get('PUBLIC_HREF') . '/cache', true)); 109 | $this->set('CACHE_PUB_PATH', Util::normalize_path($this->get('PUBLIC_PATH') . '/cache', false)); 110 | $this->set('HAS_WRITABLE_CACHE_PUB', @is_writable($this->get('CACHE_PUB_PATH'))); 111 | 112 | $this->set('PRIVATE_PATH', Util::normalize_path($this->get('H5AI_PATH') . '/private', false)); 113 | $this->set('CONF_PATH', Util::normalize_path($this->get('PRIVATE_PATH') . '/conf', false)); 114 | $this->set('CACHE_PRV_PATH', Util::normalize_path($this->get('PRIVATE_PATH') . '/cache', false)); 115 | $this->set('HAS_WRITABLE_CACHE_PRV', @is_writable($this->get('CACHE_PRV_PATH'))); 116 | } 117 | 118 | private function add_sys_cmd_checks() { 119 | $cmds_cache_path = Util::normalize_path($this->get('CACHE_PRV_PATH') . '/cmds.json', false); 120 | 121 | $cmds = Json::load($cmds_cache_path); 122 | if (sizeof($cmds) === 0 || $this->refresh) { 123 | $cmds['command'] = Util::exec_0('command -v command'); 124 | $cmds['which'] = Util::exec_0('which which') || Util::exec_0('which which.exe'); 125 | $cmds['where'] = Util::exec_0('where where.exe'); 126 | 127 | $cmd = false; 128 | if ($cmds['command']) { 129 | $cmd = 'command -v'; 130 | } elseif ($cmds['which']) { 131 | $cmd = 'which'; 132 | } elseif ($cmds['where']) { 133 | $cmd = 'where'; 134 | } 135 | 136 | foreach (['avconv', 'convert', 'du', 'ffmpeg', 'gm', 'tar', 'zip'] as $c) { 137 | $cmds[$c] = ($cmd !== false) && (Util::exec_0($cmd . ' ' . $c) || Util::exec_0($cmd . ' ' . $c . '.exe')); 138 | } 139 | 140 | Json::save($cmds_cache_path, $cmds); 141 | } 142 | foreach ($cmds as $c => $has) { 143 | $this->set('HAS_CMD_' . strtoupper($c), $has); 144 | } 145 | } 146 | 147 | public function to_jsono($as_admin = false) { 148 | $keys = [ 149 | 'PUBLIC_HREF', 150 | 'ROOT_HREF' 151 | ]; 152 | 153 | if ($as_admin) { 154 | $keys = array_merge($keys, [ 155 | 'VERSION', 156 | 157 | 'PHP_VERSION', 158 | 'MIN_PHP_VERSION', 159 | 'PHP_ARCH', 160 | 'HAS_PHP_EXIF', 161 | 'HAS_PHP_JPEG', 162 | 163 | 'SERVER_NAME', 164 | 'SERVER_VERSION', 165 | 'HAS_SERVER', 166 | 167 | 'INDEX_HREF', 168 | 169 | 'HAS_WRITABLE_CACHE_PUB', 170 | 'HAS_WRITABLE_CACHE_PRV', 171 | 172 | 'HAS_CMD_AVCONV', 173 | 'HAS_CMD_CONVERT', 174 | 'HAS_CMD_DU', 175 | 'HAS_CMD_FFMPEG', 176 | 'HAS_CMD_GM', 177 | 'HAS_CMD_TAR', 178 | 'HAS_CMD_ZIP' 179 | ]); 180 | } 181 | 182 | $jsono = ['AS_ADMIN' => $as_admin]; 183 | foreach ($keys as $key) { 184 | $jsono[$key] = $this->get($key); 185 | } 186 | return $jsono; 187 | } 188 | } 189 | -------------------------------------------------------------------------------- /config/_h5ai/.htaccess: -------------------------------------------------------------------------------- 1 | ## details here: https://github.com/h5bp/server-configs-apache 2 | 3 | 4 | 5 | ## SECURITY ################################################################### 6 | 7 | DirectoryIndex disabled 8 | FileETag None 9 | ServerSignature Off 10 | 11 | # Apache < 2.3 12 | 13 | Order allow,deny 14 | Deny from all 15 | Satisfy All 16 | 17 | 18 | # Apache ≥ 2.3 19 | 20 | Require all denied 21 | 22 | 23 | 24 | Header set X-Content-Type-Options "nosniff" 25 | Header unset ETag 26 | Header unset X-Powered-By 27 | 28 | 29 | 30 | Options -Indexes 31 | 32 | 33 | 34 | 35 | ## COMPAT ##################################################################### 36 | 37 | AddDefaultCharset utf-8 38 | 39 | 40 | AddCharset utf-8 .css .html .js .json .php .svg 41 | 42 | AddType application/font-woff woff 43 | AddType application/font-woff2 woff2 44 | AddType application/json json 45 | AddType application/javascript js 46 | AddType application/vnd.ms-fontobject eot 47 | AddType application/x-font-ttf ttc ttf 48 | AddType image/jpeg jpeg jpg 49 | AddType image/png png 50 | AddType image/svg+xml svg svgz 51 | AddType image/x-icon ico 52 | AddType font/opentype otf 53 | AddType text/css css 54 | AddType text/html html 55 | 56 | 57 | 58 | 59 | ## SPEED ###################################################################### 60 | 61 | 62 | ExpiresActive on 63 | ExpiresDefault "access plus 1 month" 64 | 65 | ExpiresByType application/json "access plus 0 seconds" 66 | 67 | ExpiresByType text/html "access plus 1 minute" 68 | 69 | ExpiresByType image/x-icon "access plus 1 week" 70 | 71 | ExpiresByType application/javascript "access plus 1 year" 72 | ExpiresByType image/jpeg "access plus 1 year" 73 | ExpiresByType image/png "access plus 1 year" 74 | ExpiresByType image/svg+xml "access plus 1 year" 75 | ExpiresByType text/css "access plus 1 year" 76 | 77 | 78 | 79 | 80 | 81 | SetEnvIfNoCase ^(Accept-EncodXng|X-cept-Encoding|X{15}|~{15}|-{15})$ ^((gzip|deflate)\s*,?\s*)+|[X~-]{4,13}$ HAVE_Accept-Encoding 82 | RequestHeader append Accept-Encoding "gzip,deflate" env=HAVE_Accept-Encoding 83 | 84 | 85 | 86 | # Apache ≥ 2.3 87 | 88 | # mod_filter as module only available for Apache ≥ 2.3.7 89 | 90 | AddOutputFilterByType DEFLATE "application/atom+xml" \ 91 | "application/javascript" \ 92 | "application/json" \ 93 | "application/ld+json" \ 94 | "application/manifest+json" \ 95 | "application/rdf+xml" \ 96 | "application/rss+xml" \ 97 | "application/schema+json" \ 98 | "application/vnd.geo+json" \ 99 | "application/vnd.ms-fontobject" \ 100 | "application/x-font-ttf" \ 101 | "application/x-javascript" \ 102 | "application/x-web-app-manifest+json" \ 103 | "application/xhtml+xml" \ 104 | "application/xml" \ 105 | "font/eot" \ 106 | "font/opentype" \ 107 | "image/bmp" \ 108 | "image/svg+xml" \ 109 | "image/vnd.microsoft.icon" \ 110 | "image/x-icon" \ 111 | "text/cache-manifest" \ 112 | "text/css" \ 113 | "text/html" \ 114 | "text/javascript" \ 115 | "text/plain" \ 116 | "text/vcard" \ 117 | "text/vnd.rim.location.xloc" \ 118 | "text/vtt" \ 119 | "text/x-component" \ 120 | "text/x-cross-domain-policy" \ 121 | "text/xml" 122 | 123 | 124 | 125 | # Apache < 2.3 126 | 127 | AddOutputFilterByType DEFLATE "application/atom+xml" \ 128 | "application/javascript" \ 129 | "application/json" \ 130 | "application/ld+json" \ 131 | "application/manifest+json" \ 132 | "application/rdf+xml" \ 133 | "application/rss+xml" \ 134 | "application/schema+json" \ 135 | "application/vnd.geo+json" \ 136 | "application/vnd.ms-fontobject" \ 137 | "application/x-font-ttf" \ 138 | "application/x-javascript" \ 139 | "application/x-web-app-manifest+json" \ 140 | "application/xhtml+xml" \ 141 | "application/xml" \ 142 | "font/eot" \ 143 | "font/opentype" \ 144 | "image/bmp" \ 145 | "image/svg+xml" \ 146 | "image/vnd.microsoft.icon" \ 147 | "image/x-icon" \ 148 | "text/cache-manifest" \ 149 | "text/css" \ 150 | "text/html" \ 151 | "text/javascript" \ 152 | "text/plain" \ 153 | "text/vcard" \ 154 | "text/vnd.rim.location.xloc" \ 155 | "text/vtt" \ 156 | "text/x-component" \ 157 | "text/x-cross-domain-policy" \ 158 | "text/xml" 159 | 160 | 161 | 162 | AddEncoding gzip gz 163 | AddEncoding gzip svgz 164 | 165 | 166 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # docker-h5ai 2 | 3 | ![](https://img.shields.io/badge/multiarch-amd64(x86__64)%2C%20arm64%2C%20armv7%2C%20armv6-lightgrey?style=flat-square) 4 | ![](https://img.shields.io/github/actions/workflow/status/awesometic/docker-h5ai/buildx.yml?branch=master?style=flat-square) 5 | 6 | ![](https://img.shields.io/docker/image-size/awesometic/h5ai/latest?style=flat-square) 7 | ![](https://img.shields.io/docker/pulls/awesometic/h5ai?style=flat-square) 8 | ![](https://img.shields.io/docker/stars/awesometic/h5ai?style=flat-square) 9 | 10 | ## What is h5ai 11 | 12 | I'd like to quote the [official website](https://larsjung.de/h5ai/). 13 | > h5ai is a modern file indexer for HTTP web servers with focus on your files. Directories are displayed in a appealing way and browsing them is enhanced by different views, a breadcrumb and a tree overview. Initially h5ai was an acronym for HTML5 Apache Index but now it supports other web servers too. 14 | 15 | ## What this project provided for 16 | 17 | I hope this project would be useful for those who uses Docker for building their server. 18 | 19 | ## Features 20 | 21 | ### Core packages 22 | 23 | I choose Alpine Linux as a base image to make it a **light-weight** service. 24 | And I do choose Nginx-Alpine to get the benefits from some tweaks of Nginx version. 25 | 26 | So this is composed of, 27 | 28 | * Alpine Linux 3.19 29 | * Nginx 1.27.0 30 | * PHP 8.2.20 31 | 32 | with, 33 | 34 | * h5ai 0.30.0 35 | 36 | And to gather all of these into one together I use supervisor that manages all of these processes. 37 | 38 | ### All functions work 39 | 40 | ![all functions work](docs/docker-h5ai-functions.png) 41 | h5ai supports extensional functions such as showing thumnails of audio and video, caching for better speed, etc. This image activates all of those functions. 42 | 43 | ### PHP 8 JIT enabled 44 | 45 | ![jit enabled](docs/docker-h5ai-php-jit.png) 46 | JIT compiler that is introduced in PHP 8 is enabled by default. 47 | 48 | ### Supports multiple architectures 49 | 50 | It builds from Github Actions for supporting multiple architectures such as AMD64(x86_64) and ARM64, ARMv7, ARMv6. 51 | 52 | So that you can use this on most computers supporting Docker. 53 | 54 | ## How can I use this 55 | 56 | First of all, it assumes that you have installed Docker on your system. 57 | 58 | ### Pulling the Docker image 59 | 60 | Pull the image from docker hub with the following command. 61 | 62 | ```bash 63 | docker pull awesometic/h5ai 64 | ``` 65 | 66 | ### Basic usage 67 | 68 | This is how it can be a service, in the other word, a container. 69 | 70 | You can run it using the following command. 71 | 72 | ```bash 73 | docker run -it --rm \ 74 | -p 80:80 \ 75 | -v /shared/dir:/h5ai \ 76 | -v /config/dir:/config \ 77 | -e PUID=$UID \ 78 | -e PGID=$GID \ 79 | -e TZ=Asia/Seoul \ 80 | awesometic/h5ai 81 | ``` 82 | 83 | The `--rm` option in the command is added to remove the executed container since this is an example usage. 84 | 85 | Basically, two directories should be mapped to the host PC. 86 | 87 | * `/h5ai`: This will be where the shared files located. 88 | * `/config`: This will be where stores configurations of h5ai and Nginx settings. 89 | 90 | And you should set proper **PUID** and **PGID**. If those not set up, the default UID, GID, the number 911, will be used for the `/config` directory. Not setting PUID/PGID will not significantly affect its operations, but setting up the proper number is still recommended. 91 | 92 | Or you can handle some directories that has special permissions using these PUID/PGID. 93 | 94 | If you want to run this image as a daemon, use `-d` option. See the following command. 95 | 96 | ```bash 97 | docker run -d --name=h5ai \ 98 | -p 80:80 \ 99 | -v /shared/dir:/h5ai \ 100 | -v /config/dir:/config \ 101 | -e PUID=$UID \ 102 | -e PGID=$GID \ 103 | -e TZ=Asia/Seoul \ 104 | awesometic/h5ai 105 | ``` 106 | 107 | If you want to run this image permanently, so to speak, to keep it runs after rebooting the server, you can use `--restart unless-stopped` option. See the following command. 108 | 109 | ```bash 110 | docker run -d --name=h5ai \ 111 | -p 80:80 \ 112 | -v /shared/dir:/h5ai \ 113 | -v /config/dir:/config \ 114 | -e PUID=$UID \ 115 | -e PGID=$GID \ 116 | -e TZ=Asia/Seoul \ 117 | --restart unless-stopped \ 118 | awesometic/h5ai 119 | ``` 120 | 121 | ### Keep in safe from anonymous 122 | 123 | If you want to login when visiting the hosted h5ai website so that implement protection from accessing anonymous users, add `HTPASSWD` environments like the below. 124 | 125 | ```bash 126 | docker run -it --name=h5ai \ 127 | -p 80:80 \ 128 | -v /shared/dir:/h5ai \ 129 | -v /config/dir:/config \ 130 | -e PUID=$UID \ 131 | -e PGID=$GID \ 132 | -e TZ=Asia/Seoul \ 133 | -e HTPASSWD=true \ 134 | -e HTPASSWD_USER=awesometic \ 135 | awesometic/h5ai 136 | ``` 137 | 138 | Then only the user set by `HTPASSWD_USER`, **awesometic** can access this h5ai website with these options. 139 | 140 | Be aware of that the `HTPASSWD` environment variable must be **true** for authentication. 141 | 142 | And aware of this too that you have to run in interaction mode by adding **-it** to set a password for the newly created user for the first time. 143 | 144 | Or, you can set the password for Htpasswd by passing an environment variable. In this case, you shouldn't have to use **-it** option because it is not needed at all. 145 | 146 | ### Use it as a real-time service 147 | 148 | Consequently, if you want to run this image as a real-time service, check the following command. 149 | 150 | ```bash 151 | docker run -d --name=h5ai \ 152 | -p 80:80 \ 153 | -v /shared/dir:/h5ai \ 154 | -v /config/dir:/config \ 155 | -e PUID=$UID \ 156 | -e PGID=$GID \ 157 | -e TZ=Asia/Seoul \ 158 | -e HTPASSWD=true \ 159 | -e HTPASSWD_USER=awesometic \ 160 | -e HTPASSWD_PW=awesometic \ 161 | --restart unless-stopped \ 162 | awesometic/h5ai 163 | ``` 164 | 165 | ### Visit your website 166 | 167 | To do the test drive, when the container runs then just let your browser browses: 168 | 169 | ``` http 170 | http://localhost/ 171 | ``` 172 | 173 | ![Sample files from https://www.sample-videos.com/](docs/docker-h5ai-demo.png) 174 | After all, you can see the directories you shared. 175 | 176 | ## Caution when update 177 | 178 | **If the new h5ai version releases**, I overwrite all the updated files to the corresponded directories on the project folder. In this sequence, some customized files by you will be replaced into the new one. 179 | 180 | So it is **highly recommended to make back up files of your edits** before update the Docker image. 181 | 182 | To prevent an unexpected accident, I put minimal protection into my `init.sh` script. This checks if the current `private/conf/options.json` file is outdated from the current about to be run. If the current `options.json` is older than the newly loaded one, the script makes its backup file under the `/config` directory. See the followings. 183 | 184 | ```bash 185 | awesometic@awesometic-nas:docker/h5ai $ ll 186 | total 32K 187 | -rwxr-xr-x 1 root root 12K Jul 10 2019 20190710_165345_options.json.bak 188 | -rwxr-xr-x 1 root root 12K Feb 3 14:46 20210203_144624_options.json.bak 189 | drwxr-xr-x 3 root root 4.0K Feb 3 14:46 h5ai 190 | drwxr-xr-x 2 root root 4.0K Dec 14 2018 nginx 191 | ``` 192 | 193 | But since I don't know how much the users edit their h5ai files like layout or style, it won't make backups for all of the h5ai related files. So it depends on your caution. 194 | 195 | If you have any good idea, please let me know. 😀 196 | 197 | ## Use with HTTPS (SSL) 198 | 199 | It is highly recommended to use this web service with HTTPS for data encryption. Without SSL, the attackers can see your data streams even if you set the htpasswd to authenticate to the web page. 200 | 201 | In this image, it is not provide any HTTPS related settings but you can set HTTPS with another web server. The most frequently used thing for HTTPS is a reverse proxy server, which can be set easiliy with a docker image called [SWAG from LinuxServer.io](https://hub.docker.com/r/linuxserver/swag). 202 | 203 | ## TODOs 204 | 205 | * [x] Easy access to options.json 206 | * [x] Access permission using htpasswd 207 | * [x] Setup PUID/PGID to better handle the permissions 208 | * [ ] Expose Nginx, PHP log files to the host 209 | 210 | ## License 211 | 212 | This project comes with MIT license. Please see the [license file](LICENSE). 213 | -------------------------------------------------------------------------------- /config/_h5ai/private/php/ext/class-thumb.php: -------------------------------------------------------------------------------- 1 | context = $context; 17 | $this->setup = $context->get_setup(); 18 | $this->thumbs_path = $this->setup->get('CACHE_PUB_PATH') . '/' . Thumb::$THUMB_CACHE; 19 | $this->thumbs_href = $this->setup->get('CACHE_PUB_HREF') . Thumb::$THUMB_CACHE; 20 | 21 | if (!is_dir($this->thumbs_path)) { 22 | @mkdir($this->thumbs_path, 0755, true); 23 | } 24 | } 25 | 26 | public function thumb($type, $source_href, $width, $height) { 27 | $source_path = $this->context->to_path($source_href); 28 | if (!file_exists($source_path) || Util::starts_with($source_path, $this->setup->get('CACHE_PUB_PATH'))) { 29 | return null; 30 | } 31 | 32 | $capture_path = $source_path; 33 | if ($type === 'img') { 34 | $capture_path = $source_path; 35 | } elseif ($type === 'mov') { 36 | if ($this->setup->get('HAS_CMD_AVCONV')) { 37 | $capture_path = $this->capture(Thumb::$AVCONV_CMDV, $source_path); 38 | } elseif ($this->setup->get('HAS_CMD_FFMPEG')) { 39 | $capture_path = $this->capture(Thumb::$FFMPEG_CMDV, $source_path); 40 | } 41 | } elseif ($type === 'doc') { 42 | if ($this->setup->get('HAS_CMD_CONVERT')) { 43 | $capture_path = $this->capture(Thumb::$CONVERT_CMDV, $source_path); 44 | } elseif ($this->setup->get('HAS_CMD_GM')) { 45 | $capture_path = $this->capture(Thumb::$GM_CONVERT_CMDV, $source_path); 46 | } 47 | } 48 | 49 | return $this->thumb_href($capture_path, $width, $height); 50 | } 51 | 52 | private function thumb_href($source_path, $width, $height) { 53 | if (!file_exists($source_path)) { 54 | return null; 55 | } 56 | 57 | $name = 'thumb-' . sha1($source_path) . '-' . $width . 'x' . $height . '.jpg'; 58 | $thumb_path = $this->thumbs_path . '/' . $name; 59 | $thumb_href = $this->thumbs_href . '/' . $name; 60 | 61 | if (!file_exists($thumb_path) || filemtime($source_path) >= filemtime($thumb_path)) { 62 | $image = new Image(); 63 | 64 | $et = false; 65 | if ($this->setup->get('HAS_PHP_EXIF') && $this->context->query_option('thumbnails.exif', false) === true && $height != 0) { 66 | $et = @exif_thumbnail($source_path); 67 | } 68 | if($et !== false) { 69 | file_put_contents($thumb_path, $et); 70 | $image->set_source($thumb_path); 71 | $image->normalize_exif_orientation($source_path); 72 | } else { 73 | $image->set_source($source_path); 74 | } 75 | 76 | $image->thumb($width, $height); 77 | $image->save_dest_jpeg($thumb_path, 80); 78 | } 79 | 80 | return file_exists($thumb_path) ? $thumb_href : null; 81 | } 82 | 83 | private function capture($cmdv, $source_path) { 84 | if (!file_exists($source_path)) { 85 | return null; 86 | } 87 | 88 | $capture_path = $this->thumbs_path . '/capture-' . sha1($source_path) . '.jpg'; 89 | 90 | if (!file_exists($capture_path) || filemtime($source_path) >= filemtime($capture_path)) { 91 | foreach ($cmdv as &$arg) { 92 | $arg = str_replace('[SRC]', $source_path, $arg); 93 | $arg = str_replace('[DEST]', $capture_path, $arg); 94 | } 95 | 96 | Util::exec_cmdv($cmdv); 97 | } 98 | 99 | return file_exists($capture_path) ? $capture_path : null; 100 | } 101 | } 102 | 103 | class Image { 104 | private $source_file; 105 | private $source; 106 | private $width; 107 | private $height; 108 | private $type; 109 | private $dest; 110 | 111 | public function __construct($filename = null) { 112 | $this->source_file = null; 113 | $this->source = null; 114 | $this->width = null; 115 | $this->height = null; 116 | $this->type = null; 117 | 118 | $this->dest = null; 119 | 120 | $this->set_source($filename); 121 | } 122 | 123 | public function __destruct() { 124 | $this->release_source(); 125 | $this->release_dest(); 126 | } 127 | 128 | public function set_source($filename) { 129 | $this->release_source(); 130 | $this->release_dest(); 131 | 132 | if (is_null($filename)) { 133 | return; 134 | } 135 | 136 | $this->source_file = $filename; 137 | 138 | list($this->width, $this->height, $this->type) = @getimagesize($this->source_file); 139 | 140 | if (!$this->width || !$this->height) { 141 | $this->source_file = null; 142 | $this->width = null; 143 | $this->height = null; 144 | $this->type = null; 145 | return; 146 | } 147 | 148 | $this->source = imagecreatefromstring(file_get_contents($this->source_file)); 149 | } 150 | 151 | public function save_dest_jpeg($filename, $quality = 80) { 152 | if (!is_null($this->dest)) { 153 | @imagejpeg($this->dest, $filename, $quality); 154 | @chmod($filename, 0775); 155 | } 156 | } 157 | 158 | public function release_dest() { 159 | if (!is_null($this->dest)) { 160 | @imagedestroy($this->dest); 161 | $this->dest = null; 162 | } 163 | } 164 | 165 | public function release_source() { 166 | if (!is_null($this->source)) { 167 | @imagedestroy($this->source); 168 | $this->source_file = null; 169 | $this->source = null; 170 | $this->width = null; 171 | $this->height = null; 172 | $this->type = null; 173 | } 174 | } 175 | 176 | public function thumb($width, $height) { 177 | if (is_null($this->source)) { 178 | return; 179 | } 180 | 181 | $src_r = 1.0 * $this->width / $this->height; 182 | 183 | if ($height == 0) { 184 | if ($src_r >= 1) { 185 | $height = 1.0 * $width / $src_r; 186 | } else { 187 | $height = $width; 188 | $width = 1.0 * $height * $src_r; 189 | } 190 | if ($width > $this->width) { 191 | $width = $this->width; 192 | $height = $this->height; 193 | } 194 | } 195 | 196 | $ratio = 1.0 * $width / $height; 197 | 198 | if ($src_r <= $ratio) { 199 | $src_w = $this->width; 200 | $src_h = $src_w / $ratio; 201 | $src_x = 0; 202 | } else { 203 | $src_h = $this->height; 204 | $src_w = $src_h * $ratio; 205 | $src_x = 0.5 * ($this->width - $src_w); 206 | } 207 | 208 | $width = intval($width); 209 | $height = intval($height); 210 | $src_x = intval($src_x); 211 | $src_w = intval($src_w); 212 | $src_h = intval($src_h); 213 | 214 | $this->dest = imagecreatetruecolor($width, $height); 215 | $icol = imagecolorallocate($this->dest, 255, 255, 255); 216 | imagefill($this->dest, 0, 0, $icol); 217 | imagecopyresampled($this->dest, $this->source, 0, 0, $src_x, 0, $width, $height, $src_w, $src_h); 218 | } 219 | 220 | public function rotate($angle) { 221 | if (is_null($this->source) || ($angle !== 90 && $angle !== 180 && $angle !== 270)) { 222 | return; 223 | } 224 | 225 | $this->source = imagerotate($this->source, $angle, 0); 226 | if ( $angle === 90 || $angle === 270 ) { 227 | list($this->width, $this->height) = [$this->height, $this->width]; 228 | } 229 | } 230 | 231 | public function normalize_exif_orientation($exif_source_file = null) { 232 | if (is_null($this->source) || !function_exists('exif_read_data')) { 233 | return; 234 | } 235 | 236 | if ($exif_source_file === null) { 237 | $exif_source_file = $this->source_file; 238 | } 239 | 240 | $exif = exif_read_data($exif_source_file); 241 | switch (@$exif['Orientation']) { 242 | case 3: 243 | $this->rotate(180); 244 | break; 245 | case 6: 246 | $this->rotate(270); 247 | break; 248 | case 8: 249 | $this->rotate(90); 250 | break; 251 | } 252 | } 253 | } 254 | -------------------------------------------------------------------------------- /config/_h5ai/private/php/core/class-context.php: -------------------------------------------------------------------------------- 1 | session = $session; 21 | $this->request = $request; 22 | $this->setup = $setup; 23 | 24 | $this->options = Json::load($this->setup->get('CONF_PATH') . '/options.json'); 25 | 26 | $this->passhash = $this->query_option('passhash', ''); 27 | $this->options['hasCustomPasshash'] = strcasecmp($this->passhash, Context::$DEFAULT_PASSHASH) !== 0; 28 | unset($this->options['passhash']); 29 | } 30 | 31 | public function get_session() { 32 | return $this->session; 33 | } 34 | 35 | public function get_request() { 36 | return $this->request; 37 | } 38 | 39 | public function get_setup() { 40 | return $this->setup; 41 | } 42 | 43 | public function get_options() { 44 | return $this->options; 45 | } 46 | 47 | public function query_option($keypath = '', $default = null) { 48 | return Util::array_query($this->options, $keypath, $default); 49 | } 50 | 51 | public function get_types() { 52 | return Json::load($this->setup->get('CONF_PATH') . '/types.json'); 53 | } 54 | 55 | public function login_admin($pass) { 56 | $this->session->set(Context::$AS_ADMIN_SESSION_KEY, strcasecmp(hash('sha512', $pass), $this->passhash) === 0); 57 | return $this->session->get(Context::$AS_ADMIN_SESSION_KEY); 58 | } 59 | 60 | public function logout_admin() { 61 | $this->session->set(Context::$AS_ADMIN_SESSION_KEY, false); 62 | return $this->session->get(Context::$AS_ADMIN_SESSION_KEY); 63 | } 64 | 65 | public function is_admin() { 66 | return $this->session->get(Context::$AS_ADMIN_SESSION_KEY); 67 | } 68 | 69 | public function is_api_request() { 70 | return strtolower($this->setup->get('REQUEST_METHOD')) === 'post'; 71 | } 72 | 73 | public function is_info_request() { 74 | return Util::starts_with($this->setup->get('REQUEST_HREF') . '/', $this->setup->get('PUBLIC_HREF')); 75 | } 76 | 77 | public function is_text_browser() { 78 | return preg_match('/curl|links|lynx|w3m/i', $this->setup->get('HTTP_USER_AGENT')) === 1; 79 | } 80 | 81 | public function is_fallback_mode() { 82 | return $this->query_option('view.fallbackMode', false) || $this->is_text_browser(); 83 | } 84 | 85 | public function to_href($path, $trailing_slash = true) { 86 | $rel_path = substr($path, strlen($this->setup->get('ROOT_PATH'))); 87 | $parts = explode('/', $rel_path); 88 | $encoded_parts = []; 89 | foreach ($parts as $part) { 90 | if ($part != '') { 91 | $encoded_parts[] = rawurlencode($part); 92 | } 93 | } 94 | 95 | return Util::normalize_path($this->setup->get('ROOT_HREF') . implode('/', $encoded_parts), $trailing_slash); 96 | } 97 | 98 | public function to_path($href) { 99 | $rel_href = substr($href, strlen($this->setup->get('ROOT_HREF'))); 100 | return Util::normalize_path($this->setup->get('ROOT_PATH') . '/' . rawurldecode($rel_href)); 101 | } 102 | 103 | public function is_hidden($name) { 104 | // always hide 105 | if ($name === '.' || $name === '..') { 106 | return true; 107 | } 108 | 109 | foreach ($this->query_option('view.hidden', []) as $re) { 110 | $re = Util::wrap_pattern($re); 111 | if (preg_match($re, $name)) { 112 | return true; 113 | } 114 | } 115 | 116 | return false; 117 | } 118 | 119 | public function read_dir($path) { 120 | $names = []; 121 | if (is_dir($path)) { 122 | foreach (scandir($path) as $name) { 123 | if ( 124 | $this->is_hidden($name) 125 | || $this->is_hidden($this->to_href($path) . $name) 126 | || (!is_readable($path . '/' . $name) && $this->query_option('view.hideIf403', false)) 127 | ) { 128 | continue; 129 | } 130 | $names[] = $name; 131 | } 132 | } 133 | return $names; 134 | } 135 | 136 | public function is_managed_href($href) { 137 | return $this->is_managed_path($this->to_path($href)); 138 | } 139 | 140 | public function is_managed_path($path) { 141 | if (!is_dir($path) || strpos($path, '../') !== false || strpos($path, '/..') !== false || $path === '..') { 142 | return false; 143 | } 144 | 145 | if (strpos($path, $this->setup->get('PUBLIC_PATH')) === 0) { 146 | return false; 147 | } 148 | 149 | if (strpos($path, $this->setup->get('PRIVATE_PATH')) === 0) { 150 | return false; 151 | } 152 | 153 | foreach ($this->query_option('view.unmanaged', []) as $name) { 154 | if (file_exists($path . '/' . $name)) { 155 | return false; 156 | } 157 | } 158 | 159 | while ($path !== $this->setup->get('ROOT_PATH')) { 160 | if (@is_dir($path . '/_h5ai/private/conf')) { 161 | return false; 162 | } 163 | $parent_path = Util::normalize_path(dirname($path)); 164 | if ($parent_path === $path) { 165 | return false; 166 | } 167 | $path = $parent_path; 168 | } 169 | return true; 170 | } 171 | 172 | public function get_current_path() { 173 | $current_href = Util::normalize_path($this->setup->get('REQUEST_HREF'), true); 174 | $current_path = $this->to_path($current_href); 175 | 176 | if (!is_dir($current_path)) { 177 | $current_path = Util::normalize_path(dirname($current_path), false); 178 | } 179 | 180 | return $current_path; 181 | } 182 | 183 | public function get_items($href, $what) { 184 | if (!$this->is_managed_href($href)) { 185 | return []; 186 | } 187 | 188 | $cache = []; 189 | $folder = Item::get($this, $this->to_path($href), $cache); 190 | 191 | // add content of subfolders 192 | if ($what >= 2 && $folder !== null) { 193 | foreach ($folder->get_content($cache) as $item) { 194 | $item->get_content($cache); 195 | } 196 | $folder = $folder->get_parent($cache); 197 | } 198 | 199 | // add content of this folder and all parent folders 200 | while ($what >= 1 && $folder !== null) { 201 | $folder->get_content($cache); 202 | $folder = $folder->get_parent($cache); 203 | } 204 | 205 | uasort($cache, ['Item', 'cmp']); 206 | $result = []; 207 | foreach ($cache as $p => $item) { 208 | $result[] = $item->to_json_object(); 209 | } 210 | 211 | return $result; 212 | } 213 | 214 | public function get_langs() { 215 | $langs = []; 216 | $l10n_path = $this->setup->get('CONF_PATH') . '/l10n'; 217 | if (is_dir($l10n_path)) { 218 | if ($dir = opendir($l10n_path)) { 219 | while (($file = readdir($dir)) !== false) { 220 | if (Util::ends_with($file, '.json')) { 221 | $translations = Json::load($l10n_path . '/' . $file); 222 | $langs[basename($file, '.json')] = $translations['lang']; 223 | } 224 | } 225 | closedir($dir); 226 | } 227 | } 228 | ksort($langs); 229 | return $langs; 230 | } 231 | 232 | public function get_l10n($iso_codes) { 233 | $results = []; 234 | 235 | foreach ($iso_codes as $iso_code) { 236 | if (!in_array($iso_code, Context::$L10N_ISO_CODES)) { 237 | continue; 238 | } 239 | 240 | $file = $this->setup->get('CONF_PATH') . '/l10n/' . $iso_code . '.json'; 241 | $results[$iso_code] = Json::load($file); 242 | $results[$iso_code]['isoCode'] = $iso_code; 243 | } 244 | 245 | return $results; 246 | } 247 | 248 | public function get_thumbs($requests) { 249 | $hrefs = []; 250 | 251 | foreach ($requests as $req) { 252 | $thumb = new Thumb($this); 253 | $hrefs[] = $thumb->thumb($req['type'], $req['href'], $req['width'], $req['height']); 254 | } 255 | 256 | return $hrefs; 257 | } 258 | 259 | private function prefix_x_head_href($href) { 260 | if (preg_match('@^(https?://|/)@i', $href)) { 261 | return $href; 262 | } 263 | 264 | return $this->setup->get('PUBLIC_HREF') . 'ext/' . $href; 265 | } 266 | 267 | private function get_fonts_html() { 268 | $fonts = $this->query_option('view.fonts', []); 269 | $fonts_mono = $this->query_option('view.fontsMono', []); 270 | 271 | $html = ''; 282 | 283 | return $html; 284 | } 285 | 286 | public function get_x_head_html() { 287 | $scripts = $this->query_option('resources.scripts', []); 288 | $styles = $this->query_option('resources.styles', []); 289 | 290 | $html = ''; 291 | 292 | foreach ($styles as $href) { 293 | $html .= ''; 294 | } 295 | 296 | foreach ($scripts as $href) { 297 | $html .= ''; 298 | } 299 | 300 | $html .= $this->get_fonts_html(); 301 | 302 | return $html; 303 | } 304 | } 305 | -------------------------------------------------------------------------------- /config/_h5ai/private/conf/options.json: -------------------------------------------------------------------------------- 1 | /* h5ai v0.30.0 - https://larsjung.de/h5ai/ */ 2 | { 3 | /* 4 | Password hash. 5 | 6 | SHA512 hash of the info page password, the preset password is the empty string. 7 | Online hash generator: http://md5hashing.net/hashing/sha512 8 | */ 9 | "passhash": "cf83e1357eefb8bdf1542850d66d8007d620e4050b5715dc83f4a921d36ce9ce47d0d13c5d85f2b0ff8318d2877eec2f63b931bd47417a81a538327af927da3e", 10 | 11 | 12 | 13 | /* 14 | Resources. 15 | 16 | Additional script and style tags added to all pages. Paths not beginning 17 | with "http://", "https://" or "/" will be looked up relative to 18 | "_h5ai/public/ext/" (no check for existence). 19 | 20 | - scripts: array of strings 21 | - styles: array of strings 22 | */ 23 | "resources": { 24 | "scripts": [], 25 | "styles": [ 26 | "//fonts.googleapis.com/css?family=Ubuntu:300,400,700%7CUbuntu+Mono:400,700" 27 | ] 28 | }, 29 | 30 | 31 | 32 | /* 33 | General view options. 34 | 35 | - binaryPrefix: boolean, set to true uses 1024B=1KiB when formatting file sizes (see http://en.wikipedia.org/wiki/Binary_prefix) 36 | - disableSidebar: boolean, hides sidebar and toggle button 37 | - fallbackMode: boolean, serve fallback mode 38 | - fastBrowsing: boolean, use History API if available (no need to reload the whole page) 39 | - fonts: array of strings, fonts to use in regular context 40 | - fontsMono: array of strings, fonts to use in monopspaced context 41 | - hidden: array of strings, don't list items matching these regular expressions 42 | - hideFolders: boolean, hide all folders in the main view 43 | - hideIf403: boolean, hide files and folders that are not readable by the server 44 | - hideParentFolder: boolean, hide parent folder links in the main view 45 | - maxIconSize: number, max size for icons in the main view 46 | - modes: array of strings, subset of ["details", "grid", "icons"] 47 | the first value indicates the default view mode. If only one value 48 | is given the view mode is fixed and the selector buttons are hidden. 49 | The user selected view mode is also stored local in modern browsers 50 | so that it will be persistent. 51 | - modeToggle: boolean, show a view mode toggle in the toolbar, or "next" 52 | - setParentFolderLabels: boolean, set parent folder labels to real folder names 53 | - sizes: array of numbers 54 | the first value indicates the default view size. If only one value 55 | is given the view size is fixed and the selector buttons are hidden. 56 | The user selected view size is also stored local in modern browsers 57 | so that it will be persistent. 58 | - theme: string, name of one of the folders in "_h5ai/public/images/themes", defaults to "default" 59 | - unmanaged: array of strings, don't manage folders containing one of those files 60 | - unmanagedInNewWindow: boolean, open unmanaged links in new window/tab 61 | */ 62 | "view": { 63 | "binaryPrefix": false, 64 | "disableSidebar": false, 65 | "fallbackMode": false, 66 | "fastBrowsing": true, 67 | "fonts": ["Ubuntu", "Roboto", "Helvetica", "Arial", "sans-serif"], 68 | "fontsMono": ["Ubuntu Mono", "Monaco", "Lucida Sans Typewriter", "monospace"], 69 | "hidden": ["^\\.", "^_h5ai"], 70 | "hideFolders": false, 71 | "hideIf403": true, 72 | "hideParentFolder": false, 73 | "maxIconSize": 40, 74 | "modes": ["details", "grid", "icons"], 75 | "modeToggle": false, 76 | "setParentFolderLabels": true, 77 | "sizes": [20, 40, 60, 80, 100, 140, 180, 220, 260, 300], 78 | "theme": "comity", 79 | "unmanaged": ["index.html", "index.htm", "index.php"], 80 | "unmanagedInNewWindow": false 81 | }, 82 | 83 | 84 | 85 | /*** Extensions (in alphabetical order) ***/ 86 | 87 | /* 88 | Watch and update current folder content. 89 | 90 | - interval: number, update interval in milliseconds, at least 1000 91 | */ 92 | "autorefresh": { 93 | "enabled": false, 94 | "interval": 5000 95 | }, 96 | 97 | /* 98 | Show a clickable breadcrumb. 99 | */ 100 | "crumb": { 101 | "enabled": true 102 | }, 103 | 104 | /* 105 | Allow customized header and footer files. 106 | First checks for files "_h5ai.header.html" and "_h5ai.footer.html" in the current directory. 107 | If not successful it checks all parent directories (starting in the current directory) for 108 | files "_h5ai.headers.html" and "_h5ai.footers.html". 109 | Note the different filenames: "header" (only current) - "headers" (current and sub directories)! 110 | The file's content will be placed inside a
tag above/below the main content. 111 | If a file's extension is ".md" instead of ".html" its content will be interpreted as markdown. 112 | 113 | - stopSearchingAtRoot: boolean, only search for header and footer files until the web root 114 | directory. if `false`, will search for header/footer up the entire directory structure, 115 | even above the web root 116 | */ 117 | "custom": { 118 | "enabled": true, 119 | "stopSearchingAtRoot": true 120 | }, 121 | 122 | /* 123 | Enable packaged download of selected entries. 124 | To select files the "select"-extension needs to be enabled. 125 | 126 | - type: string, "php-tar", "shell-tar" or "shell-zip" 127 | - packageName: string, basename of the download package, null for current filename or foldername 128 | - alwaysVisible: boolean, always show download button (defaults to download the current folder) 129 | */ 130 | "download": { 131 | "enabled": true, 132 | "type": "php-tar", 133 | "packageName": null, 134 | "alwaysVisible": false 135 | }, 136 | 137 | /* 138 | Allow filtering the displayed files and folders in current folder. 139 | Checks for substrings. 140 | 141 | If advanced is enabled it checks entries for right order of characters, 142 | i.e. "ab" matches "ab", "axb", "xaxbx" but not "ba". Space separated 143 | sequences get OR-ed. Searches will be treated as JavaScript regular 144 | expressions if you prefix them with "re:". 145 | 146 | - advanced: boolean, use advanced pattern parsing 147 | - debounceTime: number, debounce wait time in milliseconds 148 | - ignorecase: boolean, ignore case 149 | */ 150 | "filter": { 151 | "enabled": false, 152 | "advanced": true, 153 | "debounceTime": 100, 154 | "ignorecase": true 155 | }, 156 | 157 | /* 158 | Calc the size of folders. 159 | This operation is real slow. The calculated sizes differ slightly for both 160 | calculation types since "php" only adds the file size, while "shell-du" 161 | also adds the sizes for the actual folder files. 162 | 163 | - type: string, "php" (sloooow) or "shell-du" (sloow) 164 | */ 165 | "foldersize": { 166 | "enabled": true, 167 | "type": "php" 168 | }, 169 | 170 | /* 171 | Adds Google Universial Analytics asynchronous tracking code. 172 | see: https://developers.google.com/analytics/devguides/collection/analyticsjs/ 173 | 174 | - id: string, account ID 175 | */ 176 | "google-analytics-ua": { 177 | "enabled": false, 178 | "id": "UA-000000-0" 179 | }, 180 | 181 | /* 182 | Enable a generic info side bar. 183 | 184 | - show: boolean, initial visible to first time users 185 | - qrcode: boolean, show a QR-Code 186 | - qrColor: string, QR-Code fill color 187 | */ 188 | "info": { 189 | "enabled": true, 190 | "show": false, 191 | "qrcode": true, 192 | "qrFill": "#999", 193 | "qrBack": "#fff" 194 | }, 195 | 196 | /* 197 | Localization, for example "en", "de" etc. - see "_h5ai/conf/l10n" folder for 198 | possible values. Adjust it to your needs. If lang is not found 199 | it defaults to "en". 200 | 201 | - lang: string, default language 202 | - useBroserLang: boolean, try to use browser language 203 | */ 204 | "l10n": { 205 | "enabled": true, 206 | "lang": "en", 207 | "useBrowserLang": true 208 | }, 209 | 210 | /* 211 | Adds Piwik tracker javascript code. 212 | 213 | - baseURL: string, do not include the protocol, e.g. "mydomain.tld/piwik" 214 | - idSite: number 215 | */ 216 | "piwik-analytics": { 217 | "enabled": false, 218 | "baseURL": "some/url", 219 | "idSite": 1 220 | }, 221 | 222 | /* 223 | Play a audio preview on click. 224 | 225 | - autoplay: start playing as soon as ready 226 | - types: array of strings 227 | */ 228 | "preview-aud": { 229 | "enabled": true, 230 | "autoplay": true, 231 | "types": ["aud"] 232 | }, 233 | 234 | /* 235 | Show an image preview on click. 236 | 237 | - types: array of strings 238 | - size: number, sample size, or false for original size 239 | */ 240 | "preview-img": { 241 | "enabled": true, 242 | "size": false, 243 | "types": ["img", "img-bmp", "img-gif", "img-ico", "img-jpg", "img-png", "img-raw", "img-svg"] 244 | }, 245 | 246 | /* 247 | Show text file preview on click. 248 | 249 | Available styles are: 250 | 0: floating text 251 | 1: fixed width text 252 | 2: markdown 253 | 3: syntax highlighting 254 | 255 | - styles: dict string to int, maps types to styles 256 | */ 257 | "preview-txt": { 258 | "enabled": true, 259 | "styles": { 260 | "txt": 1, 261 | "txt-authors": 1, 262 | "txt-c": 3, 263 | "txt-cpp": 3, 264 | "txt-css": 3, 265 | "txt-diff": 1, 266 | "txt-go": 3, 267 | "txt-h": 3, 268 | "txt-hpp": 3, 269 | "txt-install": 1, 270 | "txt-js": 3, 271 | "txt-json": 3, 272 | "txt-less": 3, 273 | "txt-license": 1, 274 | "txt-log": 1, 275 | "txt-makefile": 1, 276 | "txt-md": 2, 277 | "txt-py": 3, 278 | "txt-rb": 3, 279 | "txt-readme": 1, 280 | "txt-rtf": 1, 281 | "txt-rust": 3, 282 | "txt-script": 3, 283 | "txt-xml": 1 284 | } 285 | }, 286 | 287 | /* 288 | Play a video preview on click. 289 | 290 | - autoplay: start playing as soon as ready 291 | - types: array of strings 292 | */ 293 | "preview-vid": { 294 | "enabled": true, 295 | "autoplay": true, 296 | "types": ["vid-avi", "vid-flv", "vid-mkv", "vid-mov", "vid-mp4", "vid-mpg", "vid-webm"] 297 | }, 298 | 299 | /* 300 | Allow searching files and folders in and below current folder. 301 | Checks for substrings. 302 | 303 | If advanced is enabled it checks entries for right order of characters, 304 | i.e. "ab" matches "ab", "axb", "xaxbx" but not "ba". Space separated 305 | sequences get OR-ed. Searches will be treated as JavaScript regular 306 | expressions if you prefix them with "re:". 307 | 308 | - advanced: boolean, use advanced pattern parsing 309 | - debounceTime: number, debounce wait time in milliseconds 310 | - ignorecase: boolean, ignore case 311 | */ 312 | "search": { 313 | "enabled": false, 314 | "advanced": true, 315 | "debounceTime": 300, 316 | "ignorecase": true 317 | }, 318 | 319 | /* 320 | Make entries selectable. 321 | At the moment only needed for packaged download. 322 | 323 | - clickndrag: boolean, allow first mouse button + drag selection 324 | - checkboxes: boolean, show a checkbox on mouse over item 325 | */ 326 | "select": { 327 | "enabled": true, 328 | "clickndrag": true, 329 | "checkboxes": true 330 | }, 331 | 332 | /* 333 | Default sort order. 334 | "column" and "reverse" are locally stored. 335 | 336 | - column: number, 0 for "Name", 1 for "Date", 2 for "Size" 337 | - reverse: boolean, false for ascending, true for descending 338 | - ignorecase: boolean, compare ignorecase 339 | - natural: boolean, use natural sort order 340 | - folders: number, where to place folders, 0 for "top", 1 for "in place", 2 for "bottom" 341 | */ 342 | "sort": { 343 | "enabled": true, 344 | "column": 0, 345 | "reverse": false, 346 | "ignorecase": true, 347 | "natural": true, 348 | "folders": 0 349 | }, 350 | 351 | /* 352 | Show thumbnails for image files. Needs the "/_h5ai/public/cache" folder to be 353 | writable for the web Server. 354 | 355 | - img: array of strings 356 | - mov: array of strings 357 | - doc: array of strings 358 | - delay: number, delay in milliseconds after "dom-ready" before thumb-requesting starts 359 | - size: number, size in pixel of the generated thumbnails 360 | - exif: boolean, use included EXIF thumbs if possible 361 | - chunksize: int, number of thumbs per request 362 | */ 363 | "thumbnails": { 364 | "enabled": true, 365 | "img": ["img-bmp", "img-gif", "img-ico", "img-jpg", "img-png"], 366 | "mov": ["vid-avi", "vid-flv", "vid-mkv", "vid-mov", "vid-mp4", "vid-mpg", "vid-webm"], 367 | "doc": ["x-pdf", "x-ps"], 368 | "delay": 1, 369 | "size": 240, 370 | "exif": false, 371 | "chunksize": 20 372 | }, 373 | 374 | /* 375 | Replace window title with current breadcrumb. 376 | */ 377 | "title": { 378 | "enabled": true 379 | }, 380 | 381 | /* 382 | Show a folder tree. 383 | Note that this might affect performance significantly. 384 | 385 | - show: boolean, initial visible to first time users 386 | - maxSubfolders: number, max number of subfolders to show in tree 387 | - naturalSort: boolean, use natural sort order for folders 388 | - ignorecase: boolean, sort ignorecase 389 | */ 390 | "tree": { 391 | "enabled": true, 392 | "show": true, 393 | "maxSubfolders": 50, 394 | "naturalSort": true, 395 | "ignorecase": true 396 | } 397 | } 398 | -------------------------------------------------------------------------------- /config/_h5ai/CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | 4 | * now require PHP 7.0.0+ 5 | * fix archive-single-item problem 6 | * add header/footer search stop condition 7 | * update languages (`id`, `it`, `pt-br`, `pt-pt`) 8 | * add EXIF-based image rotation 9 | * add `where` to command detection command list 10 | * fix #758 11 | * fix #760 12 | * add `@babel/core` 7.12.10 13 | * add `@babel/preset-env` 7.12.11 14 | * remove `babel-loader` 15 | * update `eslint` to 7.18.0 16 | * update `ghu` to 0.26.0 17 | * update `jsdom` to 16.4.0 18 | * update `kjua` to 0.9.0 19 | * update `lolight` to 1.4.0 20 | * update `marked` to 1.2.7 21 | * update `null-loader` to 4.0.1 22 | * update `scar` to 2.3.0 23 | 24 | 25 | ## v0.29.2 - *2019-03-22* 26 | 27 | * update `babel-loader` to 7.1.1 28 | * update `eslint` to 5.15.3 29 | * update `ghu` to 0.13.0 30 | * update `jsdom` to 14.0.0 31 | * update `kjua` to 0.2.0 32 | * update `lolight` to 1.0.0 33 | * update `scar` to 1.2.0 34 | 35 | 36 | ## v0.29.1 - *2019-01-20* 37 | 38 | * replace `babel-preset-es2015` with `babel-preset-env` 39 | * update `eslint` to 5.14.1 40 | * update `ghu` to 0.12.0 41 | * update `jsdom` to 9.2.0 42 | * update `kjua` to 0.1.2 43 | * update `lolight` to 0.6.0 44 | * update `marked` to 0.6.1 45 | * update `normalize.css` to 8.0.1 46 | * update `scar` to 1.0.0 47 | 48 | 49 | ## v0.29.0 - *2016-08-12* 50 | 51 | * back to cleaner visual experience 52 | * add option to disable sidebar 53 | * add options to filter/search ignore case 54 | * replace PHP `getenv` calls with `$_SERVER` lookups 55 | * add `view.fallbackMode` option to generally serve only fallback mode 56 | * serve fallback mode for text browsers (`curl`, `links`, `lynx`, `w3m`) 57 | * change type `txt-svg` to `img-svg`, no thumbs but preview 58 | * fix a tree indentation glitch 59 | * fix shell command detection on Windows 60 | * fix Piwik anayltics 61 | * fix `.htaccess` auth issues 62 | * fix drag-select on scrollable content 63 | * fix download-all function 64 | * fix audio and video preview loading 65 | * fix thumbnail request issues 66 | * add `rust` type and icon 67 | * add `autoplay` option to audio and video preview 68 | * add `--dereference` to `shell-du` to follow sym links 69 | * remove *Install* section from `README.md`, causes too much trouble 70 | * remove peer5 support 71 | * update build process to use `node 6.0+`, no need for babel now 72 | * replace `jquery-qrcode` with [`kjua`](https://larsjung.de/kjua/) 73 | * replace `prism` with [`lolight`](https://larsjung.de/lolight/) 74 | * move deps to `package.json` (`normalize.css`, `kjua`, `lolight` and `marked`) 75 | * remove `jQuery` 76 | * remove `lodash` 77 | * remove [`modulejs`](https://larsjung.de/modulejs/) for now 78 | * reduce JS code by 60% (~250kb -> ~100kb) 79 | * update languages (`et`, `nl`, `pl`) 80 | 81 | 82 | ## v0.28.0 - *2015-12-19* 83 | 84 | * now require PHP 5.5.0+ 85 | * change index path to `/_h5ai/public/index.php` 86 | * now only `/_h5ai/public/` needs to be web-accessible 87 | * add support for custom script and style additions 88 | * add options to set font families 89 | * add search 90 | * add ignorecase sorting option to tree 91 | * add wide links in tree view 92 | * add IE edge mode 93 | * add frontend tests 94 | * fix some styles in IE10 95 | * fix preview bottom bar for small screen widths 96 | * lots of code cleanup and refactorings 97 | * change API 98 | * update build process, now uses [`ghu`](https://larsjung.de/ghu/) 99 | * switch from jshint and jscs to [`eslint`](http://eslint.org/) 100 | * update `jQuery` to 2.1.4 101 | * update `lodash` to 3.9.3 (add debounce and trim) 102 | * update `marked` to 0.3.5 103 | * update `modulejs` to 1.13.0 104 | * update `prism` to 2015-12-19 105 | * update h5bp styles to 5.2.0 106 | * update `normalize.css` to 3.0.3 107 | * remove `Moment.js` 108 | 109 | 110 | ## v0.27.0 - *2015-04-06* 111 | 112 | * new layout 113 | * add editorconfig 114 | * drop support for IE9 (gets fallback) 115 | * update sidebar settings 116 | * add info sidebar 117 | * add opt-out for click'n'drag selection 118 | * add package name option for single selections 119 | * add initial support for Peer5 120 | * add option to down-sample images for preview 121 | * add option for natural sorting in tree sidebar 122 | * fix problems with files/folders named `0` 123 | * change font from `Ubuntu` to `Roboto` (smaller footprint, clearer for small sizes) 124 | * switch back to Google Fonts 125 | * improve PDF thumbnail quality 126 | * improve drag-select 127 | * improve image preview 128 | * prevent listing `_h5ai` folder and subfolders 129 | * update build process, now uses [`mkr`](https://larsjung.de/mkr/) and [`fQuery`](https://larsjung.de/fquery/) 130 | * update `jQuery` to 2.1.3 131 | * update `jQuery.qrcode` to 0.11.0 132 | * update `Lo-Dash` to 3.6.0 133 | * update `Modernizr` to 2.8.3 134 | * update `modulejs` to 1.4.0 135 | * update `Moment.js` to 2.9.0 136 | * update `Prism` to 2015-04-05 137 | * remove deprecated Google Analytics code 138 | * remove `jQuery.fracs` 139 | * remove `jQuery.scrollpanel` 140 | * remove `jQuery.mousewheel` 141 | * update languages (`af`, `es`, `ja`, `ko`, `ru`, `zh-cn`) 142 | 143 | 144 | ## v0.26.1 - *2014-08-17* 145 | 146 | * fix links 147 | 148 | 149 | ## v0.26.0 - *2014-08-16* 150 | 151 | * remove True Type fonts 152 | * outsource themes to [h5ai-themes](https://github.com/lrsjng/h5ai-themes) 153 | * add filesize fallback for large files and 32bit PHP 154 | * fix server detection 155 | * add config file tests to info page 156 | * remove JSON shim 157 | * add caching of command checks 158 | * update `jQuery.mousewheel` to 3.1.12 159 | * update `jQuery.qrcode` to 0.8.0 160 | * replace `markdown` with [`marked`](https://github.com/chjj/marked) 0.3.2 161 | * update `modulejs` to 0.4.5 162 | * update `Moment.js` to 2.8.1 163 | * replace `underscore` with [`Lo-Dash`](https://github.com/lodash/lodash) 2.4.1 164 | * replace `SyntaxHighlighter` with [`Prism`](http://prismjs.com) 2014-08-04 165 | 166 | 167 | ## v0.25.2 - *2014-07-01* 168 | 169 | * add optional info page protection 170 | * fix `short_open_tag` issues for PHP < 5.4.0 171 | * fix default folder download (`alwaysVisible` option) 172 | * minor fixes 173 | 174 | 175 | ## v0.25.1 - *2014-06-25* 176 | 177 | * fix broken paths for filenames containing '+' characters 178 | * fix Google Universal Analytics 179 | * fix file type check 180 | 181 | 182 | ## v0.25.0 - *2014-06-22* 183 | 184 | * add sidebar 185 | * add initial theme support 186 | * add icons from [Evolvere Icon Theme](http://franksouza183.deviantart.com/art/Evolvere-Icon-theme-440718295) 187 | * add PHP variant to calc folder sizes 188 | * add scroll position reset on location change (issue [#279](https://github.com/lrsjng/h5ai/issues/279)) 189 | * add option to hide unreadable files 190 | * add option where to place folders (top, inplace, bottom) 191 | * add markdown support for custom header and footer files 192 | * add video and audio preview via HTML5 elements (no fallback, works best in Chrome) 193 | * add filter reset on location change 194 | * add option to make download button always visible 195 | * add Google UA support 196 | * extend selectable icon sizes (add 128px, 192px, 256px, 384px) 197 | * improve preview GUI 198 | * disable thumbs in `cache` folder 199 | * fix QR code URI origin (issue [#287](https://github.com/lrsjng/h5ai/issues/287)) 200 | * replace PHP backtick operator with `exec` 201 | * remove server side file manipulation extensions `dropbox`, `delete` and `rename` 202 | * update `H5BP` to 4.3.0 203 | * update `jQuery` to 2.1.1 204 | * update `json2.js` to 2014-02-04 205 | * update `markdown-js` to 0.5.0 206 | * update `Modernizr` to 2.8.2 207 | * update `Moment.js` to 2.6.0 208 | * update `Underscore.js` to 1.6.0 209 | * update languages (`bg`, `ko`, `pt`, `sl`, `sv`, `zh-cn`) 210 | 211 | 212 | ## v0.24.1 - *2014-04-09* 213 | 214 | * security fixes! (issues [#268](https://github.com/lrsjng/h5ai/issues/268), [#269](https://github.com/lrsjng/h5ai/issues/269)) 215 | * fix WinOS command detection 216 | * update languages (`fi`, `fr`, `hi`, `it`, `zh-tw`) 217 | 218 | 219 | ## v0.24.0 - *2013-09-04* 220 | 221 | * updates image and text preview 222 | * adds variable icon sizes 223 | * adds optional natural sort of items 224 | * adds optional checkboxes to select items 225 | * adds text preview modes: none, fixed, markdown 226 | * optionally hide folders in main view 227 | * makes use of EXIF thumbnails optional 228 | * fixes file deletion of multiple files 229 | * fixes `setParentFolderLabels = false` 230 | * fixes shell-arg and RegExp escape issues 231 | * cleans code 232 | * updates info page `/_h5ai` 233 | * adds `aiff` to `audio` types 234 | * adds `da` translation by Ronnie Milbo 235 | * updates to `pl` translation by Mark 236 | 237 | 238 | ## v0.23.0 - *2013-07-21* 239 | 240 | * removes `aai` mode! 241 | * drops support for IE7+8 (simple fallback, same as no javascript) 242 | * uses History API if available (way faster browsing) 243 | * faster thumbnail generation if EXIF thumbnails available 244 | * adds optional custom headers/footers that are propageted to all subfolders 245 | * optional hide parent folder links 246 | * some fixes on previews 247 | * speeds up packaged downloads 248 | * add line wrap and line highlighting (on hover) to text preview 249 | * new design (colors, images) 250 | * now uses scalable images for the interface 251 | * fixes filter (ignore parent folder, display of `no match`) 252 | * lots of small fixes 253 | * updates `H5BP` to 4.2.0 254 | * updates `jQuery` to 2.0.3 255 | * updates `jQuery.mousewheel` to 3.1.3 256 | * updates `Moment.js` to 2.1.0 257 | * updates `markdown-js` to 0.4.0-9c21acdf08 258 | * updates `json2.js` to 2013-05-26 259 | * adds `uk` translation by Viktor Matveenko 260 | * updates to `pl` translation by Mark 261 | 262 | 263 | ## v0.22.1 - *2012-10-16* 264 | 265 | * bug fix concerning API requests in PHP mode 266 | * minor changes in responsive styles 267 | 268 | 269 | ## v0.22 - *2012-10-14* 270 | 271 | * general changes h5ai directory layout and configuration 272 | * splits configuration file (`config.json`) into files `options.json`, `types.json` and `langs.json` 273 | * localization now in separate files 274 | * adds auto-refresh 275 | * adds drag'n'drop upload (PHP, experimental) 276 | * adds file deletion (PHP, experimental) 277 | * cleans and improves PHP code 278 | * PHP no longer respects htaccess restrictions (so be careful) 279 | * PHP ignore patterns might include paths now 280 | * improves separation between aai and php mode 281 | * improves performance in aai mode 282 | * adds optional binary prefixes for file sizes 283 | * improves filter: autofocus on keypress, clear on `ESC` 284 | * download packages now packaged relative to current folder 285 | * download package name changable 286 | * splits type `js` into `js` and `json` 287 | * prevents some errors with files > 2GB on 32bit OS 288 | * adds max subfolder size in tree view 289 | * adds ctrl-click file selection 290 | * adds Piwik analytics extension 291 | * temp download packages are now stored in the `cache`-folder and deleted as soon as possible 292 | * updates translations 293 | * adds `he` translation by [Tomer Cohen](https://github.com/tomer) 294 | * updates 3rd party libs 295 | 296 | 297 | ## v0.21 - *2012-08-06* 298 | 299 | * fixes misaligned image previews 300 | * adds no JavaScript fallback to PHP version 301 | * fixes duplicate tree entries and empty main views 302 | * adds Google Analytics support (async) 303 | * improves filter (now ignorecase, now only checks if chars in right order) 304 | * adds keyboard support to image preview (space, enter, backspace, left, right, up, down, f, esc) 305 | * adds text file preview and highlighting with [SyntaxHighlighter](http://alexgorbatchev.com/SyntaxHighlighter/) (same keys as img preview) 306 | * adds Markdown preview with [markdown-js](https://github.com/evilstreak/markdown-js) 307 | * adds new type `markdown` 308 | * changes language code `gr` to `el` 309 | * adds localization for filter placeholder 310 | * adds `hu` translation by [Rodolffo](https://github.com/Rodolffo) 311 | * updates to [jQuery.qrcode](https://larsjung.de/qrcode/) 0.2 312 | * updates to [jQuery.scrollpanel](https://larsjung.de/scrollpanel/) 0.1 313 | * updates to [modulejs](https://larsjung.de/modulejs/) 0.2 314 | * updates to [Moment.js](http://momentjs.com) 1.7.0 315 | * updates to [Underscore.js](http://underscorejs.org) 1.3.3 316 | 317 | 318 | ## v0.20 - *2012-05-11* 319 | 320 | * adds image preview 321 | * adds thumbnails for video and pdf 322 | * adds support for lighttpd, nginx and cherokee and maybe other webservers with PHP 323 | * adds folder size in PHP version via shell `du` 324 | * fixes some localization problems 325 | * updates info page at `/_h5ai/` 326 | * switches to JSHint 327 | 328 | 329 | ## v0.19 - *2012-04-19* 330 | 331 | * adds lots of config options 332 | * changes in `config.js` and `h5ai.htaccess` 333 | * fixes js problems in IE 7+8 334 | * hides broken tree view in IE < 9, adds a message to the footer 335 | * removes hash changes since they break logical browser history 336 | * fixes thumbnail size for portrait images in icon view 337 | * fixes problems with file type recognition 338 | * adds an info page at `/_h5ai/` 339 | * sort order is preserved while browsing 340 | * removes PHP error messages on thumbnail generation 341 | * fixes PHP some problems with packed download 342 | * adds support for tarred downloads 343 | * changes crumb image for folders with an index file 344 | * adds `index.php` to use h5ai in non-Apache environments 345 | * switches from [Datejs](http://www.datejs.com) to [Moment.js](http://momentjs.com) 346 | * adds [underscore.js](http://underscorejs.org) 347 | * fixes mousewheel problems, updates [jQuery.mousewheel](https://github.com/brandonaaron/jquery-mousewheel) to 3.0.6 348 | * updates `lv` translation 349 | * adds `ro` translation by [Jakob Cosoroabă](https://github.com/midday) 350 | * adds `ja` translation by [metasta](https://github.com/metasta) 351 | * adds `nb` translation by [Sindre Sorhus](https://github.com/sindresorhus) 352 | * adds `sr` translation by [vBm](https://github.com/vBm) 353 | * adds `gr` translation by [xhmikosr](https://github.com/xhmikosr) 354 | 355 | 356 | ## v0.18 - *2012-02-24* 357 | 358 | * adds optional QRCode display 359 | * adds optional filtering for displayed files and folders 360 | * updates design 361 | * improves zipped download 362 | * adds support for zipped download of htaccess restricted files 363 | * changes h5ai.htaccess 364 | * custom headers/footers are now optional and disabled by default 365 | * fixes problems with folder recognition in the JS version 366 | * fixes include problems in PHP version 367 | * fixes path problems on servers running on Windows in PHP version 368 | * fixes broken links in custom headers/footers while zipped download enabled 369 | * fixes problems with thumbnails for files with single or double quotes in filename 370 | * improves url hashes 371 | * updates year in `LICENSE.TXT` 372 | * updates es translation 373 | * adds `zh-tw` translation by [Yao Wei](https://github.com/medicalwei) 374 | * updates `zh-cn` translation 375 | 376 | 377 | ## v0.17 - *2011-11-28* 378 | 379 | * h5ai is now located in `_h5ai` to reduce collisions 380 | * switches from HTML5 Boilerplate reset to normalization 381 | * adds some style changes for small devices 382 | * configuration (options, types, translations) now via `config.js` 383 | * icons for JS version are now configured via `config.js` 384 | * sort order configuration changed 385 | * sorting is now done without page reload 386 | * adds `customHeader` and `customFooter` to `config.js` 387 | * supports restricted folders to some extent 388 | * some style changes on tree and language menu 389 | * fixes total file/folder count in status bar 390 | * adds support for use with userdir (requires some manual changes) 391 | 392 | 393 | ## v0.16 - *2011-11-02* 394 | 395 | * sorts translations in `options.js` 396 | * improves HTML head sections 397 | * refactors JavaScript and PHP a lot 398 | * improves/fixes file selection for zipped download 399 | * fixes scrollbar and header/footer link issues (didn't work when zipped download enabled) 400 | * adds support for ctrl-select 401 | * `dateFormat` in `options.js` changed, now affecting JS and PHP version 402 | * `dateFormat` is localizable by adding it to a translation in `options.js` 403 | * PHP version is now configurable via `php/config.php` (set custom doc root and other PHP related things) 404 | * image thumbs and zipped download is disabled by default now, but works fine if PHP is configured 405 | 406 | 407 | ## v0.15.2 - *2011-09-18* 408 | 409 | * adds `it` translation by [Salvo Gentile](https://github.com/SalvoGentile) and [Marco Patriarca](https://github.com/Fexys) 410 | * switches build process from scripp to wepp 411 | 412 | 413 | ## v0.15.1 - *2011-09-06* 414 | 415 | * fixes security issues with the zipped download feature 416 | * makes zipped download optional (but enabled by default) 417 | 418 | 419 | ## v0.15 - *2011-09-04* 420 | 421 | * adds zipped download for selected files 422 | * cleans and refactores 423 | 424 | 425 | ## v0.14.1 - *2011-09-01* 426 | 427 | * display meta information in bottom bar (icon view) 428 | * adds `zh-cn` translation by [Dongsheng Cai](https://github.com/dongsheng) 429 | * adds `pl` translation by Radosław Zając 430 | * adds `ru` translation by Богдан Илюхин 431 | 432 | 433 | ## v0.14 - *2011-08-16* 434 | 435 | * adds image thumbnails for PHP version 436 | * new option `slideTree` to turn off auto slide in 437 | 438 | 439 | ## v0.13.2 - *2011-08-12* 440 | 441 | * changes in `/h5ai/.htaccess` ... PHP configuration ... 442 | 443 | 444 | ## v0.13.1 - *2011-08-12* 445 | 446 | * fixes initial tree display 447 | * adds sort order option 448 | * adds/fixes some translations 449 | * adds `lv` translation by Sandis Veinbergs 450 | 451 | 452 | ## v0.13 - *2011-08-06* 453 | 454 | * adds PHP implementation! (should work with PHP 5.2+) 455 | * adds new options 456 | * changes layout of the bottom bar to display status information 457 | * adds language selector to the bottom bar 458 | * quotes keys in `options.js` to make it valid json 459 | * changes value of option `lang` from `undefined` to `null` 460 | * adds some new keys to `h5aiLangs` 461 | * adds browser caching rules for css and js 462 | * adds `pt` translation by [Jonnathan](https://github.com/jonnsl) 463 | * adds `bg` translation by George Andonov 464 | 465 | 466 | ## v0.12.3 - *2011-07-30* 467 | 468 | * adds `tr` translation by [Batuhan Icoz](https://github.com/batuhanicoz) 469 | 470 | 471 | ## v0.12.2 - *2011-07-30* 472 | 473 | * adds `es` translation by Jose David Calderon Serrano 474 | 475 | 476 | ## v0.12.1 - *2011-07-29* 477 | 478 | * fixes unchecked use of console.log 479 | 480 | 481 | ## v0.12 - *2011-07-28* 482 | 483 | * improves performance 484 | 485 | 486 | ## v0.11 - *2011-07-27* 487 | 488 | * changes license to MIT license, see `LICENSE.txt` 489 | 490 | 491 | ## v0.10.2 - *2011-07-26* 492 | 493 | * improves tree scrollbar 494 | 495 | 496 | ## v0.10.1 - *2011-07-24* 497 | 498 | * fixes problems with ' in links 499 | 500 | 501 | ## v0.10 - *2011-07-24* 502 | 503 | * fixes problems with XAMPP on Windows (see `dot.htaccess` comments for instructions) 504 | * fixes tree fade-in-fade-out effect for small displays ([issue #6](https://github.com/lrsjng/h5ai/issues/6)) 505 | * adds custom scrollbar to tree ([issue #6](https://github.com/lrsjng/h5ai/issues/6)) 506 | * fixes broken links caused by URI encoding/decoding ([issue #9](https://github.com/lrsjng/h5ai/issues/9)) 507 | * adds "empty" to localization (hope Google Translate did a good job here) 508 | 509 | 510 | ## v0.9 - *2011-07-18* 511 | 512 | * links hover states between crumb, extended view and tree 513 | * fixes size of tree view (now there's a ugly scrollbar, hopefully will be fixed) 514 | * refactores js to improve performance and cleaned code 515 | * adds caching for folder status codes and content 516 | * adds `fr` translation by [Nicolas](https://github.com/Nicosmos) 517 | * adds `nl` translation by [Stefan de Konink](https://github.com/skinkie) 518 | * adds `sv` translation by Oscar Carlsson 519 | 520 | 521 | ## v0.8 - *2011-07-08* 522 | 523 | * removes slashes from folder labels 524 | * optionally rename parent folder entries to real folder names, see `options.js` 525 | * long breadcrumbs (multiple rows) no longer hide content 526 | * error folder icons are opaque now 527 | * refactores js a lot (again...) 528 | 529 | 530 | ## v0.7 - *2011-07-07* 531 | 532 | * removes shadows 533 | * smarter tree side bar 534 | 535 | 536 | ## v0.6 - *2011-07-05* 537 | 538 | * refactores js 539 | * adds localization, see `options.js` 540 | 541 | 542 | ## v0.5.3 - *2011-07-04* 543 | 544 | * refactores js 545 | * adds basic options support via `options.js` 546 | * adds comments to `options.js` 547 | * adds optional tree sidebar 548 | 549 | 550 | ## v0.5.2 - *2011-07-02* 551 | 552 | * details view adjusts to window width 553 | * links icon for *.gz and *.bz2 554 | 555 | 556 | ## v0.5.1 - *2011-07-01* 557 | 558 | * disables tree sidebar for now, since it had unwanted side effects 559 | 560 | 561 | ## v0.5 - *2011-07-01* 562 | 563 | * adds tree sidebar 564 | * some refactorings 565 | 566 | 567 | ## v0.4 - *2011-06-27* 568 | 569 | * adds better fallback, in case JavaScript is disabled 570 | * rewrites js, fixed middle-button click etc. problems 571 | * refactors css 572 | * sorts, adds and moves icons and images 573 | * updates dot.access 574 | 575 | 576 | ## v0.3.2 - *2011-06-24* 577 | 578 | * removes lib versions from file names 579 | * adds 'empty' indicator for icons view 580 | 581 | 582 | ## v0.3.1 - *2011-06-24* 583 | 584 | * refactores js 585 | * adds `folderClick` and `fileClick` callback hooks 586 | * fixes .emtpy style 587 | 588 | 589 | ## v0.3 - *2011-06-23* 590 | 591 | * includes build stuff, files previously found in the base directory are now located in folder `target` 592 | * styles and scripts are now minified 593 | * adds Modernizr 2.0.4 for future use 594 | * updates jQuery to version 1.6.1 595 | 596 | 597 | ## v0.2.3 - *2011-06-17* 598 | 599 | * more refactoring in main.js 600 | 601 | 602 | ## v0.2.2 - *2011-06-16* 603 | 604 | * refactores a lot, adds some comments 605 | * includes fixes from [NumEricR](https://github.com/NumEricR) 606 | * adds top/bottom message support, only basicly styled 607 | 608 | 609 | ## v0.2.1 - *2011-06-16* 610 | 611 | * fixes croped filenames 612 | * fixes missing .png extension in header 613 | * adds some color to the links 614 | * adds changelog 615 | 616 | 617 | ## v0.2 - *2011-06-15* 618 | 619 | * adds icon view 620 | --------------------------------------------------------------------------------