Download the PHP package zdenekgebauer/dosiero without Composer

On this page you can find all versions of the php package zdenekgebauer/dosiero. It is possible to download/install these versions without Composer. Possible dependencies are resolved automatically.

FAQ

After the download, you have to make one include require_once('vendor/autoload.php');. After that you have to import the classes with use statements.

Example:
If you use only one package a project is not needed. But if you use more then one package, without a project it is not possible to import the classes with use statements.

In general, it is recommended to use always a project to download your libraries. In an application normally there is more than one library needed.
Some PHP packages are not free to download and because of that hosted in private repositories. In this case some credentials are needed to access such packages. Please use the auth.json textarea to insert credentials, if a package is coming from a private repository. You can look here for more information.

  • Some hosting areas are not accessible by a terminal or SSH. Then it is not possible to use Composer.
  • To use Composer is sometimes complicated. Especially for beginners.
  • Composer needs much resources. Sometimes they are not available on a simple webspace.
  • If you are using private repositories you don't need to share your credentials. You can set up everything on our site and then you provide a simple download link to your team member.
  • Simplify your Composer build process. Use our own command line tool to download the vendor folder as binary. This makes your build process faster and you don't need to expose your credentials for private repositories.
Please rate this library. Is it a good library?

Informations about the package dosiero

Dosiero PHP

PHP server connector for Dosiero file manager

Usage

  1. Create entry point i.e. https://yourserver/dosiero/index.php by this example:

  2. Set access control - a connector without any configured check refuses every request
  3. Set at least one file storage
  4. Set url of entry point in Dosiero client side configuration

Inside a framework: a controller instead of a standalone script

The example above is a standalone script, which is the shortest thing that works. In an application that already has routing, authentication and a response object, the connector belongs in a controller on a route of its own — that way the file manager is reached through the same front controller as everything else, and it can reuse what the application already knows.

Two things change. The application answers who the caller is, through requireCallback(), so the connector does not have to be told which of session, token or cookie your login uses. And sendOutput() is not used: it echoes the body and sets headers itself, which a controller must not do. Take the status and the payload off the response object and hand them to your framework:

getHttpStatus() and toStdClass() are there for exactly this: the same outcome sendOutput() would have produced, as values you can put into a response of your own.

Points worth getting right:

Protocol

One entry point, one request per action, JSON in the response body. The authority is Connector::handleRequest(); this section describes what it does.

Every request carries $_GET['action']. Actions other than storages also carry $_GET['storage'] with the storage name, and optionally $_GET['path'] — the directory relative to BASE_DIR, without a leading or trailing slash. Mutations send their arguments as POST.

Action Also sends Returns
storages — storages
files — files
files-reload — files, with the directory cache bypassed
mkdir folder files, storage
delete files[] files; storage if a folder was deleted
rename old, new files; storage if a folder was renamed
copy files[], target_path, target_storage files; storage if a folder was copied
move files[], target_path, target_storage files; storage if a folder was moved
upload $_FILES files

The response object always has msg — empty on success, the error text otherwise — and carries these properties when the action produced them:

copy and move between two different storages are not supported yet and are refused.

Every request must carry the header X-Dosiero-Protocol: 1; one without it is refused with 403. See Requests from another site for why.

The HTTP status carries the outcome as well: 400 for an invalid request or a storage error, 403 for a refused access, 500 for anything unexpected. The mapping is the entry point's job — the catch blocks in the example above.

Securing the data directory

BASE_URL has to be publicly reachable, so BASE_DIR usually sits under the web root. Anything that lands there is served by the web server, which makes the data directory the most sensitive part of the installation.

Uploads are restricted to a list of extensions. The default list covers images, common documents and archives; extensions a web server can be talked into executing (php, phtml, phar, cgi, htaccess, …) are refused in any position of the name, so invoice.php.jpg does not get through either. A file claiming an image extension has to actually be an image.

Narrow or widen the list per storage:

svg is not in the default list on purpose. An SVG can carry script and is served from the same origin as your site, so enabling it is a decision to make knowingly.

The declared type is verified against the content. Every upload is inspected with finfo: anything detected as an executable or a script is refused whatever it is called, and where the extension has an unambiguous signature (pdf, archives, audio, video, plain text) the content has to match it. Office documents are ZIP or OLE containers that libmagic reports inconsistently, so those are checked by extension only.

Access control

Config decides who may call the connector, and a connector with nothing configured refuses everything. A public file manager has to be asked for, not arrived at by forgetting:

Whatever you set has to pass — the checks combine with AND. Every refusal answers 403 with the same message, so the response does not say which check objected.

setAllowedIp() takes single addresses or CIDR ranges, IPv4 and IPv6, and compares them by value: ::1 and 0:0:0:0:0:0:0:1 are the same address. An entry it cannot parse is refused when you set it, not silently ignored.

Deciding permissions in the application

The four checks above answer who is calling. To answer what they may do, hand the connector a function — it already knows your users, and this way the connector does not have to:

It receives the action and the storage name, and its answer is final. The storages response is filtered through it as well, so a storage the caller may not reach does not appear in the list either.

It is deliberately not given the path. rename and move change the path, so a rule bound to a folder would stop holding the moment a file was moved out of it, and copy would leave one copy inside the rule and one outside. A promise the connector cannot keep is worse than no promise.

Separating content per user

Give each user their own storage. The entry point is an ordinary script that runs on every request, so it can build one from whoever is logged in — no extra configuration:

Requests from another site

Every request must carry the X-Dosiero-Protocol header, and the connector refuses one without it. This is what stops a page on somebody else's site from reaching the endpoint: a browser will not put a custom header on a plain form submission, and a script that tries has to get the connector's permission first — which it does not give to an origin you did not name. The value is not a secret; it is the protocol version, and the protection comes from the browser's rules rather than from anything being hard to guess.

Two further checks apply to mkdir, delete, rename, copy, move and upload: a request the browser reports as coming from another site (Sec-Fetch-Site) or carrying a foreign Origin is refused unless that origin is configured. When the browser reports neither, the request goes through — those headers are filled in by the browser and cannot be forged or suppressed by a script, so their absence means an old browser or a client that is not a browser, not an attack.

Running the connector on another domain

The recommended deployment is the same origin as the application. Serving the connector from a different domain is supported and sometimes necessary — a domain reserved for content, one connector shared by several applications, or CKEditor's popup, which receives the endpoint in its query string:

The entry point then hands the configuration to the response and answers the question the browser asks before it will send such a request:

On the client set withCredentials: true when credentials have to travel with it.

Storage options

Every option goes through setOption(string $name, bool|int|string $value). List-valued options are passed as a comma-separated string. An unknown name throws.

Option Default Meaning
BASE_DIR (LocalStorage) — Directory holding the files. Required; throws when it is not a directory.
BASE_URL '' Public url the same files are served from, used to build the url in the response.
ALLOWED_EXTENSIONS images, documents, archives, media — not svg What an upload may be called. See Upload types.
MAX_FILE_SIZE 5242880 (5 MB) Per file, in bytes. 0 leaves only the php.ini ceiling.
OVERWRITE_FILES true Whether upload, copy, move and rename may replace an existing file.
NORMALIZE_NAMES true Repair an uploaded name instead of refusing it. Off means an invalid name is rejected.
READ_ONLY false Refuses every mutation and tells the client, which disables the buttons.
MODE_DIRECTORY 0o755 Permissions for a created directory.
MODE_FILE 0o644 Permissions for a stored file.
THUMBNAIL_SIZE 50 Longer side of the generated thumbnail, in pixels. Minimum 10.
CACHE_ENABLED true See Listing cache.
CACHE_DIRECTORY '' Empty keeps .htdircache next to the data.

What the connector will not do

Some behaviour is not configurable on purpose, because making it optional would mean offering a setting whose only effect is to make the installation unsafe.

Collisions

OVERWRITE_FILES governs upload, copy, move and rename alike. With it off, a collision is reported before anything is written:

Renaming onto an existing name is refused the same way. With it on — the default — the existing file is replaced, as the option says.

Upload types

What an upload has to pass is described under Securing the data directory: the extension allowlist, the executable-extension rule, verification of the content against the declared type, and getimagesize() for anything claiming to be an image.

One consequence is worth stating here, because it decides where the real protection sits. The allowlist is a rule for what comes in, not a property of what is stored. Files also arrive by ftp, by a migration or by hand, and renaming those has to stay possible — so renaming enforces only the executable-extension rule, not the allowlist. A storage can therefore hold a .svg even when svg is not on the list. Refusing to execute anything in the data directory is a requirement, not a spare layer.

Resource limits

Errors

Every failure reaches the entry point as one of four exceptions, and the mapping to status codes is yours to make — the connector never sets a status or echoes anything:

Exception Meaning Suggested status
AccessForbiddenException An access check refused the request. 403
InvalidRequestException A parameter is missing, malformed, or names something that does not exist. 400
StorageException The operation itself failed: collision, missing file, refused type, failed write. 400
\Throwable Anything unforeseen. 500

Successful or not, the body is JSON with a msg property — empty on success, the message on failure. Every access refusal answers with the same text, so the response does not tell a caller which check objected. The one exception is a connector with no access check configured at all, which names that reason: there is no visitor to keep it from and the integrator would otherwise be guessing.

For a public deployment, answer unforeseen errors with a generic message and a correlation id, and log the detail on the server. The catch-all in the example above passes getMessage() to the client, which is convenient in development and can leak paths in production.

Upload size

Each storage has its own limit, in bytes, defaulting to 5 MB:

php.ini is a ceiling this option cannot raise. The limit that really applies is the smallest of MAX_FILE_SIZE, upload_max_filesize and post_max_size, and that is also the value getMaxFileSize() reports and the connector sends to the client. Setting the storage to 20 MB on a server configured for 2 MB gives you 2 MB.

To allow larger uploads, raise the ini directives as well — both of them, because a request also carries multipart overhead:

Two traps worth knowing:

The client uses the reported limit to reject an oversized file before it is sent, which saves the transfer; the server check is the authoritative one and always runs.

Turn off script execution for the data directory as well. The extension list is one layer; the web server should be the second.

Put the rules outside the directory they protect — in the vhost, or in the .htaccess of a parent directory scoped to the path. A configuration file sitting among the managed files is part of the data the connector serves, and a future change to what it lists or writes could expose it. The connector hides names starting with a dot and refuses to delete or rename them, so .htaccess is not reachable through the manager, but relying on that is a weaker arrangement than not putting it there at all.

For Apache, in the .htaccess one level up or in the vhost:

Content-Disposition: attachment makes the browser download a file opened directly instead of rendering it, which neutralizes an uploaded document that tries to behave like a page. It does not stop <img src> from displaying the file, so editor integrations are unaffected.

On nginx make sure no location ~ \.php$ block applies to the data directory.

Listing cache

Keep the listing cache out of reach. By default every directory gets a .htdircache file holding its listing including base64 thumbnails. The .ht prefix is only honoured by Apache's default configuration - on nginx the file is downloadable unless you block it explicitly. What leaks is not the files, which are public anyway, but the listing: names nobody linked to, plus their thumbnails.

Two options change that:

CACHE_DIRECTORY moves the cache to a directory of your choice - pick one outside the web root, and not a temp directory shared with other accounts. CACHE_ENABLED switches caching off completely; listings then rebuild thumbnails on every request, which is slower but writes nothing anywhere.

A directory the web server cannot write to - a read-only mount, another owner - is handled the same way as CACHE_ENABLED = false: the listing works and nothing is cached. Set CACHE_DIRECTORY to get the cache back for such a storage.

Local development

The Api suite drives the connector over real HTTP, which is the only place the CORS and preflight headers actually exist. It runs against tests/Support/Endpoint/index.php, a committed entry point — not against /index.php, which is gitignored and is the local playground. CI serves the same file with php's built-in server:

Client and connector are separate repositories and are released together. The client is at ../Dosiero; the demo that wires both together is at ../DosieroDemo.


All versions of dosiero with dependencies

PHP Build Version
Package Version
Requires php Version >=8.3
ext-fileinfo Version *
ext-gd Version *
ext-iconv Version *
ext-json Version *
Composer command for our command line client (download client) This client runs in each environment. You don't need a specific PHP version etc. The first 20 API calls are free. Standard composer command

The package zdenekgebauer/dosiero contains the following files

Loading the files please wait ...