Appuyez sur [s] pour ouvrir les notes présentateur dans une nouvelle fenêtre.
Utilisez la touche [ESPACE]
pour passer au slide suivant.
Fichier entier
$str = file_get_contents(__DIR__ . '/data/file-01.txt');
$str = "plop glop !";
file_put_contents(__DIR__ . '/data/file-01-out.txt', $str);
$file = fopen(__DIR__ . '/data/file-01.txt', 'r');
if (false === $path) {
// Ouverture impossible
}
while (!feof($file)) {
$line = fgets($file);
echo "-> $line";
}
fclose($file);
$file = fopen(__DIR__ . '/data/file-01.txt', 'r');
if (false === $path) {
// Ouverture impossible
}
$position = ftell($file);
fseek($file, 10, SEEK_CUR);
fseek($file, -5, SEEK_END);
rewind($file);
fclose($file);
$exists = file_exists($path);
$size = filesize($path);
$type = filetype($path);
$ctime = filectime($path);
$mtime = filemtime($path);
$atime = fileatime($path);
touch($path, strtotime('10 days ago'));
$owner = fileowner($path);
$group = filegroup($path);
$info = stat($path);
unlink()
rename()
copy()
tempnam()
, tmpfile()
mkdir()
rmdir()
opendir()
, readir()
, closedir()
, ...PHP permet de manipuler des fichiers !
Travailler avec des flux,
c'est comme manipuler
des fichiers ?
Ressource, streamable,
lecture / écriture.
Même si on ne s'en rend pas toujours compte !
resource
stream_*()
Stream
schema://cible
schema
: nom du gestionnairecible
: dépend du gestionnairefile:///home/pmartin/test.txt
/home/pmartin/test.txt
http://www.example.net
ftp://user:password@example.com/pub/file.txt
phar://my.phar/somefile.php
glob://examples/*.php
compress.zlib://file.gz
Copier un fichier
Approche souvent vue
curl
,exec('scp ...')
Même chose, en 1 ligne
copy(
"http://blog.pascal-martin.fr/public/cv/pascal-martin-cv.pdf",
"ssh2.sftp://user:pass@test.machine.dev:22/home/user/cv.pdf"
);
Avec l'extension ssh2
Extensions ou userland
php://
php://stdin
, php://stdout
, php://stderr
php://input
, php://output
php://memory
, php://temp
Tester des accès fichiers /o\
function do_something($path)
{
$file = fopen($path, 'r+');
// ...
fclose($file);
}
do_something(__DIR__ . '/data/mon-fichier.txt');
Tester des accès flux \o/
$stream = fopen(__DIR__ . '/data/mon-fichier.txt', 'r+');
do_something($stream);
$stream = get_test_stream();
do_something($stream);
function get_test_stream() {
$stream = fopen('php://memory', 'w+');
fwrite($stream, "plop glop !");
rewind($stream);
return $stream;
}
Gérer des affichages /o\
function output_smth($str) {
echo "$str\n";
}
output_smth("Hello, World !");
Gérer des sorties \o/
function output_smth($stream, $str) {
fwrite($stream, "$str\n");
}
$out = fopen('php://output', 'w');
output_smth($out, "Hello, World !");
$out = fopen('file://' . __DIR__ . '/data/out.txt', 'w');
output_smth($out, "Hello, World !");
class FluxWrapper
{
public $context;
public function stream_open ($path , $mode , $options , & $opened_path) { }
public function stream_read($count) {}
public function stream_write($data) {}
public function stream_eof() {}
// ...
}
if (stream_wrapper_register(
'flux', FluxWrapper::class
) === false) {
// ...
}
$stream = fopen('flux://plop', 'r');
if (!$stream) { /* ... */ }
// Utilisation du flux...
fclose($stream);
stream_filter_append()
, stream_filter_prepend()
et stream_filter_remove()
$s = fopen('php://output', 'w');
$rot = stream_filter_append($s, 'string.rot13');
$low = stream_filter_append($s, 'string.tolower');
fwrite($s, "Hello, World!\n");
uryyb, jbeyq!
string
: rot13
, tolower
, toupper
convert
: base64-encode
, base64-decode
, iconv
, ...zlib
: inflate
, deflate
bzip2
: decompress
, compress
class MyFilterToUpper extends php_user_filter {
public function filter($in, $out, & $consumed, $closing) {
while ($bucket = stream_bucket_make_writeable($in)) {
$bucket->data = strtoupper($bucket->data);
$consumed += $bucket->datalen;
stream_bucket_append($out, $bucket);
}
return PSFS_PASS_ON;
}
}
C'est pas très drôle...
// Enregistrement du filtre
if (stream_filter_register(
'mytoupper', MyFilterToUpper::class
) === false) {
// ...
}
// Ajout du filtre à ceux portant sur le flux
stream_filter_append($stream, 'mytoupper');
Paramétrage du comportement
stream_context_create()
$options = [
'http' => [
'protocol_version' => '1.1',
'method' => 'GET',
'header' => "Accept-language: fr\r\n",
'user_agent' => "Mon client d'API",
'timeout' => 15,
'ignore_errors' => true,
],
];
$params = [];
$context = stream_context_create($options, $params);
Paramètre optionnel des fonctions de flux
$url = "http://api.openweathermap.org/data/2.5/weather?"
. http_build_query([
'q' => "Lyon,FR", 'APPID' => API_KEY,
], null, '&');
// 3ème paramètre de file_get_contents()
$str = file_get_contents($url, false, $context);
$data = json_decode($str, true);
$default = stream_context_get_default();
$default = stream_context_set_default([
'http' => [
'protocol_version' => '1.1',
'method' => 'GET',
'header' => "Accept-language: fr\r\n",
'user_agent' => "Mon client d'API",
'timeout' => 15,
'ignore_errors' => true,
],
]);
Dépendent du gestionnaire utilisé
$context = stream_context_create([
'ssl' => [
// /!\ UNIQUEMENT EN DEVELOPPEMENT /!\
'verify_peer' => false,
'verify_peer_name' => false,
'allow_self_signed' => true,
],
'ssh2' => [
'username' => "squale",
'pubkey_file' => "/.../.ssh/id_rsa.ks2.pub",
'privkey_file' => "/../.ssh/id_rsa.ks2",
],
]);
copy(
"https://.../public/cv/pascal-martin-cv.pdf",
"ssh2.sftp://.../home/user/cv.pdf",
$context
);
$from = "https://.../public/cv/pascal-martin-cv.pdf";
$to = "ssh2.sftp://.../home/user/cv.pdf";
$fin = fopen($from, 'r', false, $context) or die("Fail: in\n");
$fout = fopen($to, 'w', false, $context) or die("Fail: out\n");
// Ici, des filtres, si je veux ;-)
stream_copy_to_stream($fin, $fout);
fclose($fin);
fclose($fout);
stream_is_local($uri_or_stream)
stream_set_blocking($stream, $mode)
stream_set_read_buffer($stream, $buffer)
et stream_set_write_buffer($stream, $buffer)
et stream_set_chunk_size($stream, $size)
stream_resolve_include_path($filename)
stream_socket_server()
stream_socket_accept()
stream_socket_client()
$server = stream_socket_server('tcp://127.0.0.1:8080');
if (false === $server) { /* ... */ }
while (($conn = stream_socket_accept($server, -1))) {
$str = "Hello, World!";
fwrite($conn, "HTTP/1.1 200 OK\r\n");
fprintf($conn, "Content-Length: %d\r\n", strlen($str));
fwrite($conn, "\r\n");
fwrite($conn, $str);
fclose($conn);
}
$ip = gethostbyname('example.org');
$client = stream_socket_client("tcp://$ip:80");
if (false === $client) { /* ... */ }
fwrite($client, "GET / HTTP/1.1\n\r");
fwrite($client, "Host: example.org\n\r");
fwrite($client, "User-agent: Some agent\n\r");
fwrite($client, "\n\r");
while (!feof($client)) {
echo fgets($client);
}
fclose($client);
Flux de type socket peuvent être non-bloquants
Le gros de la logique
$server = stream_socket_server("tcp://127.0.0.1:8080",
$errno, $err);
if (false === $server) { /* ... */ }
$clients = [];
while (true) {
$reads = array_merge($clients, [$server]);
$writes = $excepts = [];
if (stream_select($reads, $writes, $excepts, 1, 0) === false) {
// Timeout
}
foreach ($reads as $read) {
// Cf slide suivant ;-)
} // foreach $reads
} // while true
fclose($server);
Le corps de la boucle
if ($read === $server) {
if (($new_client = stream_socket_accept($server))) {
printf("+Client: %s\n", stream_socket_get_name($new_client, true));
$clients[] = $new_client;
}
}
else if (($str = trim(fread($read, 1024))) !== '') {
printf("[%s] Server received: %s\n", date('H:i:s'), $str);
foreach ($clients as $client) {
fprintf($client, "> %s\n", $str);
}
}
Pascal MARTIN
blog.pascal-martin.fr
contact@pascal-martin.fr
@pascal_martin
TEA, The Ebook Alternative