<?php
//----------------------------------------
// receive : 1.0 du 11/03/2022
// 2.1 du 25/03/2022
// 2.2 du 27/03/2022 rajouter delete, taille (I)
// -------- 2 formes d'appel ----------------
// 1 GET :
// receive.php?N=<nom>&D=<date>&S=<taille>&C=<taille_Chunk> 32 (Mo par défaut)
// retour : Ok
// 2 POST :
// receive.php B = blob, H = Hash (2 octets), O : Offset, C : nombre octets
// retour H
//----------------------------------------
set_time_limit(0);
date_default_timezone_set('Europe/Paris');
ini_set("memory_limit", "-1");
ini_set("always_populate_raw_post_data", "-1");
$nohash = 'Oooops!_no_data_hash';
function file_ecrit($filename, $data)
{ // pour gestion des erreurs
if ($fp = fopen($filename, 'a')) // mode ajout !!
{
$ok = fwrite($fp, $data);
fclose($fp);
return $ok;
}
else return false;
}
function write_file($filename, $data)
{
if ($fo = fopen($filename, 'w')) // Warning: fwrite() expects parameter 2 to be string, array given
{
$ok = fwrite($fo, $data);
fclose($fo);
return $ok;
}
else return false;
}
function modif_fichier($filename, $data)
{ // pour modification fichier
if ($fa = fopen($filename, 'r+')) // Warning: fwrite() expects parameter 2 to be string, array given
{
$ok = fwrite($fa, $data);
fclose($fa);
return $ok;
}
else return false;
}
function hash_Sv($blob)
{
// petite verification blob esr en octets donc 20 octets par sha1
if ((strlen($blob) % 40) != 0)
{
return -1;
}
$table = [];
$nbrow = strlen($blob) / 40;
for ($i = 0;$i < $nbrow;$i++)
{
$table[] = array(
"Cl" => substr($blob, 40 * $i, 20) ,
"Sv" => substr($blob, (40 * $i) + 20, 20)
);
}
return $table;
}
function hash_in($blob)
{
// petite verification
if (((strlen($blob) % 20) != 0) && (strlen($blob) > 0))
{
return -1;
}
$table = [];
$nbrow = strlen($blob) / 20;
//file_ecrit('receive_deb.txt','84: '.$nbrow."\n");
for ($i = 0;$i < $nbrow;$i++)
{
$table[] = substr($blob, 20 * $i, 20);
//file_ecrit('receive_deb.txt','88: '.substr($blob, 20*$i, 20)."\n");
}
return $table;
}
function nhex2bin($h)
{
if (!is_string($h)) return null;
$r = '';
for ($a = 0;$a < strlen($h);$a += 2)
{
$r .= chr(hexdec($h[$a] . $h[($a + 1) ]));
}
return $r;
}
//$data = json_decode(file_get_contents('php://input'), true);
// DONNEE POST : INPUT_POST
$input = fopen("php://input", "rb");
$input_post = '';
while (!feof($input))
{
$input_post .= fread($input, 8192);
}
fclose($input);
//file_ecrit('receive_deb.txt','114: taille input = '.strlen($input_post)."\n");
$db = new PDO('sqlite:bfuv.sqlite');
// si forme GET :
/*--------------------------------------------------*/
if (strlen($input_post) == 0)
{
$N = '';
if (isset($_GET['N']))
{
$N = $_GET['N'];
}
$D = 0;
if (isset($_GET['D']))
{
$D = $_GET['D'];
}
$S = 0;
if (isset($_GET['S']))
{
$S = $_GET['S'];
}
$C = 0; // taille en Mo <=> 1.048.576 octets
if (isset($_GET['C']))
{
$C = intval($_GET['C']);
}
$I = false;
if (isset($_GET['I']))
{
$I = true;
}
$retour_GET = array(
'RId' => - 1,
'Ht' => '',
'new' => true
);
// Traitement pour l'appel en GET
if (is_string($N) && is_string($D) && is_string($S) && is_int($C))
{
// vérification si dejà existant : on compte combien y'en a
$reqsel = "SELECT ROWID FROM files WHERE (nom = '" . $N . "') AND (taille = '" . $S . "') AND (date = '" . $D . "') AND (cluster = " . $C . ")";
//file_ecrit('receive_deb.txt','161 : '.$reqsel."\n");
$stmt = $db->query($reqsel);
$stmt->setFetchMode(PDO::FETCH_OBJ);
$rows = $stmt->fetchAll();
$stmt->closeCursor();
if (empty($rows))
{
// on crée la ligne
$debug = "N=" . $N . ",S=" . $S . ",C=" . $C . ",D=" . $D . "\n";
$sqlcreate = "INSERT INTO files (nom, taille, cluster, date) VALUES(?, ?, ?, ?)";
$stmt = $db->prepare($sqlcreate);
$stmt->bindParam(1, $N, PDO::PARAM_STR);
$stmt->bindParam(2, $S, PDO::PARAM_STR);
$stmt->bindParam(3, $C, PDO::PARAM_INT);
$stmt->bindParam(4, $D, PDO::PARAM_STR);
$stmt->execute();
// retourne numéro de ligne correspondant à l'introduction éventuellement négatif si l'on ne peut créer le fichier (précaution)
$ret = write_file($N, '');
if (!file_exists($N)) $retour_GET['RId'] = - $retour_GET['RId']; // rowid négatif <=> pas pu créer fichier
$retour_GET['RId'] = $db->lastInsertId();
}
else
{
// ligne déjà existante a priori impossible car le client ne l'a pas récupérée à l'initialisation
//file_ecrit('receive_deb.txt',"185: EXISTE, ligne ".$res."\n");
$retour_GET['new'] = false;
$retour_GET['RId'] = $rows[0]->rowid;
}
$tableH = '';
$fileSv = './' . $N;
//file_ecrit('receive_deb.txt',"191: OK".json_encode($retour_GET)."\n");
echo json_encode($retour_GET);
}
else
// y'a un blèm' !
{
if ($I && is_string($N)){ // demande taille $N côté serveur
if (!file_exists($N)){ // si fichier inexistant, on le crée avec une taille de 0
file_ecrit($N,'');
echo 0;
} else {
$fp = fopen($N, 'rb');
$tsize = (float) 0;
$tchunksize = 1024 * 1024;
while (!feof($fp)) {
fread($fp, $tchunksize);
$tsize += (float) $tchunksize;
}
echo $tsize;
}
}
else
{
echo json_encode($retour_GET);
//file_ecrit('receive_deb.txt',"216: bizz\n");
}
}
$db = Null;
}
else
{
// $input non vide : POST
$ind = strpos($input_post, "*");
$firstpart = substr($input_post, 0, $ind);
//file_ecrit('receive_deb.txt','226: '.$firstpart."\n");
$params = explode("-", $firstpart);
$rowId = intval($params[0]);
$name = $params[1];
//file_ecrit('receive_deb.txt','230: rowid='.$rowId." et name=".$name."\n");
if (substr($name, 0, 6) == 'cremod')
{ // envoit d'une partie d'un cluster (gros chunk)
$params = explode("_", $name);
$ieme = intval($params[1]);
$clustInd = intval($params[2]);
$hashBlCl = $params[3];
$buffsize = intval($params[4]);
//file_ecrit('receive_deb.txt','238: cremod=('.$ieme.",".$clustInd.",".$buffsize."\n");
$reqsel = "SELECT nom, taille, cluster, hex(hashT) AS HhashT FROM files WHERE rowid = " . $rowId;
$pdo_result = $db->query($reqsel);
$pdo_result->setFetchMode(PDO::FETCH_BOTH);
$rows = $pdo_result->fetchAll();
$pdo_result->closeCursor();
$namef = $rows[0]['nom'];
$sizef = bcadd("0", $rows[0]['taille']);
$clusterf = 1048576 * $rows[0]['cluster'];
$locHashT = $rows[0]['HhashT']; // eventuellement vide
$tmpfile = $namef . "." . $ieme;
$data = substr($input_post, $ind + 1);
if (strlen($data) == $buffsize)
{
if (($clustInd % 100) == 0)
{
$ret = write_file($tmpfile, $data);
}
else
{
$ret = file_ecrit($tmpfile, $data);
}
//file_ecrit('receive_deb.txt','260: ret='.$ret."\n");
if ($ret == $buffsize)
{
if ($clustInd < 99)
{
echo $ret; // retourne nombre d'octets traités et fin
}
else
{
//file_ecrit('receive_deb.txt','270: hexHashTable= '.$locHashT."\n");
// 100 ième envoi (ou premier et unique)
$blocHash = sha1_file($tmpfile);
//file_ecrit('receive_deb.txt','273: blocHash= '.$blocHash."\n");
if ($hashBlCl != $blocHash)
{ // Aïe !
@unlink($tmpfile); // on efface le fichier
echo "fault";
}
else
{
// OK on a bien le bon bloc ! on l'écrit / remplace dans notre fichier
// positionnons-nous bien au bon endroit ! suppose que taille est au moins égale à ... normalement oui !
$f2mod = fopen($namef, "r+");
for ($k = 0;$k < $ieme;$k++)
{
$nimp = fread($f2mod, $clusterf);
}
$fread = fopen($tmpfile, "r");
$data_block = fread($fread, filesize($tmpfile));
fwrite($f2mod, $data_block);
//mise à jour table
$newhash = substr($locHashT, 0, (80 * $ieme)+40) . $blocHash . substr($locHashT, 80 * ($ieme+1));
$requpdate = "UPDATE files SET hashT = X'" . $newhash . "' WHERE rowid = " . $rowId;
$db->beginTransaction();
$stmt = $db->exec($requpdate);
$db->commit();
echo $blocHash; // dernière passe : envoit le hash
fclose($f2mod);
fclose($fread);
unlink($tmpfile);
}
}
} // else {file_ecrit('receive_deb.txt',"303: nombre octets ecrits dans fichier temp != buffsize\n");}
} //else {file_ecrit('receive_deb.txt',"304: nombre octets envoyés dans fichier temp != buffsize\n");}
}
if (substr($name, 0, 6) == 'hashSv')
{
$params = explode("_", $name);
$ieme = intval($params[1]);
$nbB = intval($params[2]);
$lochashCl = $params[3];
$maj = $params[4];
$reqsel = "SELECT nom, taille, cluster, hex(hashT) AS HhashT FROM files WHERE rowid = " . $rowId;
$pdo_result = $db->query($reqsel);
$pdo_result->setFetchMode(PDO::FETCH_BOTH);
$rows = $pdo_result->fetchAll();
$pdo_result->closeCursor();
$namef = $rows[0]['nom'];
$sizef = bcadd("0", $rows[0]['taille']);
$clusterf = 1048576 * $rows[0]['cluster'];
$locHashT = $rows[0]['HhashT']; // écrit en hexa 20 caract par clef, 40 par paire
//file_ecrit('receive_deb.txt','322: lochashT='.$locHashT."\n"); // ecrit en hexa
$f2mod = fopen($namef, "rb"); // pas d'écriture
for ($k = 0;$k < $ieme;$k++)
{
$nimp = fread($f2mod, $clusterf);
}
$path_parts = pathinfo($namef);
$tmpfile = $path_parts['filename'] . "." . "bak";
if ($path_parts['extension'] != "tmp")
{
$tmpfile = $path_parts['filename'] . "." . "tmp";
}
$data = fread($f2mod, $nbB);
$ret = write_file($tmpfile, $data);
$blocHash = sha1_file($tmpfile);
echo $blocHash;
fclose($f2mod);
unlink($tmpfile);
//hex2bin(substr($locHashT, 0, (80 * $ieme)));
if ($maj == "O"){ // mise à jour table en base si mise à jour
$newhash = substr($locHashT, 0, (80 * $ieme)) . $lochashCl . $blocHash . substr($locHashT, 80 * ($ieme+1));
$requpdate = "UPDATE files SET hashT = X'" . $newhash . "' WHERE rowid = " . $rowId;
$db->beginTransaction();
$stmt = $db->exec($requpdate);
$db->commit();
}
}
if (substr($name, 0, 6) == 'delete') //rowId = recno to delete
{
$reqdel = "DELETE FROM files WHERE rowid = " . $rowId;
$db->beginTransaction();
$stmt = $db->prepare($reqdel);
$ret = $stmt -> execute();
$db->commit();
echo $ret;
}
}
|