{"id":14965418,"url":"https://github.com/nette/safe-stream","last_synced_at":"2025-05-15T14:08:42.592Z","repository":{"id":15215081,"uuid":"17943561","full_name":"nette/safe-stream","owner":"nette","description":"SafeStream: atomic and safe manipulation with files via native PHP functions.","archived":false,"fork":false,"pushed_at":"2025-03-30T17:43:11.000Z","size":86,"stargazers_count":115,"open_issues_count":0,"forks_count":14,"subscribers_count":30,"default_branch":"master","last_synced_at":"2025-04-27T15:04:58.504Z","etag":null,"topics":["atomicity","filesystem","isolation","multiple-threads","nette","nette-framework","php"],"latest_commit_sha":null,"homepage":"https://doc.nette.org/safestream","language":"PHP","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"other","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/nette.png","metadata":{"files":{"readme":"readme.md","changelog":null,"contributing":"contributing.md","funding":null,"license":"license.md","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null},"funding":{"github":"dg","custom":"https://nette.org/donate"}},"created_at":"2014-03-20T13:29:37.000Z","updated_at":"2025-03-30T17:43:15.000Z","dependencies_parsed_at":"2023-11-27T00:22:23.605Z","dependency_job_id":"2c3f9971-47ad-4cee-801c-1aaa9bf22b8b","html_url":"https://github.com/nette/safe-stream","commit_stats":{"total_commits":110,"total_committers":8,"mean_commits":13.75,"dds":0.0636363636363636,"last_synced_commit":"dc81d3b9e40a1d852db76aebc48ca5da1718b261"},"previous_names":[],"tags_count":14,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nette%2Fsafe-stream","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nette%2Fsafe-stream/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nette%2Fsafe-stream/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nette%2Fsafe-stream/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/nette","download_url":"https://codeload.github.com/nette/safe-stream/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":252279071,"owners_count":21722833,"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":["atomicity","filesystem","isolation","multiple-threads","nette","nette-framework","php"],"created_at":"2024-09-24T13:34:43.660Z","updated_at":"2025-05-15T14:08:37.507Z","avatar_url":"https://github.com/nette.png","language":"PHP","readme":"SafeStream: Safety for Files\n============================\n\n[![Downloads this Month](https://img.shields.io/packagist/dm/nette/safe-stream.svg)](https://packagist.org/packages/nette/safe-stream)\n[![Tests](https://github.com/nette/safe-stream/workflows/Tests/badge.svg?branch=master)](https://github.com/nette/safe-stream/actions)\n[![Coverage Status](https://coveralls.io/repos/github/nette/safe-stream/badge.svg?branch=master)](https://coveralls.io/github/nette/safe-stream?branch=master)\n[![Latest Stable Version](https://poser.pugx.org/nette/safe-stream/v/stable)](https://github.com/nette/safe-stream/releases)\n[![License](https://img.shields.io/badge/license-New%20BSD-blue.svg)](https://github.com/nette/safe-stream/blob/master/license.md)\n\n\nIntroduction\n------------\n\nSafeStream guarantees that every read and write to a file is isolated. This means that no thread will start reading a file that is not yet fully written, or multiple threads will not overwrite the same file.\n\nInstallation:\n\n```shell\ncomposer require nette/safe-stream\n```\n\n\nWhat is it good for?\n--------------------\n\nWhat are isolated operations actually good for? Let's start with a simple example that repeatedly writes to a file and then reads the same string from it:\n\n```php\n$s = str_repeat('Long String', 10000);\n\n$counter = 1000;\nwhile ($counter--) {\n\tfile_put_contents('file', $s); // write it\n\t$readed = file_get_contents('file'); // read it\n\tif ($s !== $readed) { // check it\n\t\techo 'strings are different!';\n\t}\n}\n```\n\nIt may seem that `echo 'strings differ!'` can never occur. The opposite is true. Try running this script in two browser tabs at the same time. The error will occur almost immediately.\n\nOne of the tabs will read the file at a time when the other hasn't had a chance to write it all, so the content will not be complete.\n\nTherefore, the code is not safe if it is executed multiple times at the same time (i.e. in multiple threads). Which is not uncommon on the internet, often a server is responding to a large number of users at one time. So ensuring that your application works reliably even when executed in multiple threads (thread-safe) is very important. Otherwise, data will be lost and hard-to-detect errors will occur.\n\nBut as you can see, PHP's native file read and write functions are not isolated and atomic.\n\n\nHow to use SafeStream?\n----------------------\n\nSafeStream creates a secure protocol to read and write files in isolation using standard PHP functions. All you need to do is to specify `nette.safe://` before the file name:\n\n```php\nfile_put_contents('nette.safe://file', $s);\n$s = file_get_contents('nette.safe://file');\n```\n\nSafeStream ensures that at most one thread can write to the file at a time. The other threads are waiting in the queue. If no thread is writing, any number of threads can read the file in parallel.\n\nAll common PHP functions can be used with the protocol, for example:\n\n```php\n// 'r' means open read-only\n$handle = fopen('nette.safe://file.txt', 'r');\n\n$ini = parse_ini_file('nette.safe://translations.neon');\n```\n\n-----\n\nDocumentation can be found on the [website](https://doc.nette.org/safe-stream). If you like it, **[please make a donation now](https://github.com/sponsors/dg)**. Thank you!\n","funding_links":["https://github.com/sponsors/dg","https://nette.org/donate","https://github.com/sponsors/dg)*"],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fnette%2Fsafe-stream","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fnette%2Fsafe-stream","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fnette%2Fsafe-stream/lists"}