{"id":22226149,"url":"https://github.com/kivagant/staticus","last_synced_at":"2025-03-25T08:28:09.124Z","repository":{"id":57007149,"uuid":"59917969","full_name":"KIVagant/staticus","owner":"KIVagant","description":"HTTP-based file proxy and file manager with the REST API","archived":false,"fork":false,"pushed_at":"2017-03-29T09:35:03.000Z","size":309,"stargazers_count":1,"open_issues_count":1,"forks_count":0,"subscribers_count":3,"default_branch":"master","last_synced_at":"2025-01-30T07:43:04.371Z","etag":null,"topics":["api-service","file","file-manager","filemanager","filesystem","generator"],"latest_commit_sha":null,"homepage":"","language":"PHP","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/KIVagant.png","metadata":{"files":{"readme":"Readme.md","changelog":null,"contributing":"CONTRIBUTING.md","funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2016-05-28T23:07:32.000Z","updated_at":"2017-03-16T10:59:05.000Z","dependencies_parsed_at":"2022-08-21T14:30:55.638Z","dependency_job_id":null,"html_url":"https://github.com/KIVagant/staticus","commit_stats":null,"previous_names":[],"tags_count":10,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/KIVagant%2Fstaticus","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/KIVagant%2Fstaticus/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/KIVagant%2Fstaticus/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/KIVagant%2Fstaticus/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/KIVagant","download_url":"https://codeload.github.com/KIVagant/staticus/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":245425428,"owners_count":20613164,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["api-service","file","file-manager","filemanager","filesystem","generator"],"created_at":"2024-12-03T00:23:40.757Z","updated_at":"2025-03-25T08:28:09.088Z","avatar_url":"https://github.com/KIVagant.png","language":"PHP","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Staticus\n\nApplication:\n[![Build Status](https://scrutinizer-ci.com/g/KIVagant/staticus/badges/build.png)](https://scrutinizer-ci.com/g/KIVagant/staticus/build-status/master)\n[![Scrutinizer Code Quality](https://scrutinizer-ci.com/g/KIVagant/staticus/badges/quality-score.png)](https://scrutinizer-ci.com/g/KIVagant/staticus/)\n[![Code Coverage](https://scrutinizer-ci.com/g/KIVagant/staticus/badges/coverage.png)](https://scrutinizer-ci.com/g/KIVagant/staticus/)\nCore:\n[![Build Status](https://scrutinizer-ci.com/g/KIVagant/staticus-core/badges/build.png)](https://scrutinizer-ci.com/g/KIVagant/staticus-core/build-status/master)\n[![Scrutinizer Code Quality](https://scrutinizer-ci.com/g/KIVagant/staticus-core/badges/quality-score.png)](https://scrutinizer-ci.com/g/KIVagant/staticus-core/)\n[![Code Coverage](https://scrutinizer-ci.com/g/KIVagant/staticus-core/badges/coverage.png)](https://scrutinizer-ci.com/g/KIVagant/staticus-core/)\n\nIn short: this [PSR-7](http://www.php-fig.org/psr/psr-7/) based service is an \"invisible\" layer, which dynamically looking for requested static files and tells to Nginx\nwhere they placed. \"Pipeline post-processing\", content generators and ACL support give to you a powerfull instrument\nfor a files management on your web-service.\n\nQuick example:\n\n```\n- POST https://www.your.project.dev/staticus/waxwing.mp3\n\u003e File will be generated (if you have access) and placed to path like ~/mp3/def/0/22af64.mp3\n\n- GET https://www.your.project.dev/staticus/waxwing.mp3\n\u003e The php-backend layer will be called once for the file path search, then file will be sended throught Nginx\n\n- GET https://www.your.project.dev/staticus/waxwing.mp3\n\u003e File will be returned from Nginx cache\n```\n\nThe service handles HTTP requests and gives\n[X-Accel-Redirect](https://www.nginx.com/resources/wiki/start/topics/examples/x-accel/) for Nginx,\nwhich will force the file downloading.\n\nDepending on the requested route the corresponding proxy layer is loaded, which refers to the providers to generate\ncontent, then caches the result and next time gives the file from cache.\n\nNginx internal cache should be configured for providing a maximum speed of repeated requests. Read the example below.\n\nWith Staticus you will can:\n\n- call HTTP CRUD operations for different static files on your project without hard integration work;\n- generate any file resources by request: images, sounds, documents etc;\n- resize and crop images 'on the fly' when it requested from your frontend;\n- search for the new images in Google;\n- write your own operation layers (middlewares) and make this instrument more powerful!\n\n## Dependencies\n\nRead [information about dependencies](Dependencies.md) used in the project.\n\n## Contents\n\n\u003c!---\nsee: https://github.com/aslushnikov/table-of-contents-preprocessor\nmd-toc-filter ./Readme.md \u003e Readme2.md\n--\u003e\n- [Staticus](#staticus)\n    - [Dependencies](#dependencies)\n    - [Contents](#contents)\n    - [Disclaimer](#disclaimer)\n    - [Installation and tests](#installation-and-tests)\n    - [The Nginx configuration](#the-nginx-configuration)\n    - [Query structure](#query-structure)\n    - [Supported HTTP Methods](#supported-http-methods)\n        - [Parameters](#parameters)\n            - [var: string, resource variant name](#var-string-resource-variant-name)\n            - [alt: string, alternative resource name](#alt-string-alternative-resource-name)\n            - [v: integer, version id](#v-integer-version-id)\n            - [DELETE destroy: bool, remove without backup](#delete-destroy-bool-remove-without-backup)\n            - [POST author: string, author](#post-author-string-author)\n            - [POST uri=http Upload image by remote URI](#post-urihttp-upload-image-by-remote-uri)\n    - [Path structure](#path-structure)\n    - [JPG Type](#jpg-type)\n        - [Special parameters](#special-parameters)\n            - [size=WxH, string, image dimension](#sizewxh-string-image-dimension)\n            - [filters[]=filtername, string, postprocessing filters](#filtersfiltername-string-postprocessing-filters)\n    - [MP3 Type](#mp3-type)\n        - [GET /*.mp3](#get-mp3)\n            - [First request (without cache)](#first-request-without-cache)\n            - [Second request (Nginx cache)](#second-request-nginx-cache)\n        - [POST /*.mp3](#post-mp3)\n            - [Creation](#creation)\n            - [Secondary creation](#secondary-creation)\n            - [Regeneration 1: Re-created file is identical to the existing](#regeneration-1-re-created-file-is-identical-to-the-existing)\n            - [Regeneration 2: The created file is a different](#regeneration-2-the-created-file-is-a-different)\n            - [File Uploading](#file-uploading)\n            - [File Remote Downloading](#file-remote-downloading)\n        - [DELETE /*.mp3](#delete-mp3)\n            - [Safety deletion](#safety-deletion)\n            - [Destroying](#destroying)\n    - [Advanced usage](#advanced-usage)\n        - [List all resource files](#list-all-resource-files)\n        - [JPG searching with the special route /search/](#jpg-searching-with-the-special-route-search)\n            - [Search example](#search-example)\n        - [HTTP-based authentication](#http-based-authentication)\n        - [Session-based authentication](#session-based-authentication)\n        - [Namespaces](#namespaces)\n    - [Contributors](#contributors)\n    - [License](#license)\n\n## Disclaimer\n\n- **Some parts of this readme still not translated**. If you can help with that – you are welcome with a PR.\n- Examples are shown by the utility [jkbrzt/httpie](https://github.com/jkbrzt/httpie).\n  Hint: if you see some unexpected html in your console, use [your-command | html2text](https://pypi.python.org/pypi/html2text)\n- All data operations such as reading, generation or deleting, controlled with the ACL config.\n\n## Installation and tests\n\nNotice: composer will run ```post-create-project-cmd````.\nAll distributive configuration files will be copied without replacing from their templates.\nIf you not trust to composer scripts, just add ```--no-scripts``` argument.\n\n1. This project works like ready-to-use application. So, you don't need to **require** it. Instead run:\n\n```\n$ composer create-project \"kivagant/staticus\"\n$ cd staticus\n```\n\n2. Open **.env** file for editing and setup the variables inside. First of all, **do not forget to setup the DATA_DIR**!\n\n3. **Important note:** The next step will try to create and delete test files (in [AcceptanceTest](test/StaticusTest/Actions/Fractal/AcceptanceTest.php).\nSo, read the [License](#license), run and pray :)\n\n```\n$ composer run-script test\n\u003e phpunit\nPHPUnit 4.8.24 by Sebastian Bergmann and contributors.\n...\nOK (85 tests, 377 assertions)\n```\n\nThen you can run project without Nginx and works with it almost like in examples below. The only difference is that\nyou can't see any files in GET requests because the only X-Accel-Redirect header will be sent.\n\n```\n$ composer run-script serve\n```\n\nBut if you want to see a real dark magic, read the next part of this documentation.\n\n## The Nginx configuration\n\nLook for simple Nginx config example: [staticus.conf](etc/nginx/conf.d/staticus.conf)\n\nThe main host in Nginx proxies a request to the \"auxiliary host\" (at himself in reality) and caches a successful result:\n\n```\nproxy_pass http://127.0.0.1:8081;\n```\n\nAuxiliary Nginx-host proxies a request to the backend (Staticus php-project).\n\n```\nlocation / {\n    ...\n    include fastcgi_fpm.conf;\n}\n```\n\nBackend processes the request, looks for file or generates the new content and sends the\n[X-Accel-Redirect](https://www.nginx.com/resources/wiki/start/topics/examples/x-accel/),\nwhich tells Nginx, where to take the final file for downloading.\n\nNginx processes the route according to the internal location configuration and sends the result to the client.\n\n```\nlocation ~* ^/data/(img|voice)/(.+)\\.(jpg|jpeg|gif|png|mp3)$ {\n    internal;\n    ...\n}\n```\n\nFor the client, all looks like his just received a static file.\n\n## Query structure\n\nscheme:[//[user:password@]host[:port]][/path-to-home][/namespace/sub/namespace]/resource.type[?parameters]\n\n- **user:password**: HTTP-based authentication for the administrator role.\n- **path-to-home**: project can be located in the sub-route, this is should be taken into account,\n  creating the right URLs in the client Views.\n- **namespace**: logically grouped resources with separate ACL rules.\n  Every session-authorised user has own namespace ```/user/{id}```.\n- **resource**: basic short name of the resource. With the same address the same resource always will be returned.\n- **type**: the type of resource that guarantees the return file extension and mime-type.\n- **parameters**: some parameters is supported by default, but different types of resources can have their own parameters.\n  Parameters affect the returned data. Can be sent in query or in the POST body.\n\n## Supported HTTP Methods\n\n| Method | HTTP Statuses | Comment |\n|--------|---------------|---------|\n| GET | 404, 200 | Returns the resource data (which can be cached with Nginx) |\n| POST | 201, 304 | Once creates a resource on the specified route, unless the forcing re-creation will be requested |\n| DELETE | 204 | It removes the requested version of the resource or reports that the resource is not exists. |\n\nPUT is not supported.\n\n### Parameters\n\n#### var: string, resource variant name\n\nBy default the 'def' variant is used.\n\nFor some resources may need to store or generate different unique variants.\nFor example, a user can upload his own version of a resource or a resource can be generated in several variants.\n\n#### alt: string, alternative resource name\n\n*This parameter can be handled differently for different resource types.*\n\n*When you create a resource*, you can pass an alternative name.\n\nSometimes the main resource name is not enough to generate the correct data, or to ensure uniqueness.\nFor example, if the common short name is not fully describes the resource, or lacks length of a GET-request,\nor full name contains Unicode-characters etc.\n\nDepending on the resource type, an alternate name can be further processed or ignored.\nFor example, the alternative name will be used for voicing *instead of the common name*.\nAnd for the image searching – *along with the main name*.\n\nResources ```car.jpg```, ```car.jpg?alt=вагон``` and ```car.jpg?alt=машина``` considered as **different resources**.\nAlternative name will be used in the formation **uuid** resource together with the basic name.\n\n#### body: string, additional information for resource creation\n\nSometimes is not enough to use URI variables for resource creation.\nFor example, when you need to create some audio-file with uri: ```/my-audio.mp3``` with a big text (for voicing) inside,\nyou can send the body argument through HTTP POST body. The resource will have short url (without alt=...) and,\nin the same time, correct long data inside.\n\n#### v: integer, version id\n\nEach version of a resource contains its own version.\nBy **default the 0 version** used (and v=0 is not required), which reflects the *latest state* of the current resource.\n\nIf a standard or a special version of the resource is changed (recreated or deleted), the current zero-version\nis automatically saved as a new auto-increment version and the new zero-version will be created instead.\n\nWhen the zero version is deleted, it's just moved to a new auto-increment version and the other versions\nwill be not deleted.\n\nWhen changing the resource you can send a pointer to the specific version and it can be completely removed or replaced.\nIf the version in the middle of the list will be deleted (v=2 for example), a \"hole\" will be appear:\nv=1: 200, v=2: 404 Not found, v=3: 200.\n\nIf you delete a version at the end of the list, the other version will be available at the next change to the same number:\n\n1. v=1: 200, v=2: 404 \u003c removed\n2. v=1: 200, v=2: 200 \u003c added again after changing the zero version\n\nFor completely resource deleting, you need to send a **destroy** parameter.\n\n#### DELETE destroy: bool, remove without backup\n\n- Если при удалении ресурса *версии по-умолчанию* в *варианте по-умолчанию* передать параметр destroy — ресурс будет\nудалён во всех вариантах и версиях.\n- Если при удалении *версии по-умолчанию* для *конкретного варианта* передать параметр destroy — будут удалены\n  все версии этого варианта.\n- Если при удалении ресурса указана определенная версия (для любого варианта) и передан параметр destroy,\n  будет удалена только указанная версия этого варианта, т.е. параметр destroy не окажет никакого влияния на поведение.\n\n#### POST author: string, author\n\nTODO: not implemented yet\nThe line with information about the author of the changes in an arbitrary string. Required only for logging.\n\n#### POST uri=http Upload image by remote URI\n\nImage, specified in the url parameter, will be uploaded to the server.\n\n## Path structure\n\nDifferent resources types can have different path structure. The Resource object have a path map specification inside.\nYou can look into specification with method [ResourceDOInterface::getDirectoryTokens()](https://github.com/KIVagant/staticus-core/blob/master/src/Resources/ResourceDOInterface.php#L129)\n\n- **[/namespace]/type/shard_variant/variant/version/[size/][other-type-specified/]shard_uuid/uuid.type**\n- /jpg/def/def/0/0/22a/22af64.jpg\n- /jpg/use/user/3/0/22a/22af64.jpg\n- /jpg/fra/fractal/0/22a/30x40/22af64.jpg\n- /jpg/som/some_module/0/22a/100x110/22af64.jpg\n- /mp3/def/def/0/22a/22af64.mp3\n- /mp3/def/def/1/22a/22af64.mp3\n\nNotice: ```shard_variant```` and ```shard_uuid``` should help to avoid filesystem crash or critical response time.\nIn the examples below their can be skipped.\n\n## JPG Type\n\n### Special parameters\n\n#### size=WxH, string, image dimension\n\nДля jpg поддерживается автоматическая обрезка изображений при выдаче.\nЧтобы изображения обрезались, в конфигурационном файле должны быть зарегистрированы все разрешенные размеры.\nИзображение с неразрешенным размером будет обрезано к ближайшему найденному зарегистрированному *большему* размеру.\n\nЕсли отправить POST-запрос на изображение без загружаемого файла, будет генерирована картинка с фракталом. Удобно использовать в качестве\nзаглушек по-умолчанию.\n\n#### filters[]=filtername, string, postprocessing filters\n\nTODO: filters support\n\n## MP3 Type\n\n### GET /*.mp3\n\n- Бекенд проверяет существование файла\n- Если найден — сообщит Nginx-у конечный URL, который будет закеширован\n- Иначе вернёт 404 Not found\n\n#### First request (without cache)\n```\n$ http --verify no -h GET https://www.your.project.dev/staticus/waxwing.mp3\nHTTP/1.1 200 OK\nAccept-Ranges: bytes\nCache-Control: public\nConnection: keep-alive\nContent-Length: 4904\nContent-Type: audio/mpeg\nDate: Mon, 04 Apr 2016 07:13:12 GMT\nETag: \"5701963e-1328\"\nLast-Modified: Sun, 03 Apr 2016 22:16:30 GMT\nServer: nginx/1.9.7\nX-Proxy-Cache: MISS\n```\n\n#### Second request (Nginx cache)\n\nNginx отдаёт файл из собственного кеша, уже не обращаясь на proxy_pass.\n\n```\n$ http --verify no -h GET https://www.your.project.dev/staticus/waxwing.mp3\nHTTP/1.1 200 OK\nAccept-Ranges: bytes\nCache-Control: public\nConnection: keep-alive\nContent-Length: 4904\nContent-Type: audio/mpeg\nDate: Mon, 04 Apr 2016 07:13:21 GMT\nETag: \"5701963e-1328\"\nLast-Modified: Sun, 03 Apr 2016 22:16:30 GMT\nServer: nginx/1.9.7\nX-Proxy-Cache: HIT\n```\n\n### POST /*.mp3\n\n*Примечание:* параметр recreate всегда вызовет перегенерацию\n\n- Бекенд проверяет существование файла.\n- Если найден (и нет флага recreate), вернёт HTTP 304 Not Modified.\n- Если не найден, обращается к зарегистрированному провайдеру озвучки (поддерживается один провайдер).\n- Полученный результат бекенд кеширует в своей папке.\n- TODO: и прописывает связь запроса и файла, чтоб позволить поиск и фильтрацию файлов.\n- Вернёт HTTP 201 Created\n\n#### Creation\n\n```\n$ find /var/www/cache/mp3 -type f -name *.mp3\n(nothing here)\n\n$ http --verify no --auth Developer:12345 -f POST https://www.your.project.dev/staticus/waxwing.mp3\nHTTP/1.1 201 Created\nCache-Control: public\nCache-Control: public\nConnection: keep-alive\nContent-Length: 0\nContent-Type: application/json\nDate: Mon, 04 Apr 2016 20:30:37 GMT\nServer: nginx/1.9.7\nX-Powered-By: PHP/5.6.15\n\n{\n    \"resource\": {\n        \"name\": \"waxwing\",\n        \"nameAlternative\": \"\",\n        \"recreate\": false,\n        \"type\": \"mp3\",\n        \"uuid\": \"2d5080a8ea20ec175c318d65d1429e94\",\n        \"variant\": \"def\",\n        \"version\": 0\n    },\n    \"uri\": \"waxwing.mp3\"\n}\n\n$ find /var/www/cache/mp3 -type f -name *.mp3\n/var/www/cache/mp3/def/0/2d5080a8ea20ec175c318d65d1429e94.mp3\n```\n\n#### Secondary creation\n\n```\n$ http --verify no --auth Developer:12345 -f POST https://www.your.project.dev/staticus/WaxWing.mp3\nHTTP/1.1 304 Not Modified\nCache-Control: public\nCache-Control: public\nConnection: keep-alive\nContent-Length: 0\nDate: Mon, 04 Apr 2016 20:36:16 GMT\nServer: nginx/1.9.7\nX-Powered-By: PHP/5.6.15\n\nfind /var/www/cache/mp3 -type f -name *.mp3\n/var/www/cache/mp3/def/0/2d5080a8ea20ec175c318d65d1429e94.mp3\n```\n\n#### Regeneration 1: Re-created file is identical to the existing\n\n```\n$ http --verify no --auth Developer:12345 -f POST https://www.your.project.dev/staticus/waxwing.mp3 recreate=1\nHTTP/1.1 304 Not Modified\nCache-Control: public\nCache-Control: public\nConnection: keep-alive\nContent-Length: 0\nDate: Sat, 09 Apr 2016 10:08:50 GMT\nServer: nginx/1.9.7\nX-Powered-By: PHP/5.6.15\n\n$ find /var/www/cache/mp3 -type f -name *.mp3\n/var/www/cache/mp3/def/0/2d5080a8ea20ec175c318d65d1429e94.mp3\n```\n\n#### Regeneration 2: The created file is a different\n\n```\n$ http --verify no --auth Developer:12345 -f POST https://www.your.project.dev/staticus/waxwing.mp3 recreate=1\nHTTP/1.1 201 Created\nCache-Control: public\nCache-Control: public\nConnection: keep-alive\nContent-Length: 0\nContent-Type: application/json\nDate: Sat, 09 Apr 2016 10:41:39 GMT\nServer: nginx/1.9.7\nX-Powered-By: PHP/5.6.15\n\n{\n    \"resource\": {\n        \"name\": \"waxwing\",\n        \"nameAlternative\": \"\",\n        \"recreate\": true,\n        \"type\": \"mp3\",\n        \"uuid\": \"2d5080a8ea20ec175c318d65d1429e94\",\n        \"variant\": \"def\",\n        \"version\": 0\n    },\n    \"uri\": \"waxwing.mp3\"\n}\n\n$ find /var/www/cache/mp3 -type f -name *.mp3\n/var/www/cache/mp3/def/0/2d5080a8ea20ec175c318d65d1429e94.mp3\n/var/www/cache/mp3/def/1/2d5080a8ea20ec175c318d65d1429e94.mp3 # automatically backuped version\n```\n\n#### File Uploading\n\n- You can use any parameter name for the uploaded file, but only first file from multiple files list will be uploaded.\n- Uploading will be ignored, if the version already exist. So, use 'recreate' param to force uploading.\n\n```\n$ http --verify no --auth Developer:12345 -f POST https://www.your.project.dev/staticus/waxwing.mp3 \\\n  recreate=true var=uploaded file@/Users/kivagant/vagrant/staticus/test.mp3\nHTTP/1.1 201 Created\nCache-Control: public\nCache-Control: public\nConnection: keep-alive\nContent-Length: 0\nContent-Type: application/json\nDate: Sun, 10 Apr 2016 14:40:17 GMT\nServer: nginx/1.9.7\nX-Powered-By: PHP/5.6.15\n\n{\n    \"resource\": {\n        \"name\": \"waxwing\",\n        \"nameAlternative\": \"\",\n        \"recreate\": true,\n        \"type\": \"mp3\",\n        \"uuid\": \"2d5080a8ea20ec175c318d65d1429e94\",\n        \"variant\": \"test\",\n        \"version\": 0\n    },\n    \"uri\": \"waxwing.mp3?var=test\"\n}\n\n$ find /var/www/cache/mp3 -type f -name *.mp3\n/var/www/cache/mp3/def/0/2d5080a8ea20ec175c318d65d1429e94.mp3\n/var/www/cache/mp3/def/1/2d5080a8ea20ec175c318d65d1429e94.mp3\n/var/www/cache/mp3/test/0/2d5080a8ea20ec175c318d65d1429e94.mp3\n```\n\n#### File Remote Downloading\n\n```\n$ http --verify no --auth Developer:12345 -f POST https://www.your.project.dev/staticus/waxwing.mp3 var=remote uri='http://some.domain/new.mp3'\nHTTP/1.1 201 Created\nCache-Control: public\nCache-Control: public\nConnection: keep-alive\nContent-Length: 186\nContent-Type: application/json\nDate: Mon, 11 Apr 2016 01:22:01 GMT\nServer: nginx/1.9.7\nX-Powered-By: PHP/5.6.15\n\n{\n    \"resource\": {\n        \"name\": \"waxwing\",\n        \"nameAlternative\": \"\",\n        \"recreate\": false,\n        \"type\": \"mp3\",\n        \"uuid\": \"2d5080a8ea20ec175c318d65d1429e94\",\n        \"variant\": \"remote\",\n        \"version\": 0\n    },\n    \"uri\": \"waxwing.mp3?var=remote\"\n}\n```\n\n### DELETE /*.mp3\n\n- Бекенд проверяет существование файла.\n- Если найден, создаёт резервную копию при условии, что предыдущая не-нулевая версия не идентична удаляемой.\n- Удаляет текущий оригинальный файл.\n- Возвращает 204 No content.\n\n#### Safety deletion\n\nIf Version 1 not equal to 0, then version 0 will backup to new version 2.\n\n```\n$ find /var/www/cache/mp3 -type f -name *.mp3\n/var/www/cache/mp3/def/0/2d5080a8ea20ec175c318d65d1429e94.mp3\n/var/www/cache/mp3/def/1/2d5080a8ea20ec175c318d65d1429e94.mp3\n\n$ http --verify no --auth Developer:12345 DELETE https://www.your.project.dev/staticus/waxwing.mp3\nHTTP/1.1 204 No Content\nCache-Control: public\nCache-Control: public\nConnection: keep-alive\nContent-Length: 0\nContent-Type: audio/mpeg\nDate: Mon, 04 Apr 2016 20:40:05 GMT\nServer: nginx/1.9.7\nX-Powered-By: PHP/5.6.15\n\n$ find /var/www/cache/mp3 -type f -name *.mp3\n/var/www/cache/mp3/def/2/2d5080a8ea20ec175c318d65d1429e94.mp3 # automatically backuped version\n/var/www/cache/mp3/def/1/2d5080a8ea20ec175c318d65d1429e94.mp3\n\n$ http --verify no GET https://www.your.project.dev/staticus/waxwing.mp3\\?nocache\\=bzbzbz # skip nginx cache\nHTTP/1.1 404 Not Found\nConnection: keep-alive\nContent-Length: 0\nContent-Type: audio/mpeg\nDate: Sat, 09 Apr 2016 10:48:19 GMT\nServer: nginx/1.9.7\nX-Powered-By: PHP/5.6.15\n```\n\n#### Destroying\n\n```\n$ http --verify no --auth Developer:12345 DELETE https://www.your.project.dev/staticus/waxwing.mp3\\?destroy\\=1\nHTTP/1.1 204 No Content\nCache-Control: public\nCache-Control: public\nConnection: keep-alive\nContent-Length: 0\nContent-Type: audio/mpeg\nDate: Sat, 09 Apr 2016 11:38:30 GMT\nServer: nginx/1.9.7\nX-Powered-By: PHP/5.6.15\n\n$ find /var/www/cache/mp3 -type f -name *.mp3\n(nothing here)\n```\n\n## Advanced usage\n\n### List all resource files\n\n- **GET|POST** /list/*{resource_route}*\n- **ACL Action**: list\n\n```\n$ http --body --verify no --auth Developer:12345 GET https://www.your.project.dev/staticus/list/welcome.jpg\n{\n    \"options\": [\n        {\n            \"dimension\": \"0\",\n            \"size\": 5322,\n            \"timestamp\": 1464692308,\n            \"variant\": \"def\",\n            \"version\": \"0\"\n        },\n        {\n            \"dimension\": \"100x100\",\n            \"size\": 2165,\n            \"timestamp\": 1464692314,\n            \"variant\": \"def\",\n            \"version\": \"0\"\n        },\n        {\n            \"dimension\": \"0\",\n            \"size\": 17055,\n            \"timestamp\": 1464692306,\n            \"variant\": \"def\",\n            \"version\": \"1\"\n        }\n    ],\n    \"resource\": {\n        \"dimension\": \"0\",\n        \"height\": 0,\n        \"name\": \"welcome\",\n        \"nameAlternative\": \"\",\n        \"namespace\": \"\",\n        \"new\": false,\n        \"recreate\": false,\n        \"type\": \"jpg\",\n        \"uuid\": \"40be4e59b9a2a2b5dffb918c0e86b3d7\",\n        \"variant\": \"def\",\n        \"version\": 0,\n        \"width\": 0\n    }\n}\n```\n\n### JPG searching with the special route /search/\n\nSetup the GOOGLE_SEARCH_API_KEY and the GOOGLE_SEARCH_API_CX in your ```.env``` config.\n\n- **GET|POST** /search/*{resource_route}?cursor=integer*\n- **ACL Action**: search\n\nThe file list found by a search adapter will be returned.\n\n1. Select a URL from the list.\n2. Send a POST request to any resource route with the same type and add the parameter uri=*chosen-uri*.\n\n- You can attach another search adapters and actions for different resource types (and change search behaviour).\n- You can configure ACL config for searching with Actions::ACTION_SEARCH command.\n- Only users with the 'adimn' role can use cursor attribute.\n- By default, 'name' and 'alt' will be used together for more correct searching.\n- By default, the POST 'body' argument will be used instead of 'name' and 'alt' if passed (can be used as searching string).\n\n#### Search example\n\n```\n$ http --body --verify no --auth Developer:12345 -f GET https://www.your.project.dev/staticus/search/welcome.jpg\\?alt\\='school'\\\u0026cursor\\=11\n{\n    \"found\": {\n        \"count\": 10,\n        \"items\": [\n            {\n                \"height\": 675,\n                \"size\": 453573,\n                \"thumbnailheight\": 112,\n                \"thumbnailurl\": \"https://somehots.somedomain/someurl\",\n                \"thumbnailwidth\": 146,\n                \"title\": \"FREE Back to School Party\",\n                \"url\": \"http://somehots.somedomain/wp-content/uploads/2013/02/welcome-back-to-school.jpg\",\n                \"width\": 880\n            },\n            {...},\n        ],\n        \"start\": 10,\n        \"total\": \"449000000\"\n    }\n}\n```\n\n### HTTP-based authentication\n\nThis is a primary authentication.\nUsed only for the administrator role. Look into ```AuthBasicMiddleware``` that activated in ```routes.global``` config.\nThis middleware will setup ADMIN role for current User object regardless session-based login status.\nLook into ```acl.global``` config for ADMIN roles.\n\n### Session-based authentication\n\nThe ```AuthSessionMiddleware``` allows you to use sessions from your project that includes 'Staticus' inside.\nYou can transparently embed this project to yours just with Nginx rules.\n\nFor example, if your basic project have domain ```https://my.domain.dev```, then you can put 'Staticus' to subpath:\n```https://my.domain.dev/static/``` and then all your files will accessible inside this route.\nThis subpath called ```path-to-home``` in Query structure in this document.\nSee ```etc/nginx/conf.d/staticus.conf``` with Nginx rules template for this case.\n\nIn this situation, 'Staticus' will have clear access to cookies from basic domain. And to users sessions too.\n\nSo, if your project used [Zend_Auth storage](http://framework.zend.com/manual/current/en/modules/zend.authentication.intro.html),\nthe ```AuthSessionMiddleware``` will load it from ```Redis``` sessions\nand will look for this path: ```$_SESSION['Zend_Auth']-\u003estorage-\u003euser_id```.\n\nIf you want to change session handler from Redis to something else, just replace\n```SessionManagerFactory``` to another one in the dependency section in this config: ```auth.global.php```.\n\nAll that ```AuthSessionMiddleware``` need for the ACL rules and default user namespaces support – it is user_id.\nSo you can replace the middleware to yours and realise this logic:\n\n```\n$this-\u003euser-\u003elogin($storage-\u003euser_id, [Roles::USER]);\n$this-\u003euser-\u003esetNamespace(UserInterface::NAMESPACES . DIRECTORY_SEPARATOR . $storage-\u003euser_id);\n```\n\n### Namespaces\n\nYou can group your resources in namespaces and setup different Access Control List rules for them.\nSetup the allowed namespaces list in the ```staticus.global``` config. You can use wildcard syntax here.\n\nThe ```AclMiddleware``` will help to implement rules from the ```acl.global``` config.\n\nSo, you can setup rules for different roles for any resource types for global namespace and special namespaces.\n\nBy default:\n- any guests have READ access to any resources in any namespaces.\n- any authorised user has own namespace (started from ```/user/{id}```) and have ANY access to JPG-resources inside.\n- an administrator has ANY access to all resources.\n\nYou can add or change this behaviour with ACL configuration or with adding another middleware.\n\n## Contributors\n\n- Andrew Yanakov \u003cayanakov at englishdom.com\u003e\n- Eugene Glotov \u003ckivagant at gmail.com\u003e\n\n## License\n\nMade in the [EnglishDom online school](https://www.englishdom.com/en/).\n\nCopyright 2016 Eugene Glotov \u003ckivagant at gmail.com\u003e\n\nLicensed under the Apache License, Version 2.0 (the \"License\");\nyou may not use this file except in compliance with the License.\nYou may obtain a copy of the License at\n\n    http://www.apache.org/licenses/LICENSE-2.0\n\nUnless required by applicable law or agreed to in writing, software\ndistributed under the License is distributed on an \"AS IS\" BASIS,\nWITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\nSee the License for the specific language governing permissions and\nlimitations under the License.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fkivagant%2Fstaticus","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fkivagant%2Fstaticus","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fkivagant%2Fstaticus/lists"}