Fórum Root.cz
Hlavní témata => Vývoj => Téma založeno: A. F. 30. 06. 2018, 15:18:47
-
Ahoj.
Načítám celkem velký objem dat (několik giga) po kouskách o velikosti typicky 2096 bajtů. A následně ho zapisuju do souboru v tempu:
$tmpdir = sys_get_temp_dir();
$tmpname = tempnam($tmpdir, 'app-');
$handle = fopen($tmpname, 'a');
// velikost $s je obvykle 2096 bajtů
function write($s)
{
$len = strlen($s);
$wrote = fwrite($handle, $s);
if ($len !== $wrote) {
echo "\n\nERROR: Nesedí počet zapsaných bytů. C1 {$wrote} ~ {$len}\n\n"; // "419 ~ 2096"
var_dump(error_get_last()); // nic
$wrote2 = fwrite($handle, substr($s, $wrote));
if ($wrote2 !== ($len - $wrote)) {
echo "\n\n{$s}\n\n"; // zde vidím, že to není poslední záznam. Je to uřízlé uprostřed textu.
throw new RuntimeException('Nesedí počet zapsaných bytů. C2 ' . "{$wrote2} ~ " . ($len - $wrote) ); // "0 ~ 1677"
}
}
}
Celé mi to chcípne na tom, že nesedí počet zapsaných bajtů. Je možné, že mi třeba došlo místo v tempu, nebo tak něco. Ale vadí mi, že mi to nevypíše žádnou chybu.
Otázka tedy zní, jak zjistím, co se stalo?
Děkuji za odpověď.
-
Nevládnu PHP, ale nepomohlo by tohle?
https://stackoverflow.com/questions/9473474/php-fwrite-doesnt-finish-writing-string-data-to-file-why#9473840
sice se člověk nedozví, kde to zkrachovalo, ale funkce, zmíněná v odkazu údajně garantuje přepis celého řetězce.
-
Funkce fwrite negarantuje, že zapíše všechny znaky. Musíte si posouvat ukazatel v řetězci a opakovat funkci tak dlouho, dokud nezapíše vše. Pokud by došlo k chybě, vrací fwrite FALSE.
-
$len = strlen($s);
$wrote = fwrite($handle, $s, $len);
-
Funkce fwrite negarantuje, že zapíše všechny znaky. Musíte si posouvat ukazatel v řetězci a opakovat funkci tak dlouho, dokud nezapíše vše. Pokud by došlo k chybě, vrací fwrite FALSE.
Nechápu, jak to souvisí s mojí otázkou?
-
Nechápu, jak to souvisí s mojí otázkou?
Máte ten kód špatně. Porovnáváte počet zapsaných bajtů s počtem bajtů k zapsání, a když nesouhlasí, považujete to za chybu. Ale ona to chyba není, počet zapsaných bajtů může být v rozmezí 0 až počet bajtů k zapsání. fwrite prostě zapíše tolik bajtů, kolik zrovna zapsat může, a vy si musíte zkontrolovat, zda už zapsal všechno, a když ne, tak to otočit v cyklu a zapsat další část. Podívejte se na dokumentaci fwrite (http://php.net/manual/en/function.fwrite.php), tammáte hned v první poznámce příklad, jak má zápis do souboru vypadat správně.
-
Nechápu, jak to souvisí s mojí otázkou?
Máte ten kód špatně. Porovnáváte počet zapsaných bajtů s počtem bajtů k zapsání, a když nesouhlasí, považujete to za chybu. Ale ona to chyba není, počet zapsaných bajtů může být v rozmezí 0 až počet bajtů k zapsání. fwrite prostě zapíše tolik bajtů, kolik zrovna zapsat může, a vy si musíte zkontrolovat, zda už zapsal všechno, a když ne, tak to otočit v cyklu a zapsat další část. Podívejte se na dokumentaci fwrite (http://php.net/manual/en/function.fwrite.php), tammáte hned v první poznámce příklad, jak má zápis do souboru vypadat správně.
Přečtěte si prosím nejdříve ten kód, dobře?
-
$len = strlen($s);
$wrote = fwrite($handle, $s, $len);
To by bylo hloupé, ale zkusím to.
-
Přečtěte si prosím nejdříve ten kód, dobře?
Nejprve si vy velmi pomalu přečtěte, co jsem vám napsal ve svém prvním komentáři. Máte tam vysvětlené, jak funguje funkce fwrite a proč máte ten kód špatně. Pak si přečtěte dokumentaci funkce fwrite, abyste to lépe chápal, odkaz jsem vám dával.
$len = strlen($s);
$wrote = fwrite($handle, $s);
if ($len !== $wrote) {
echo "\n\nERROR: Nesedí počet zapsaných bytů. C1 {$wrote} ~ {$len}\n\n"; // "419 ~ 2096"
Konkrétně tady jsou špatně ty poslední dva řádky, protože to, že se zapsalo méně bajtů, než kolik jich bylo k dispozici, není chyba, je to standardní chování funkce fwrite.
-
$len = strlen($s);
$wrote = fwrite($handle, $s, $len);
To by bylo hloupé, ale zkusím to.
Klidně to zkuste, ale ničemu to nepomůže, protože třetí parametr funkce fwrite je nepovinný, a pokud není uveden, zapisuje se celý řetězec. Tedy uvedený kód je ekvivaletní s tímhle:
$wrote = fwrite($handle, $s);
Nebývá špatné přečíst si dokumentaci, pak se nemusíte ptát na věci, které jsou tam napsané.
-
Nebývá špatné přečíst si dokumentaci, pak se nemusíte ptát na věci, které jsou tam napsané.
V dokumentaci je napsáno přesně to, co jsem psal, tedy že třetí parametr je v takových případech nutný.
-
$len = strlen($s);
$wrote = fwrite($handle, $s, $len);
To by bylo hloupé, ale zkusím to.
Klidně to zkuste, ale ničemu to nepomůže, protože třetí parametr funkce fwrite je nepovinný, a pokud není uveden, zapisuje se celý řetězec. Tedy uvedený kód je ekvivaletní s tímhle:
$wrote = fwrite($handle, $s);
Nebývá špatné přečíst si dokumentaci, pak se nemusíte ptát na věci, které jsou tam napsané.
Děkuji za příspěvek. Stále nechápu jak by mi mohl alespoň vzdáleně pomoci s mým problémem. Opakování zápisu je použito už v tom kódu, nevím tedy proč mi to doporučujete. Cožpak jste ten kód nečetl, než jste psal svou radu?
-
V dokumentaci je napsáno přesně to, co jsem psal, tedy že třetí parametr je v takových případech nutný.
Vy jste napsal jenom kus kódu, žádné vysvětlení, natož něco o „takových případech“. Ty hranaté závorky kolem parametru $length v definici funkce označují, že je parametr nepovinný, pak je to ještě zopakované u samotného parametru: „If the length argument is given…“. Pokud narážíte na to, že přítomnost parametru $length zároveň znamená,že s ebude ignorovat volba magic_quotes_runtime, my nevíme ani co chce zapisovat ani jak má tuto volbu nastavenou.
-
Stále nechápu jak by mi mohl alespoň vzdáleně pomoci s mým problémem.
Váš problém je, že si myslíte, že došlo k chybě, ve skutečnosti k žádné chybě nejspíš nedošlo. Zda došlo k chybě otestujete tak, že návratovou hodnotu funkce fwrite() porovnáte s hodnotou FALSE.
Opakování zápisu je použito už v tom kódu
Ne, není. Jak jste přišel na to, že při druhém volání se zapíše vše? Volání se musí opakovat tak dlouho, dokud nejsou zapsaná všechna data. Používají se k tomu cykly.
Cožpak jste ten kód nečetl, než jste psal svou radu?
Přestaňte pořád hledat chyby u jiných, když je ta chyba jenom ve vašem kódu. Četl jste tu poznámku s příkladem v dokumentaci fwrite(), kterou jsem odkazoval? Vidíte tam ten cyklus? Připadá vám, že takový cyklus máte ve svém kódu?
-
Je mi líto, ale žádné úžasné řešení asi neexistuje.
Funkce fwrite() je jen alias na php_stream_write() a ten nijak zvlášť neřeší důvod nezápisu.
Funkce file_put_contents() sice zařve, že se nepovedlo zapsat ale přičinu, "possibly out of free disk space" si bohapustě vycucá z prstu. Je fakt, že to bude nejčastější příčina, protože práva etc si zjistíš už při fopen().
-
Opakování zápisu je použito už v tom kódu
Ne, není. Jak jste přišel na to, že při druhém volání se zapíše vše? Volání se musí opakovat tak dlouho, dokud nejsou zapsaná všechna data. Používají se k tomu cykly.
Doufám @andreaw.fean, že tě nenapadne se jeho radou řídit :-)
-
<heap of sh*t snipped>
Poslechni Jirsáku, tady maj něco pro tebe (https://ona.idnes.cz/foto.aspx?r=modni-trendy&c=A180627_104815_modni-trendy_kace&foto=KAC744567_profimedia_0279978734.jpg) - možná bys mohl být ohleduplný k ostatním a taky na svůj hormonální cyklus upozornit... Ono je to nesnesitelné i normálně, ale dneska už jseš opravdu zralej na ránu bazukou.
:o ??? ::)
-
Je mi líto, ale žádné úžasné řešení asi neexistuje.
Funkce fwrite() je jen alias na php_stream_write() a ten nijak zvlášť neřeší důvod nezápisu.
Funkce file_put_contents() sice zařve, že se nepovedlo zapsat ale přičinu, "possibly out of free disk space" si bohapustě vycucá z prstu. Je fakt, že to bude nejčastější příčina, protože práva etc si zjistíš už při fopen().
Pokud skutečně dojde k chybě (což zjistíte testem, zda hodnota vrácená funkci fwrite() je FALSE), bude nejspíš kód chyby v posix_get_last_error(). PHPčkové fwrite je jenom obálka nad libc fwrite(), která vrací chybu v errno, a tuhle hodnotu vrací právě posix_get_last_error().
-
Doufám @andreaw.fean, že tě nenapadne se jeho radou řídit :-)
Bacha na to, povídat si sám se sebou, to už je nemoc…
-
Je mi líto, ale žádné úžasné řešení asi neexistuje.
Funkce fwrite() je jen alias na php_stream_write() a ten nijak zvlášť neřeší důvod nezápisu.
Funkce file_put_contents() sice zařve, že se nepovedlo zapsat ale přičinu, "possibly out of free disk space" si bohapustě vycucá z prstu. Je fakt, že to bude nejčastější příčina, protože práva etc si zjistíš už při fopen().
Pokud skutečně dojde k chybě (což zjistíte testem, zda hodnota vrácená funkci fwrite() je FALSE), bude nejspíš kód chyby v posix_get_last_error(). PHPčkové fwrite je jenom obálka nad libc fwrite(), která vrací chybu v errno, a tuhle hodnotu vrací právě posix_get_last_error().
Není. Nezjistíš.
-
Opakování zápisu je použito už v tom kódu
Ne, není. Jak jste přišel na to, že při druhém volání se zapíše vše? Volání se musí opakovat tak dlouho, dokud nejsou zapsaná všechna data. Používají se k tomu cykly.
Doufám @andreaw.fean, že tě nenapadne se jeho radou řídit :-)
Udělat si tam cyklus? Nejsem blbej.
Problém skutečně byl v tom nedostatku místa.
Přidal jsem si tam test pomocí funkce disk_free_space. Problém to nevyřeší, ale budu vědět co je to za problém.
-
fwrite() return values jsou docela zmatené, obojí false a 0 znamenají chybu. false je chyba v parametrech, zatímco 0 je chyba provádění (typicky chyba vrácená OS - out of space apod.). Více detailů první komentář v dokumentaci. 0 jako korektní hodnota je nesmysl, protože vždycky se musí něco zapsat. V případě, že by došlo k blokování a je nastaven NONBLOCK, vrací se chyba EAGAIN. Předpokládám, že v rámci "kompatibility" je dobré ošetřít false a 0 stejně :-)
V tom kódu je třeba zpracovat error_get_last na místě, kde se vyhazuje výjimka, tam se vrátí asi finální chyba. Kromě toho jsou tam k opravě následující:
- loop while writte != 0 místo jednoho if (i když technicky vzato běžné OS zapíšou všechno co jde, pokud jde o normální soubor, jinak je to u pipe, socket apod)/li]
- nevím, jak je to u php s konverzí znakových sad a DOS/UNIX konverzí, soubor musí být v každém případě otevřen jako binary.
- ... a podobně jako v předchozím - viz poslední argument, který vypíná magic chování, které rovněž může ovlivnit délku zápisu.
-
fwrite() return values jsou docela zmatené, obojí false a 0 znamenají chybu. false je chyba v parametrech, zatímco 0 je chyba provádění (typicky chyba vrácená OS - out of space apod.). Více detailů první komentář v dokumentaci.
Ten komentář je 8 let starý, chování se mohlo změnit. Připadá mi divné, že by se za 8 let tak zásadní chyba v dokumentaci neopravila. Ale neověřoval jsem to.
0 jako korektní hodnota je nesmysl, protože vždycky se musí něco zapsat.
Je možné, že nadstavba PHP chování mění, ale standardní POSIXový write může vrátit i nulu jako normální hodnotu – zapsat se nic nemusí. Při nedostatku místa OS vrátí -1 a v errno bude ENOSPC.
Při zápisu do souboru se bude OS snažit zapsat vše, ale nemusí se mu to podařit. O to je to horší, že to bude skoro vždy fungovat, ale pak se někdy „nepochopitelně“ zapíše jen část.
-
fwrite() return values jsou docela zmatené, obojí false a 0 znamenají chybu. false je chyba v parametrech, zatímco 0 je chyba provádění (typicky chyba vrácená OS - out of space apod.). Více detailů první komentář v dokumentaci.
Ten komentář je 8 let starý, chování se mohlo změnit. Připadá mi divné, že by se za 8 let tak zásadní chyba v dokumentaci neopravila. Ale neověřoval jsem to.
0 jako korektní hodnota je nesmysl, protože vždycky se musí něco zapsat.
Je možné, že nadstavba PHP chování mění, ale standardní POSIXový write může vrátit i nulu jako normální hodnotu – zapsat se nic nemusí. Při nedostatku místa OS vrátí -1 a v errno bude ENOSPC.
Při zápisu do souboru se bude OS snažit zapsat vše, ale nemusí se mu to podařit. O to je to horší, že to bude skoro vždy fungovat, ale pak se někdy „nepochopitelně“ zapíše jen část.
Nemůžeš tu podmínku hodit do cyklu. Musíš testovat, zda návratová hodnota je větší jak 0 - jak píše @kvr kvr, pak teprve můžeš zkusit zapsat znova. @andreaw.fean zvolil opačnou strategii, a při neúspěchu prostě končí - což je v pořádku.
Ty posixový funkce nefungují.
fwrite() není wrapper nad posixovým fwrite...
Sečteno a podtrženo problém je v tom, že tvá rada byla úplně špatná.
-
Nemůžeš tu podmínku hodit do cyklu.
Nízkoúrovňové čtení nebo zápis z/do streamnů (soubory, sokety apod.) vždy může zpracovat menší množství dat, než bylo požadováno, proto se musí opakovat v cyklu. To snad vědí programátoři už ve školce.
Musíš testovat, zda návratová hodnota je větší jak 0 - jak píše @kvr kvr, pak teprve můžeš zkusit zapsat znova.
U toho nízkoúrovňového zápisu představuje chybu jen záporná hodnota. Je možné, že PHP to má zařízené tak, aby se vždy zapsal alespoň jeden bajt, a nula také znamená chybu, ale pak je vážná chyba v dokumentaci, že to tam není napsané.
@andreaw.fean zvolil opačnou strategii, a při neúspěchu prostě končí - což je v pořádku.
V pořádku ovšem není, že končí chybou i v případě úspěšného (částečného) zápisu.
Ty posixový funkce nefungují.
Jasně, vy jste expert na všechno a chyba je v Linuxu nebo jakou implementaci POSIXu myslíte. To sedí od někoho, kdo ani neví, jak zkopírovat data z jednoho souboru do druhého.
Sečteno a podtrženo problém je v tom, že tvá rada byla úplně špatná.
Že vám programování moc nejde jsem pochopil už v sousední diskusi. Že nezvládnete ani takovéhle základy a nechápete, v čem je problém, to mne překvapilo. Vaše hodnocení mých rad je mi tím pádem úplně jedno.
-
Nemůžeš tu podmínku hodit do cyklu.
Nízkoúrovňové čtení nebo zápis z/do streamnů (soubory, sokety apod.) vždy může zpracovat menší množství dat, než bylo požadováno, proto se musí opakovat v cyklu. To snad vědí programátoři už ve školce.
Děti ve školce znají věc jako zacyklení. Ty ne?
Musíš testovat, zda návratová hodnota je větší jak 0 - jak píše @kvr kvr, pak teprve můžeš zkusit zapsat znova.
U toho nízkoúrovňového zápisu představuje chybu jen záporná hodnota. Je možné, že PHP to má zařízené tak, aby se vždy zapsal alespoň jeden bajt, a nula také znamená chybu, ale pak je vážná chyba v dokumentaci, že to tam není napsané.
Takže doporučuješ kód, který v případě, že dojde místo na disku, tak se zacyklí?
@andreaw.fean zvolil opačnou strategii, a při neúspěchu prostě končí - což je v pořádku.
V pořádku ovšem není, že končí chybou i v případě úspěšného (částečného) zápisu.
Furt lepší, než co navrhuješ ty.
Ty posixový funkce nefungují.
Jasně, vy jste expert na všechno a chyba je v Linuxu nebo jakou implementaci POSIXu myslíte. To sedí od někoho, kdo ani neví, jak zkopírovat data z jednoho souboru do druhého.
Sečteno a podtrženo problém je v tom, že tvá rada byla úplně špatná.
Že vám programování moc nejde jsem pochopil už v sousední diskusi. Že nezvládnete ani takovéhle základy a nechápete, v čem je problém, to mne překvapilo. Vaše hodnocení mých rad je mi tím pádem úplně jedno.
Když to říkáš.
-
Nemůžeš tu podmínku hodit do cyklu. Musíš testovat, zda návratová hodnota je větší jak 0 - jak píše @kvr kvr, pak teprve můžeš zkusit zapsat znova
Pokus o zápis nemusí zapsat všechna data, takže bežné a správné řešení je v cyklu zapisovat to, co zbývá zapsat, dokud není zapsáno všechno a pokud při zápisu aktuálního "kousku" dojde k chybě, tak cyklus přerušit. Co je na tom k nepochopení?
-
Mimo špatného "algoritmu", je $handle globalní proměnná, která v té funkci write není vidět, takže by to nemělo fungovat vůbec a případně ještě řvát.
Jinak je v PHP taky funkce file_put_contents, která tě takového šaškování zbaví.
-
Nemůžeš tu podmínku hodit do cyklu. Musíš testovat, zda návratová hodnota je větší jak 0 - jak píše @kvr kvr, pak teprve můžeš zkusit zapsat znova
Pokus o zápis nemusí zapsat všechna data, takže bežné a správné řešení je v cyklu zapisovat to, co zbývá zapsat, dokud není zapsáno všechno a pokud při zápisu aktuálního "kousku" dojde k chybě, tak cyklus přerušit. Co je na tom k nepochopení?
Nekonečný cyklus.
-
...dojde k chybě, tak cyklus přerušit.
-
Mimo špatného "algoritmu", je $handle globalní proměnná, která v té funkci write není vidět, takže by to nemělo fungovat vůbec a případně ještě řvát.
Jinak je v PHP taky funkce file_put_contents, která tě takového šaškování zbaví.
To jsem to jen špatně přepsal.
file_put_contents se mi nehodí, protože pracuji s tím handle. A pokud je to tak jak píše BoneFlute, že stejně jen vypíše chybovku na výstup, tak se mi to nehodí už vůbec a nebudu to tedy přepisovat.
-
Děti ve školce znají věc jako zacyklení. Ty ne?
K zacyklení dojde jedině tehdy, pokud v cyklu není nikdy splněna podmínka, která by cyklus ukončila.
Teda „programátor“, který se bojí používat cykly, protože neumí napsat ukončovací podmínku, to je fakt něco.
Takže doporučuješ kód, který v případě, že dojde místo na disku, tak se zacyklí?
Z mých komentářů nic takového neplyne. Pokud funkce fwrite() v PHP je implementovaná tak, jak je popsaná v dokumentaci, vrátí v případě zaplnění disku FALSE. I kdyby fungovala jinak a v případě chyby mohla vracet i nulu, pořád se akorát ten test na úspěch funkce upraví tak, zda vrátila hodnotu větší než nula.
Furt lepší, než co navrhuješ ty.
Ne, kód, který občas náhodně nefunguje, není lepší.
-
...dojde k chybě, tak cyklus přerušit.
Pokud je plnej disk, tak to fwrite() neeviduje jako chybu.
A jako vůbec, von se tu dotyčný táže, jak zjistit že je nějaká chyba, a vy mu radíte, že má blbě algoritmus, kterej nakonec opravíte do ještě horšího stavu. To myslíte vážně?
-
Děti ve školce znají věc jako zacyklení. Ty ne?
K zacyklení dojde jedině tehdy, pokud v cyklu není nikdy splněna podmínka, která by cyklus ukončila.
Teda „programátor“, který se bojí používat cykly, protože neumí napsat ukončovací podmínku, to je fakt něco.
To jsi jako sebral kde?
Takže doporučuješ kód, který v případě, že dojde místo na disku, tak se zacyklí?
Z mých komentářů nic takového neplyne. Pokud funkce fwrite() v PHP je implementovaná tak, jak je popsaná v dokumentaci, vrátí v případě zaplnění disku FALSE. I kdyby fungovala jinak a v případě chyby mohla vracet i nulu, pořád se akorát ten test na úspěch funkce upraví tak, zda vrátila hodnotu větší než nula.
No konečně to chápeš. Že se vůbec pouštíš do něčeho, čemu nerozumíš.
Furt lepší, než co navrhuješ ty.
Ne, kód, který občas náhodně nefunguje, není lepší.
Beru na vědomí. Zacyklení je lepší.
-
Pokud je plnej disk, tak to fwrite() neeviduje jako chybu.
Takže pokračuje v zápisu za konec disku? Nebo co přesně fwrite() vrátí, když je plnýdisk?
A jako vůbec, von se tu dotyčný táže, jak zjistit že je nějaká chyba, a vy mu radíte, že má blbě algoritmus, kterej nakonec opravíte do ještě horšího stavu. To myslíte vážně?
Ne, ten algoritmus byl špatně a tvrdil, že došlo k chybě, i když to není pravda. Když se bude volat fwrite() v cyklu a testovat, zda se něco zapsalo nebo došlo k chybě, bude to fungovat správně.
Vy už byste se k tomu měl přestat vyjadřovat, když je pro vás nepochopitelný i obyčejný cyklus, nemáte k tomu co říci.
-
Pokud je plnej disk, tak to fwrite() neeviduje jako chybu.
Takže pokračuje v zápisu za konec disku? Nebo co přesně fwrite() vrátí, když je plnýdisk?
[facepalm]
A jako vůbec, von se tu dotyčný táže, jak zjistit že je nějaká chyba, a vy mu radíte, že má blbě algoritmus, kterej nakonec opravíte do ještě horšího stavu. To myslíte vážně?
Ne, ten algoritmus byl špatně a tvrdil, že došlo k chybě, i když to není pravda. Když se bude volat fwrite() v cyklu a testovat, zda se něco zapsalo nebo došlo k chybě, bude to fungovat správně.
Vy už byste se k tomu měl přestat vyjadřovat, když je pro vás nepochopitelný i obyčejný cyklus, nemáte k tomu co říci.
Fakt žeru tyhle lidi s bujnou fantazií.
-
0 jako korektní hodnota je nesmysl, protože vždycky se musí něco zapsat.
Je možné, že nadstavba PHP chování mění, ale standardní POSIXový write může vrátit i nulu jako normální hodnotu – zapsat se nic nemusí. Při nedostatku místa OS vrátí -1 a v errno bude ENOSPC.
Při zápisu do souboru se bude OS snažit zapsat vše, ale nemusí se mu to podařit. O to je to horší, že to bude skoro vždy fungovat, ale pak se někdy „nepochopitelně“ zapíše jen část.
POSIXový write() může vrátit 0 v případě, že velikost zapisovaných dat byla 0. Pokud OS nemůže nic zapsat v případě neprázdných argumentů, má vrátit chybu EAGAIN, aby program mohl počkat přes select() (nebo podobnou funkci) na to, až zápis bude možný. Kdyby vracel 0, tak by to skončilo bez kontroly v busy loop.
To, že PHP si překládá chybu na 0, je jiná věc (nejspíš, aby se dalo snadno testovat v podmínce), ale v zásadě to na věci nic nemění - zapisovat prázdné data je stejně nesmysl.
-
POSIXový write() může vrátit 0 v případě, že velikost zapisovaných dat byla 0. Pokud OS nemůže nic zapsat v případě neprázdných argumentů, má vrátit chybu EAGAIN, aby program mohl počkat přes select() (nebo podobnou funkci) na to, až zápis bude možný. Kdyby vracel 0, tak by to skončilo bez kontroly v busy loop.
POSIXový write může vrátit 0 i v případě, že je požadován zápis nenulového počtu bajtů. A znamená to jen, že bylo zapsáno nula bajtů – není to chyba.
On success, the number of bytes written is returned (zero indicates nothing was written). It is not an error if this number is smaller than the number of bytes requested; this may happen for example because the disk device was filled. See also NOTES.
On error, -1 is returned, and errno is set appropriately.
Vrácení 0 by měl být výjimečný případ, ale počítá se mezi úspěšné výsledky volání. Nekonečnému cyklu zabrání to, že takový stav by byl jen dočasný, a v některém z příštích cyklů by write mělo něco zapsat nebo skončit chybou.
-
Pokud je plnej disk, tak to fwrite() neeviduje jako chybu.
Tak vrátí nulu, kterou vyhodnotíš jako chybu! Jo, ten příklad v dokumentaci je na hovno.
A jako vůbec, von se tu dotyčný táže, jak zjistit že je nějaká chyba, a vy mu radíte, že má blbě algoritmus, kterej nakonec opravíte do ještě horšího stavu. To myslíte vážně?
Protože v první řadě to má tak blbě, že to co vidí jako chybu, nemusí být chyba.
Když jsi tak vykulenej z trviálních věcí, tak se k tomu prostě nevyjadřuj, protože o tom víš kulový a jen se ztrapňuješ.
-
Vrácení 0 by měl být výjimečný případ, ale počítá se mezi úspěšné výsledky volání.
fwrite v PHP při záporné návratovce write vrací nulu. Šlo by si s tím hrát, ale prakticky nemá smysl to hned vyhodnodit jako konečnou chybu.
-
vyhodnodit jako konečnou chybu.
nevyhodnotit
-
0 jako korektní hodnota je nesmysl, protože vždycky se musí něco zapsat.
Je možné, že nadstavba PHP chování mění, ale standardní POSIXový write může vrátit i nulu jako normální hodnotu – zapsat se nic nemusí. Při nedostatku místa OS vrátí -1 a v errno bude ENOSPC.
Při zápisu do souboru se bude OS snažit zapsat vše, ale nemusí se mu to podařit. O to je to horší, že to bude skoro vždy fungovat, ale pak se někdy „nepochopitelně“ zapíše jen část.
POSIXový write() může vrátit 0 v případě, že velikost zapisovaných dat byla 0. Pokud OS nemůže nic zapsat v případě neprázdných argumentů, má vrátit chybu EAGAIN, aby program mohl počkat přes select() (nebo podobnou funkci) na to, až zápis bude možný. Kdyby vracel 0, tak by to skončilo bez kontroly v busy loop.
To, že PHP si překládá chybu na 0, je jiná věc (nejspíš, aby se dalo snadno testovat v podmínce), ale v zásadě to na věci nic nemění - zapisovat prázdné data je stejně nesmysl.
Jen doplním - Pokud zapíšu alespoň jeden bajt, tak je to v pořádku a můžu zkusit znova. Ale pokud se nepovede zápis ani jednoho, není důvod k optimismu si myslet že v příštím kole to bude lepší. Takže dávám tak dva tři pokusy maximálně.
-
fwrite v PHP při záporné návratovce write vrací nulu. Šlo by si s tím hrát, ale prakticky nemá smysl to hned vyhodnodit jako konečnou chybu.
Díky, konečně někdo napsal, jak to je, ne jen nějaké dohady.
Předpokládám, že to byl překlep, a že jste chtěl napsat, že 0 jako návratová hodnota PHP fwrite() by měla být hned vyhodnocena jako chyba.
Každopádně mi to teda připadá jako dost zásadní chyba v dokumentaci PHP. Jednoduché porovnání fwrite() == FALSE sice bude fungovat díky automatickému přetypování, ale třeba už to, co je tam uvedené jako příklad, kvůli === fungovat nebude.
-
fwrite() return values jsou docela zmatené, obojí false a 0 znamenají chybu. false je chyba v parametrech, zatímco 0 je chyba provádění (typicky chyba vrácená OS - out of space apod.). Více detailů první komentář v dokumentaci. 0 jako korektní hodnota je nesmysl, protože vždycky se musí něco zapsat. V případě, že by došlo k blokování a je nastaven NONBLOCK, vrací se chyba EAGAIN. Předpokládám, že v rámci "kompatibility" je dobré ošetřít false a 0 stejně :-)
V tom kódu je třeba zpracovat error_get_last na místě, kde se vyhazuje výjimka, tam se vrátí asi finální chyba. Kromě toho jsou tam k opravě následující:
- loop while writte != 0 místo jednoho if (i když technicky vzato běžné OS zapíšou všechno co jde, pokud jde o normální soubor, jinak je to u pipe, socket apod)/li]
- nevím, jak je to u php s konverzí znakových sad a DOS/UNIX konverzí, soubor musí být v každém případě otevřen jako binary.
- ... a podobně jako v předchozím - viz poslední argument, který vypíná magic chování, které rovněž může ovlivnit délku zápisu.
Tak v mém případě se jedná o normální soubor, takže předpokládám, že netřeba to prožívat.
A já mám právě problém v tom, že mi to žádnou chybu nevrátí. To je to co řeším.[/list]
-
A já mám právě problém v tom, že mi to žádnou chybu nevrátí. To je to co řeším.
Že došlo k chybě zjistíte tak, že otestujete výsledek volání fwrite(), zda je to FALSE nebo 0. Když funkce vrátí hodnotu větší než nula, opakujete její volání v cyklu a zapíšete další část.
-
A já mám právě problém v tom, že mi to žádnou chybu nevrátí. To je to co řeším.
Že došlo k chybě zjistíte tak, že otestujete výsledek volání fwrite(), zda je to FALSE nebo 0. Když funkce vrátí hodnotu větší než nula, opakujete její volání v cyklu a zapíšete další část.
A jak zjistím, jaká je to chyba?
-
A jak zjistím, jaká je to chyba?
Zkusil bych error_get_last() nebo posix_get_last_error().
-
A jak zjistím, jaká je to chyba?
Zkusil bych error_get_last() nebo posix_get_last_error().
To jsem zkoušel. To mi vrací success.
-
To jsem zkoušel. To mi vrací success.
Obě dvě? Voláte je až po té, co vám fwrite() vrátí false nebo 0? Bylo by lepší, kdybyste sem dal kód, který zkoušíte.
-
A jak zjistím, jaká je to chyba?
Zkusil bych error_get_last() nebo posix_get_last_error().
Už ti tady asi 5x psali, že to nefunguje. Vyměň si tampón. ;D ::)
-
POSIXový write může vrátit 0 i v případě, že je požadován zápis nenulového počtu bajtů. A znamená to jen, že bylo zapsáno nula bajtů – není to chyba.
A ve kterém případě by se to mělo stát? POSIX také specifikuje, za jakých okolností je možné zapsat méně než požadovaný počet bajtů, a všechny při nezapsaní ani jednoho bajtu vrací -1 a nastavují errno.
-
To jsem zkoušel. To mi vrací success.
Obě dvě? Voláte je až po té, co vám fwrite() vrátí false nebo 0? Bylo by lepší, kdybyste sem dal kód, který zkoušíte.
Máte ho hned v mém prvním příspěvku.
-
POSIX také specifikuje, za jakých okolností je možné zapsat méně než požadovaný počet bajtů
Kde to specifikuje?
-
Máte ho hned v mém prvním příspěvku.
Ano, ale ten kód je špatně, tam netestujete, zda došlo k chybě. A nevolá se tam ani error_get_last() nebo posix_get_last_error().
-
Radši vám ten opravený kód napíšu, jinak to bude na dlouho…
$tmpdir = sys_get_temp_dir();
$tmpname = tempnam($tmpdir, 'app-');
$handle = fopen($tmpname, 'a');
// velikost $s je obvykle 2096 bajtů
function write($handle, $s)
{
$len = strlen($s);
while ( $len > 0 )
{
$wrote = fwrite($handle, $s);
if ( $wrote === false || $wrote == 0 )
{
var_dump(error_get_last());
var_dump(posix_get_last_error());
throw new RuntimeException('Zápis do souboru skončil chybou.');
}
$s = substr($s, $wrote)
$len = strlen($s);
}
}
-
Radši vám ten opravený kód napíšu, jinak to bude na dlouho…
Výsledek je stejný.
-
:)
;) ;)
:D :D :D
;D ;D ;D ;D
:P :P :P
:-* :-*
8)
-
Kouknul jsem do zdrojáku PHP a fwrite nakonec vede na
int bytes_written = write(data->fd, buf, count);
if (bytes_written < 0) return 0;
return (size_t) bytes_written;
tj. na https://linux.die.net/man/2/write (https://linux.die.net/man/2/write)
Když se koukneš na https://linux.die.net/man/3/explain_write (https://linux.die.net/man/3/explain_write) tak bys asi rád znal hodnotu errno (errno.h), což by právě měla dělat posix_get_last_error() , jestli ta ale nevrací chybový kód, tak možná nezbyde než se smířit s "těžký život ve světě PHP". ;)
-
Ještě bych dodal, že errno mění kdejaká funkce z libc a i PHP samotné, takže hodnotu vrácenou z posix_get_last_error() bych si pro jistotu zapamatoval ihned po volání fwrite().
-
POSIXový write může vrátit 0 i v případě, že je požadován zápis nenulového počtu bajtů. A znamená to jen, že bylo zapsáno nula bajtů – není to chyba.
On success, the number of bytes written is returned (zero indicates nothing was written). It is not an error if this number is smaller than the number of bytes requested; this may happen for example because the disk device was filled. See also NOTES.
On error, -1 is returned, and errno is set appropriately.
Vrácení 0 by měl být výjimečný případ, ale počítá se mezi úspěšné výsledky volání. Nekonečnému cyklu zabrání to, že takový stav by byl jen dočasný, a v některém z příštích cyklů by write mělo něco zapsat nebo skončit chybou.
Zapsání nula bytes chyba je a OS by měl vrátit důvod, proč k tomu došlo. Podobné je to u interrupted by signal - pokud se aspoň jeden byte zapsal, vrací délku zapsaných dat, v opačném případě vrátí chybu EINTR. Návratová hodnota "nic se nepovedlo, ale neřeknu proč" není hodna implementace slušného OS. Jak jsem psal výše, něco takového by vedlo k busy loop a nesmyslnému aplikačnímu kódu. write() může skončit úspěšně i v případě předchozí chyby, proto tam ty chybové kódy jsou, aby se aplikace mohla rozhodnout, co má zkusit znovu a jak (EAGAIN, EINTR, ENOSPC).
Na druhé straně je třeba říct, že dokumentace (citace je z Linux man page, nikoliv POSIX specifikace) by mohla být napsaná jasněji, že jde o speciální případ prázdných dat (které můžou mít u speciálních file descriptors zvláštní význam - například EOF).
-
Výsledek je stejný.
V tom případě jste nezkoušel tu variantu s posix_get_last_error(), protože ta funkce vrací číslo, takže nemůže být výsledek stejný, jako když zavoláte variantu s funkcí error_get_last(), která vrací pole.
Pokud by vám i posix_get_last_error() vracela, že k žádné chybě nedošlo, máte smůlu, protože PHP mezitím zavolalo nějakou jinou POSIXovou funkci, která výsledek volání write() překryla.
-
Zapsání nula bytes chyba je
To je napsané kde?
Když se podíváte na ty příklady v manuálové stránce explain_write, neúspěšný zápise se tam rozpoznává tak, že návratový kód je menší než nula. Myslíte, že to v té manuálové stránce je špatně?
Jak jsem psal výše, něco takového by vedlo k busy loop a nesmyslnému aplikačnímu kódu.
Ne nutně. Nikdo netvrdí, že když write() vrátí nulu, musí ji vrátit i v příštím cyklu – v příštím cyklu už může být zápis úspěšnější a zapíše alespoň něco, nebo už se alespoň bude vědět příčina chyby a write() vrátí chybu plus třeba EAGAIN.
write() může skončit úspěšně i v případě předchozí chyby, proto tam ty chybové kódy jsou, aby se aplikace mohla rozhodnout, co má zkusit znovu a jak (EAGAIN, EINTR, ENOSPC).
Na druhé straně je třeba říct, že dokumentace (citace je z Linux man page, nikoliv POSIX specifikace) by mohla být napsaná jasněji
V té manuálové stránce je jasně napsáno, že i při úspěšném volání se může vrátit nula. Ale mohlo by tam být explicitně napsáno, že se pak má volání opakovat, stejně jako pro jiné případy,když nebylo zapsáno vše. Dokumentace k jiným knihovnám tu nulu často neřeší vůbec.
V POSIX specifikaci jsem také nenašel nic o tom, že by nula byla chyba.
-
........... (https://www.youtube.com/watch?v=j4UpBVN-qE8&feature=youtu.be&t=10s)
;D ;D ;D ;D ;D
:D :D :D :D :D
:P :P :P :P :P
-
Výsledek je stejný.
V tom případě jste nezkoušel tu variantu s posix_get_last_error()...
Jestli on tazatel nemyslí, že výsledek je stejný, tedy i s touto implementací mu došlo na disku místo ;-)
-
Výsledek je stejný.
V tom případě jste nezkoušel tu variantu s posix_get_last_error()...
Jestli on tazatel nemyslí, že výsledek je stejný, tedy i s touto implementací mu došlo na disku místo ;-)
Tak já myslím, že se od Filipa Jirsáka kromě siláckých řečí nic zajímavého nedozvím. Všechno mu to musím vysvětlovat po lopatě a nic z toho.
Tak jsem tam zatím jen upravil hlášku, kontroluju místo na disku pomocí disk_free_space(). Nic lepšího asi nevymyslíme.
Kdyby někoho ještě napadl nějaký způsob, třeba nějaká zahrabaná globální proměnná, nebo tak něco.
-
Tak já myslím, že se od Filipa Jirsáka kromě siláckých řečí nic zajímavého nedozvím. Všechno mu to musím vysvětlovat po lopatě a nic z toho.
Dozvěděl jste se, kde máte v kódu chybu, proč je to chyba a jak jí opravit. Vysvětlovat jste nic nemusel, naopak jste na mnohé dotazy odpovídal až na několikátý pokus, případně vůbec. Vaše „výsledek stejný“ má k vyčerpávajícímu popisu chyby opravdu velmi daleko – i mnozí uživatelé chápou, že musí napsat, co přesně dělali a jaký byl výsledek. Pro programátora by to měla být úplná samozřejmost.
-
Já teda obdivuju trpělivost pana Jirsáka s tazatelem a několika individui jako Lol Phirae a BoneFlute. Já osobně bych se už na jakoukoliv pomoc vy..., protože tazatel není schopen přečíst a porozumět psanému textu, nápodobně BoneFlute, který nepřinese jediný faktický argument, který by dokázal, že pan Jirsák nemá pravdu a jen tu sprostě uráží. Pánové, fakt nechápu smysl Vašeho počínání, tohle fórum má sloužit k výměně zkušeností a Vy informace a rady ignorujete.
-
Kdyby někoho ještě napadl nějaký způsob, třeba nějaká zahrabaná globální proměnná, nebo tak něco.
Zahrabaná globální proměnná se jmenuje errno, kód tady máte, někteří si dokonce dali práci a našli, jak je implementované fwrite() a Vy se omezíte na "výsledek je stejný". To mi nepřijde příliš motivující. Obtěžovalo by Vás napsat, co vrací fwrite() poté, co dojde místo a co obsahuje errno?
-
To je zas diskuse. Připomíná mi to jistou scénu ze Ztráty třídní knihy... Jeden se zeptá a pak nadává lidem, co se mu snaží poradit. Druhý sofistikovaně teoretizuje z manuálu, zdrojáku, ale že by ho napadlo si svoji radu prakticky vyzkoušet, to ne. Udělal jsem to tedy za vás. Kód:
<?php
echo "PHP VERSION: ".phpversion()."\n";
$FILE_NAME = '/my_small_partition/test';
$s = '0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789';
$len = strlen($s);
$file = fopen($FILE_NAME , 'w');
for(;;) {
$wrote = fwrite($file, $s);
if ($wrote <= 0) {
$stored_posix_get_last_error = posix_get_last_error();
$stored_error_get_last = error_get_last();
$stored_errno = $errno;
echo "wrote: ";
var_dump($wrote);
echo "errno: ";
var_dump($stored_errno);
echo "posix_get_last_error: ";
var_dump($stored_posix_get_last_error);
echo "error_get_last: ";
var_dump($stored_error_get_last);
break;
}
}
fclose($file);
unlink($FILE_NAME);
?>
Výsledek:
PHP VERSION: 7.0.18-0ubuntu0.16.04.1
PHP Notice: Undefined variable: errno in test.php on line 15
wrote: int(0)
errno: NULL
posix_get_last_error: int(0)
error_get_last: NULL
(Padá to opravdu na zaplnění disku. Chyby si nejdřív uložím do proměnných aby nedošlo k volání knihovny při echo.)
No a včil mudrujte.
-
Já myslim že tam máš málo cyklů...
;D
;D ;D
;D ;D ;D
;D ;D
;D
-
Druhý sofistikovaně teoretizuje z manuálu, zdrojáku, ale že by ho napadlo si svoji radu prakticky vyzkoušet, to ne. Udělal jsem to tedy za vás.
Udělal jste to za tazatele. Když má spoustu blbých keců a ani neumí napsat, co vyzkoušel, nemíním si kvůli němu ještě instalovat PHP a něco zkoušet.
-
Udělal jste to za tazatele. Když má spoustu blbých keců a ani neumí napsat, co vyzkoušel, nemíním si kvůli němu ještě instalovat PHP a něco zkoušet.
Být tebou Jirsák, tak mlčím a šoupu nohama, protože se právě ukázalo, že jsi tu celou dobu velkohubě radil hovadiny.
-
Být tebou Jirsák, tak mlčím a šoupu nohama, protože se právě ukázalo, že jsi tu celou dobu velkohubě radil hovadiny.
Mohl byste být přesnější, co z toho, co jsem radil, byla hovadina? Tazatel měl špatně napsaný zápis do souboru, to jsem mu poradil, jak opravit – ten původní kód by fungoval jedině tehdy, kdyby se jedním voláním fwrite() podařilo zapsat všechna data bez chyby. Ve všech ostatních případech by ten kód dělal nesmysly. Dále jsem tazateli poradil, že až si kód opraví tak, aby opravdu detekoval selhání fwrite(), ať vyzkouší, zda přesnou chybu nezjistí z funkcí posix_get_last_error() nebo error_get_last(). Že to doteď tazatel nevyzkoušel nebo nenapsal výsledek toho pokusu, za to nemůžu. A povinnost zkoušet to za tazatele fakt nemám, už tak dostal mnohem lepší rady, než by si svým chováním zasloužil.
-
Mohl byste být přesnější, co z toho, co jsem radil, byla hovadina?
Možná bude jednodušší popsat, co z "rad" hovadina nebyla... To si ušetříme hodně práce. ;D
-
Tazatel měl špatně napsaný zápis do souboru, to jsem mu poradil, jak opravit – ten původní kód by fungoval jedině tehdy, kdyby se jedním voláním fwrite() podařilo zapsat všechna data bez chyby. Ve všech ostatních případech by ten kód dělal nesmysly.
Na což se neptal, nesouviselo to s tím na co se ptal, a ani to nijak nepomohlo s jeho problémem. Rada na nic.
Dále jsem tazateli poradil, že až si kód opraví tak, aby opravdu detekoval selhání fwrite(), ať vyzkouší, zda přesnou chybu nezjistí z funkcí posix_get_last_error() nebo error_get_last(). Že to doteď tazatel nevyzkoušel nebo nenapsal výsledek toho pokusu, za to nemůžu.
Což udělal, a podle jeho reakcí soudě vyzkoušel. Že tvrdíš, že to nevyzkoušel, že tvrdíš, že to nenapsal, přestože to má uvedené hned v prvním příspěvku - to už je tvůj problém. A tvá drzost.
A povinnost zkoušet to za tazatele fakt nemám, už tak dostal mnohem lepší rady, než by si svým chováním zasloužil.
Jaký chování? Že není spokojený s radou, která prostě nefunguje? Když by se všichni chovali jako on, tak by bylo krásně na foru.
Víš, problém jsi tu ty, ne ostatní.
-
Na což se neptal, nesouviselo to s tím na co se ptal, a ani to nijak nepomohlo s jeho problémem. Rada na nic.
Vy jste stále ještě nepochopil, jaký problém se tu řeší. Takže vaše názory na to, co pomohlo a co ne, jsou k ničemu.
Což udělal, a podle jeho reakcí soudě vyzkoušel. Že tvrdíš, že to nevyzkoušel, že tvrdíš, že to nenapsal, přestože to má uvedené hned v prvním příspěvku - to už je tvůj problém. A tvá drzost.
Kdyby napsal výsledky toho pokusu, napsal by fwrite() zaplnilo disk a vrátilo v poslední smyčce 0 a posix_get_last_error() také 0, v druhém pokusu vrátilo po zaplnění disku error_get_last() hodnotu NULL. To by to ovšem nejdřív musel vyzkoušet, že… Kód v prvním příspěvku by mohl hlásit chybu zaplnění disku jedině v případě, že by disk byl plný už před začátkem zápisu. Kdyby se disk zaplnil už voláním té funkce fwrite(), selhalo by už druhé volání fwrite(), a tam žádný výpis chybového kódu není. Programátor to musí vidět na první pohled. Takže vaše snaha najít nějaký programovací jazyk, kde byste vůbec nemusel programovat, protože vám to nejde, je pochopitelná. A to ještě pořád nejsem drzý.
Jaký chování? Že není spokojený s radou, která prostě nefunguje? Když by se všichni chovali jako on, tak by bylo krásně na foru.
Jestli ta rada funguje nebo nefunguje by mohl zjistit teprve tehdy, až by ten kód opravil. Což se nestalo. Pokud nepochopil, v čem je problém, mohl se slušně zeptat. Což se také nestalo.
Víš, problém jsi tu ty, ne ostatní.
Můj problém je, že se tu vybavuju s někým, kdo si o sobě myslí, že je mistr světa, a přitom si ani neumí zavázat tkaničky. Pozdravujte Jéčko na ignorlistu.
-
No a včil mudrujte.
No tak hurá, aspoň někdo to zkusil! Odtud:
https://github.com/php/php-src/blob/master/ext/standard/file.c#L1189
a odtud:
https://github.com/php/php-src/blob/master/main/streams/streams.c#L1189
#define php_stream_write(stream, buf, count) _php_stream_write(stream, (buf), (count))
to vypadá, že se pracuje s FILE, nikoliv s fd.
Byl byste ochotný udělat ještě jeden pokus, kdy se soubor otevře pomocí dio_open() a odtud se teprve získá stream?
-
No a včil mudrujte.
No tak hurá, aspoň někdo to zkusil! Odtud:
https://github.com/php/php-src/blob/master/ext/standard/file.c#L1189
a odtud:
https://github.com/php/php-src/blob/master/main/streams/streams.c#L1189
#define php_stream_write(stream, buf, count) _php_stream_write(stream, (buf), (count))
to vypadá, že se pracuje s FILE, nikoliv s fd.
Byl byste ochotný udělat ještě jeden pokus, kdy se soubor otevře pomocí dio_open() a odtud se teprve získá stream?
Určitě!
Ale bohužel. Mám PHP verzi 5.6, tohle je pro < 5.1 (dle dokumentace). Pro jistotu jsem to i tak zkusil, člověk nikdy neví, ale už tam není no.
(Degradovat na 5.1 se mi nechce, a i kdyby to pomohlo, tak to stejně nebudu moct použít.)
-
Na což se neptal, nesouviselo to s tím na co se ptal, a ani to nijak nepomohlo s jeho problémem. Rada na nic.
Vy jste stále ještě nepochopil, jaký problém se tu řeší. Takže vaše názory na to, co pomohlo a co ne, jsou k ničemu.
Tak jeho rada (https://forum.root.cz/index.php?topic=18906.msg272378#msg272378) sice nebyla moc povzbudivá, ale alespoň byla k věci a normální.
-
Mám PHP verzi 5.6, tohle je pro < 5.1 (dle dokumentace). Pro jistotu jsem to i tak zkusil, člověk nikdy neví, ale už tam není no.
(Degradovat na 5.1 se mi nechce, a i kdyby to pomohlo, tak to stejně nebudu moct použít.)
Pardon. Přiznám se, že jsem nevšiml, že tahle část je obsolete. Teoreticky by mohlo jít použit eio_open() z https://pecl.php.net/package/eio a protože se tím krmí libev, předpokládám, že vrací file descriptor. Bez záruky, do kódu jsem se nedíval.
-
Pardon. Přiznám se, že jsem nevšiml, že tahle část je obsolete. Teoreticky by mohlo jít použit eio_open() z https://pecl.php.net/package/eio a protože se tím krmí libev, předpokládám, že vrací file descriptor. Bez záruky, do kódu jsem se nedíval.
Tak teda to EIO jsem zkusil. Funguje to hezky. Při vyčerpání místa to vrátí chybu, a tu lze přečíst pomocí eio_get_last_error(). Takhle by se mi to líbilo u to fwrite(), škoda, že to neumí no.
-
Mohl byste být přesnější, co z toho, co jsem radil, byla hovadina?
Prakticky všechno. Nejdřív jsi se tu točil na nějakém částečném zápisu, což ale problém vůbec nebyl. Ono totiž PHP, jak se zdá, tu smyčku dělá už interně ve funkci, kterou volá ten fwrite(): https://github.com/php/php-src/blob/master/main/streams/streams.c#L1080 (https://github.com/php/php-src/blob/master/main/streams/streams.c#L1080)
Dál jsi psal:
Pokud by vám i posix_get_last_error() vracela, že k žádné chybě nedošlo, máte smůlu, protože PHP mezitím zavolalo nějakou jinou POSIXovou funkci, která výsledek volání write() překryla.
Kdybys měl alespoň trochu ánunk o tom, o čem píšeš, tak by ti došlo, že posix_get_last_error() je z POSIX modulu, tedy funguje jen pro jeho funkce. Ty se vyznačují tím, že mají prefix posix_. No a jak si můžeš všimnout, funkce fwrite() ten prefix nemá. Takže na ni posix_get_last_error() logicky nefunguje a tedy to co jsi psal, je totální hovadina.
Kód v prvním příspěvku by mohl hlásit chybu zaplnění disku jedině v případě, že by disk byl plný už před začátkem zápisu. Kdyby se disk zaplnil už voláním té funkce fwrite(), selhalo by už druhé volání fwrite(), a tam žádný výpis chybového kódu není.
Hele a tohle jsi v praxi ověřoval? Řek bych že ne a zase jen plácáš ty svoje neověřený teoretický nesmysly. PHP prostě žádný chybový kód nenastaví. Ani při prvním, ani při jakémkoli dalším volání.
-
Nejdřív jsi se tu točil na nějakém částečném zápisu, což ale problém vůbec nebyl. Ono totiž PHP, jak se zdá, tu smyčku dělá už interně ve funkci, kterou volá ten fwrite(): https://github.com/php/php-src/blob/master/main/streams/streams.c#L1080 (https://github.com/php/php-src/blob/master/main/streams/streams.c#L1080)
Normální je programovat proti specifikaci funkce, ne proti tomu, jak je aktuálně naimplementovaná. Když je zdokumentováno, že funkce vrací počet zapsaných bajtů, plyne z toho, že nemusí zapsat vše (zvlášť když je to obvyklé chování funkcí zapisujících do streamu). Když si někdo zjistí, že zrovna v jeho verzi ta funkce zapíše vše nebo vrátí chybu, naprogramuje podle toho svůj kód, a pak se chování funkce změní (ale bude pořád v souladu s dokumentací), bude mít v programu chybu, v tomto případě navíc těžko odhalitelnou (protože bude nastávat jen někdy).
Že ta PHP funkce fwrite() funguje úplně jinak, než je popsáno v dokumentaci, je dost zásadní chyba. Pokud to tazatel věděl, měl to napsat. Jinak bývá dobrým zvykem hledat chybu nejprve ve svém kódu a teprve pak v knihovnách. A ten kód andreaw.fean je špatně, a to i v případě, když bude počítat s tím, že tu smyčku dělá fwrite() interně.
Kdybys měl alespoň trochu ánunk o tom, o čem píšeš, tak by ti došlo, že posix_get_last_error() je z POSIX modulu, tedy funguje jen pro jeho funkce. Ty se vyznačují tím, že mají prefix posix_. No a jak si můžeš všimnout, funkce fwrite() ten prefix nemá. Takže na ni posix_get_last_error() logicky nefunguje a tedy to co jsi psal, je totální hovadina.
Dalo se předpokládat, že fwrite() interně volá nativní funkci write(), která je definovaná POSIX standardem, a která v případě neúspěchu ukládá chybový kód do errno. Funkce posix_get_last_error() mohl být způsob, jak errno přečíst.
Hele a tohle jsi v praxi ověřoval? Řek bych že ne a zase jen plácáš ty svoje neověřený teoretický nesmysly. PHP prostě žádný chybový kód nenastaví. Ani při prvním, ani při jakémkoli dalším volání.
Ten kód, tak jak je napsaný, nejdřív předpokládá, že když se nezapíše vše, je to hned chyba, a vzápětí se pokusí zapsat ještě zbytek. Při jaké konstelaci tenhle kód dává smysl?
Ověřit to chování měl andreaw.fean, on měl prostředí, kde k nějaké chybě docházelo. Když se mně nepodaří nasimulovat případ, že by fwrite() vrátilo menší počet zapsaných bajtů, než byl počet bajtů k zápisu, v žádném případě to neznamená, že mám počítat s tím, že to nemůže nikdy nastat. Přesně na základě takovýchto předpokladů vznikají programy, které pak různě náhodně padají.
To, že PHP žádný chybový kód nenastaví bylo potřeba zjistit – buď zkoumáním zdrojáků, nebo testem. Ten test je ovšem potřeba provést tak, aby vůbec byla šance, že tu chybu nastaví. Tvrdit, že funkce fwrite() chybu nenastavuje, na základě kódu, který nastavení chyby neumí zjistit, je dost odvážné. A nic na tom nemění fakt, že se nakonec (úplně jiným způsobem) ukázalo, že fwrite() opravdu chybu nenastavuje.
Kdyby se funkce fwrite() chovala tak, jak je popsané v dokumentaci, ten kód andreaw.fean by se choval přesně tak, jak popisoval – tj. žádnou chybu by to nevypsalo. Stačilo by ten kód opravit. Že se nakonec fwrite() chová úplně jinak je dost problém, a vzhledem k této diskusi je to jen náhoda. Kdyby andreaw.fean ten svůj kód opravil, vzápětí by se přišlo na to, že fwrite() funguje špatně – a mohlo by se to řešit. Místo toho se tu pořád dokola řešilo, že vlastně nikdo neví, jak vlastně ten kód funguje. Vždyť andreaw.fean ani nebyl schopen napsat, jestli mu to volání fwrite() vrací FALSE, 0 nebo nějakou kladnou hodnotu. To by hledání chyby značně urychlilo, protože kdyby opakovaně vracelo 0, bylo by jasné, že se to chová jinak, než je zdokumentováno.
Nakonec se tedy strašně dlouhou a klopotnou cestou skládání náhodných úryvků kódu dospělo k řešení, se kterým je andreaw.fean spokojen. Je ale velmi smutné, kolik lidí tady v diskusi vůbec nepochopilo, proč je ten původní kód špatně, a vlastně jim je úplně jedno, že to nechápou – prostě ten kód zkouší náhodnými výstřely měnit, a když jim to jednou udělá, co chtějí, jsou spokojení, a mají pocit, že je kód správně. A ještě mají pocit, jací jsou machři. Už se vůbec nedivím, že BoneFluteovi jednotkové testy vůbec nepomáhají – pokud testuje jenom to, co mu zrovna spadlo pod rukama, a vůbec nechápe, co jeho kód vlastně dělá a kde jsou potenciální chyby, jednotkové testy mu opravdu nijak nepomůžou.
-
< ... bláboly snipped ... >
Stále kvoká, stále kvoká... (https://www.youtube.com/watch?v=j4UpBVN-qE8&feature=youtu.be&t=10s)
-
Stále kvoká, stále kvoká... (https://www.youtube.com/watch?v=j4UpBVN-qE8&feature=youtu.be&t=10s)
Je to tak. Pevně doufám, že nikde neprogramuje a pokud ano, tak lituju jeho spolupracovníky. U mě by takový nemehlo vyletělo na hodinu zavřenýma dveřma a ještě bych mu je dal k úhradě.
-
Je to tak. Pevně doufám, že nikde neprogramuje a pokud ano, tak lituju jeho spolupracovníky. U mě by takový nemehlo vyletělo na hodinu zavřenýma dveřma a ještě bych mu je dal k úhradě.
Dobře, uznávám, rozumíte tomu lépe než já. Můžete mi tedy některé věci na tom kódu uvedeném v dotazu vysvětlit? Napíšu i nijaké příklady možných odpovědí, aby bylo srozumitelnější, na co se ptám – těmi příklady odpovědí se ale nenechte zmást, ty jsou evidentně špatně.
- Jaký je význam toho druhého volání fwrite() – na řádku 14? Myslím tím jakou situaci ošetřuje. Např. by odpověď mohla být: „Ošetřuje situaci, kdy první volání fwrite() na řádku 9 je jen částečně úspěšné, zapíše jen část dat, ale je možné, že se při dalším pokusu podaří zapsat další část – např. pokud by při prvním volání byl disk plný, ale před druhým voláním by se místo uvolnilo.“
- V jakém případě dojde program k tomu druhému volání fwrite() – na řádku 14? Jaké budou invarianty programu? Např.: „První volání fwrite() na řádku 9 vrátilo hodnotu FALSE nebo 0.“ Nebo.: „První volání fwrite() na řádku 9 vrátilo hodnotu počet zapsaných bajtů, větší než 0 a menší než délka $s.“
- Jaký bude výsledek volání programu, pokud před prvním voláním fwrite() (na řádku 9) bude na cílovém disku volné místo, ale ne tolik, aby se tam vešlo celé $s, a před druhým voláním fwrite() (na řádku 14) se nějaké místo na disku uvolní? Zajímá mne především co bude aplikace vypisovat a co bude zapsané v cílovém souboru.
-
Stále kvoká, stále kvoká... (https://www.youtube.com/watch?v=j4UpBVN-qE8&feature=youtu.be&t=10s)
Je to tak. Pevně doufám, že nikde neprogramuje a pokud ano, tak lituju jeho spolupracovníky. U mě by takový nemehlo vyletělo na hodinu zavřenýma dveřma a ještě bych mu je dal k úhradě.
No tak strasne to asi nebude, ale v tymu nebo ve firme bych ho nechtel. At si nekde cosi patla na kontrakt, kdyz je s tim zakaznik happy, proc ne. Ale jinak domluva s nim musi byt ukrutne slozita.
-
To je vtipná představa, že by junioři ve zkušební době (protože po zkušebce už musí takhle očividné chyby vidět sám) vyhazovali seniory, když by si senior dovolil upozornit na chybu v kódu juniora.
Ale je teda dost smutné vidět tu několik lidí, kteří si o sobě očividně myslí bůhví co a myslí si, že umí programovat, kterým nevadí program pro zápis do souboru, který:
- úspěšně zapíše všechna data a vypíše chybu, že se podařilo zapsat jenom část dat
- skončí s chybou, že se nepodařilo všechna data zapsat, přestože na disku je dost místa a ani nic jiného nebrání všechna data zapsat
Navíc kdyby ta funkce fwrite() uměla nějak signalizovat příčinu chyby, při zápisu na zcela plný disk by program správně oznámil, že disk je plný, ale kdyby se disk zaplnil teprve v průběhu zápisu, program by v lepším případě (pokud by andreaw.feana něco osvítilo a počítal by s tím, že se při zjištění chyby může dozvědět, že k žádné chybě nedošlo) oznámil, že došlo k nečekané chybě.
Stejně by mne ale zajímalo, kdyby L., ffd, BoneFlute nebo andreaw.fean odpověděli na ty tři otázky, které jsou v mém předchozím komentáři. Zajímalo by mne, jestli aspoň chápete význam jednotlivých řádků kódu, jenom si nedokážete spojit dohromady, co to dělá, když se ty řádky provádí postupně za sebou, a nebo jestli vám uniká i význam těch jednotlivých řádků.
-
Kdybys měl alespoň trochu ánunk o tom, o čem píšeš, tak by ti došlo, že posix_get_last_error() je z POSIX modulu, tedy funguje jen pro jeho funkce. Ty se vyznačují tím, že mají prefix posix_. No a jak si můžeš všimnout, funkce fwrite() ten prefix nemá. Takže na ni posix_get_last_error() logicky nefunguje a tedy to co jsi psal, je totální hovadina.
Přímo v dokumentaci http://php.net/manual/en/function.posix-get-last-error.php se používá v příkladu stream_select(), takže to s tím "posix_" prefixem není pravda. Zbytek se mi nechce hledat, ale řekl bych, že ta funkce logicky vrací "errno".
-
Kdybys měl alespoň trochu ánunk o tom, o čem píšeš, tak by ti došlo, že posix_get_last_error() je z POSIX modulu, tedy funguje jen pro jeho funkce. Ty se vyznačují tím, že mají prefix posix_. No a jak si můžeš všimnout, funkce fwrite() ten prefix nemá. Takže na ni posix_get_last_error() logicky nefunguje a tedy to co jsi psal, je totální hovadina.
Přímo v dokumentaci http://php.net/manual/en/function.posix-get-last-error.php se používá v příkladu stream_select(), takže to s tím "posix_" prefixem není pravda. Zbytek se mi nechce hledat, ale řekl bych, že ta funkce logicky vrací "errno".
Zkoušel jsem to. Ty funkce bohužel nefachají. Ani jedna.