Autor Zpráva
maycza
Profil
Zdravím,

chtěl bych se zeptat, máte někdo zkušenosti s nahráváním souborů do ms sql databáze? Data ukládám do sloupce typu varbinary(max). Mám kód:
$content=file_get_contents($_FILES["soubor"]["tmp_name"]);
$content=base64_encode($content);
$q="INSERT INTO files (name,size,type,content,znak)VALUES('".htmlspecialchars($soubor_name)."','$soubor_size','$soubor_typ',CONVERT(varbinary(MAX), '$content'),'c')";
$d=odbc_exec($db, $q);

Data se bez problémů uloží. Problém nastává při výpisu dat, pro který používám následující kód:
$db = odbc_connect('Driver=TDS;Server=nejakyServer;', 'jmeno', 'heslo'); 
if($db === false) {echo "Chyba připojení k databázi";}
$q=odbc_exec($db,"SELECT name, type, size, CONVERT(varbinary(MAX),content) AS content FROM files WHERE id=".$_GET["id"]);
while($r=odbc_fetch_array($q)){
  $name=$r["name"];
  $size=$r["size"];
  $velikost=$r["content"];
  $type=$r["type"];
  $content=base64_decode($r["content"]);
}

header("Expires: Mon, 26 Jul 1997 05:00:00 GMT"); // Date in the past 
header("Last-Modified: " . gmdate("D, d M Y H:i:s") . " GMT");    // always modified 
header("Content-length: " . $size); 
header("Content-type: " . $type); 
header("Content-Disposition: attachment; filename={$name}"); 
header("Content-Transfer-Encoding: binary"); 
print($content);

Dalo by se říct, že všechno funguje, ale... pokud jsou data < 8kB vše je ok, pokud jsou větší, vypíše se jen část (do 8kB) a tím pádem se data stávají nečitelnými. Když si nechám vypsat jen surová data ze sloupce content, vypíše se vždy jen jejich část, vždy se to utne na stejném místě (omezení 46000). Pokud v databázi spustím dotaz SELECT LEN(content) FROM tabulka zjistím, že soubor má mnohem víc znaků než 46000.

Zjistil jsem, že MS SQL managenet studio má záměrně omezení pro výpis dat 8kB / 46000 znaků, čemuž rozumím, proč ale nemůžu z databáze dostat celý obsah sloupce content pomocí php?
maycza
Profil
Kdyby to náhodou někdy někdo řešil, tak doporučuju tento odkaz. Je sice starší, ale mě to pomohlo. Jen jsem musel změnit typ sloupce content z varbinary(max) na image.

Nahrávání souborů zůstalo jak je, pro stažení souboru jsem si upravil kód z článku (komentáře jsou původní):
if (isset($_GET["file"])){$id_priloha=$_GET["file"];}

$dbconnect = odbc_connect('Driver=TDS;Server=servername;', 'user', 'password'); 
if($dbconnect === false) {echo "Chyba připojení k databázi";}

$data=""; 
$blok_dat=512; //data budeme z databáze číst po 512 b
if (isset($id_priloha) and is_numeric($id_priloha)){ 
  $query="SELECT size, name, type FROM table_name.files WHERE id=".$id_priloha;
   
  $soubory=ODBC_exec($dbconnect,$query);  
  while ($r=odbc_fetch_array($soubory)){
    $velikost=$r["size"]; 
    $jmeno=$r["name"]; 
    $mime_type=$r["type"]; 
  }
    
  $p=0; //$p označuje pozici, odkud se začneme binárně soubor z databáze číst (pokud 0, tak od začátku)
  //zjištění ukazatele a dalších pomocných proměnných 
  $sql="SELECT TEXTPTR(content) as textptr, DATALENGTH(content) as blobsize, 
    $p as chunkindex, 
  CASE WHEN $blok_dat< DATALENGTH(content) THEN 512 ELSE DATALENGTH(content) END as chunksize 
  FROM table_name.files WHERE id=".$id_priloha; 

  $rs=ODBC_exec($dbconnect,$sql);
  while ($r=odbc_fetch_array($rs)){ 
    //načtení výsledků z dtb do proměnných  
    $textptr=bin2hex($r["textptr"]); //ukazatel (musí být binární) na pozici souboru
    $blobsize=$r["blobsize"]; //definuje celou velikost souboru
    $chunksize=$r["chunksize"]; //definuje po kolika bitech se bude načítat soubor
    //Soubor je nutné načítat po blocích! Nelze najednou… chunksize je velkost bloku
    $chunkindex=$r["chunkindex"]; //def. pozici, odkud se začíná číst blok dat (jehož velikost def. $chunksize
  }
//=================
  if ($textptr<>""){  //jestliže je nalezen ukazatel
    while (($chunkindex<$blobsize)){ //tento cyklus postupně načte všechna data
      if (($chunkindex+$chunksize)>$blobsize){ 
        /*
        kdybychom chtěli načíst větší blok, než jaký můžeme => pak je nutné vzít jako blok přesnou velikost toto typicky nastane tehdy, je-li max. možná délka načítaných dat menší, než udává proměnná $blok_dat
        */
        $chunksize=$blobsize-$chunkindex; 
      } 
      //celý princip je o tom, že SQL server není schopen vrátit víc jak 2048bitů.
      //Proto tedy /po námi stanoveném kroku v proměnné proměnná $blok_dat (512b)/
      //čteme celý soubor část po části a následně tyto bloky spojujeme do celku
      $sql2="set textsize 512 READTEXT table_name.files.content 0x".$textptr." $chunkindex ".($chunksize-$p).""; 
      //nezapomeňme, že proměnná $p označuje počáteční pozici čtení dat;
      $rs2=ODBC_exec($dbconnect,$sql2); 
      //přilepení bloku dat ke stávajícím
      while ($r=odbc_fetch_array($rs2)){
        $data.=$r["content"];
      } 
      //navýšení indexu =>abychom četli následující blok dat
      $chunkindex=$chunkindex+$chunksize; 
    }
  } 
//a máme načtená data
//odešleme HTTP hlavičku
    
  header("Pragma: public"); //vypnutí cache pro proxy servery atp. pro HTTPverze 1.0
  header("Expires: 0"); //datum expirace – nastavení na ihned
  header("Cache-Control: must-revalidate, post-check=0, pre-check=0"); //opět vypnutí cache; pro HTTP verze 1.1
  header("Content-Description: File Transfer"); 
  header("Content-Type: $mime_type"); 
  header("Content-Length: " . $velikost); 
  header("Content-Disposition: attachment; filename=" . $jmeno); 
// a nyní odešleme data prohlížeči
  echo base64_decode($data);      
  exit(); 
}

Vaše odpověď

Mohlo by se hodit


Prosím používejte diakritiku a interpunkci.

Ochrana proti spamu. Napište prosím číslo dvě-sta čtyřicet-sedm: