Utwórz lub zapisz / dołącz w pliku tekstowym

170

Mam stronę internetową, na której za każdym razem, gdy użytkownik się loguje lub wylogowuje, zapisuję ją do pliku tekstowego.

Mój kod nie działa w zakresie dołączania danych lub tworzenia pliku tekstowego, jeśli nie istnieje. Oto przykładowy kod

$myfile = fopen("logs.txt", "wr") or die("Unable to open file!");
$txt = "user id date";
fwrite($myfile, $txt);
fclose($myfile);

Wygląda na to, że nie jest dołączany do następnego wiersza po ponownym otwarciu.

Myślę też, że miałoby to również błąd w sytuacji, gdy loguje się 2 użytkowników w tym samym czasie, czy wpłynęłoby to na otwarcie pliku tekstowego i późniejsze jego zapisanie?

Jerahmeel Acebuche
źródło

Odpowiedzi:

337

Spróbuj czegoś takiego:

 $txt = "user id date";
 $myfile = file_put_contents('logs.txt', $txt.PHP_EOL , FILE_APPEND | LOCK_EX);
SpencerX
źródło
5
czy to tworzy plik tekstowy, jeśli nie istnieje?
Jerahmeel Acebuche
5
Tak, stwórz plik tekstowy logs.txti
dołącz
5
mam pytanie. używając LOCK_EX. Wiem, że uniemożliwi to innym osobom zapisywanie się do pliku w tym samym czasie. ale co się stanie z drugim?
Jerahmeel Acebuche
13
php.net/manual/en/function.file-put-contents.php Ta funkcja zwraca liczbę bajtów, które zostały zapisane do pliku lub FALSE w przypadku błędu. Tylko jeśli ktoś się zastanawia.
Master James,
7
@JerahmeelAcebuche Drugi proces próby uzyskania blokady „będzie blokowany do momentu uzyskania żądanej blokady” ( źródło ). Innymi słowy, drugi proces będzie czekał, aż pierwszy zamknie plik i zwolni blokadę.
rinogo
102

Użyj atrybu. To oznacza append.

$myfile = fopen("logs.txt", "a") or die("Unable to open file!");
$txt = "user id date";
fwrite($myfile, "\n". $txt);
fclose($myfile);
Valentin Mercier
źródło
mam też ten problem z \ n. to nie działa. czy to ci pasuje?
Jerahmeel Acebuche
1
czy to działa, jeśli sytuacja jest taka, jak powiedziałem?
Jerahmeel Acebuche
1
aflaga stworzy plik, jeśli nie istnieje i nie będzie ważne, co się upewnić, że naprawdę appendnowy tekst. Aby \nto działa, ale tylko wtedy, gdy wewnątrz cudzysłowach "nie pojedyncze cytaty'
Valentin Mercier
mam na myśli sytuację, jeśli dwóch użytkowników zaloguje się w innej przeglądarce. następnie php otworzy plik w dwóch przeglądarkach w tym samym czasie i zaktualizuje go w tym samym czasie. czy będzie problem? \
Jerahmeel Acebuche
1
Aha, tak, będzie, w tym przypadku użyj bazy danych SQL, która ma wbudowany silnik, aby uniknąć warunków wyścigu. Ale to zupełnie nowe pytanie.
Valentin Mercier
10

Możesz to zrobić na sposób OO, tylko alternatywnie i elastycznie:

class Logger {

    private
        $file,
        $timestamp;

    public function __construct($filename) {
        $this->file = $filename;
    }

    public function setTimestamp($format) {
        $this->timestamp = date($format)." » ";
    }

    public function putLog($insert) {
        if (isset($this->timestamp)) {
            file_put_contents($this->file, $this->timestamp.$insert."<br>", FILE_APPEND);
        } else {
            trigger_error("Timestamp not set", E_USER_ERROR);
        }
    }

    public function getLog() {
        $content = @file_get_contents($this->file);
        return $content;
    }

}

Następnie użyj tego w ten sposób ... powiedzmy, że user_namezapisałeś w sesji (pół pseudo kod):

$log = new Logger("log.txt");
$log->setTimestamp("D M d 'y h.i A");

if (user logs in) {
    $log->putLog("Successful Login: ".$_SESSION["user_name"]);
}
if (user logs out) {
    $log->putLog("Logout: ".$_SESSION["user_name"]);
}

Sprawdź swój dziennik za pomocą tego:

$log->getLog();

Wynik jest taki:

Sun Jul 02 '17 05.45 PM » Successful Login: JohnDoe
Sun Jul 02 '17 05.46 PM » Logout: JohnDoe


github.com/thielicious/Logger

Thielicious
źródło
1
Wielkie dzięki za tę klasę Loggera! Nie spodziewałem się tego, kiedy znalazłem tę stronę ... ale w rzeczywistości jest to podstawa znacznie lepszego rozwiązania niż to, które pierwotnie planowałem wdrożyć.
Myke Carter
4

To działa dla mnie, Pisanie (także tworzenie) i / lub dołączanie treści w tym samym trybie.

$fp = fopen("MyFile.txt", "a+") 
Mihir Bhatt
źródło
3

Wypróbuj ten kod:

function logErr($data){
  $logPath = __DIR__. "/../logs/logs.txt";
  $mode = (!file_exists($logPath)) ? 'w':'a';
  $logfile = fopen($logPath, $mode);
  fwrite($logfile, "\r\n". $data);
  fclose($logfile);
}

Zawsze go tak używam i działa ...

Rwakos
źródło
1
Nie ma powodu do zrobienia (!file_exists($logPath)) ? 'w':'a'- aopcja już działa poprawnie, gdy plik nie istnieje. Więc można uprościć tę odpowiedź, usuwając linię $mode = ...;i zmieniając następną linię na $logfile = fopen($logPath, 'a');.
ToolmakerSteve
2

W Twoim kodzie nie ma takiego trybu otwierania plików jak „wr”:

fopen("logs.txt", "wr") 

Tryby otwierania plików w PHP http://php.net/manual/en/function.fopen.php są takie same jak w C: http://www.cplusplus.com/reference/cstdio/fopen/

Istnieją następujące główne otwarte tryby „r” do odczytu, „w” do zapisu i „a” do dołączania i nie można ich łączyć. Możesz dodać inne modyfikatory, takie jak „+” dla aktualizacji, „b” dla binarnego. Nowy standard C dodaje nowy standardowy specyfikator („x”), obsługiwany przez PHP, który można dołączyć do dowolnego specyfikatora „w” (aby utworzyć „wx”, „wbx”, „w + x” lub „w + bx „/„ wb + x ”). Ten subspecifier wymusza niepowodzenie funkcji, jeśli plik istnieje, zamiast go nadpisywać.

Poza tym w PHP 5.2.6 dodano główny tryb otwarty „c”. Nie można łączyć „c” z „a”, „r”, „w”. Litera „c” otwiera plik tylko do zapisu. Jeśli plik nie istnieje, zostanie utworzony. Jeśli istnieje, nie jest obcinany (w przeciwieństwie do „w”), ani wywołanie tej funkcji nie kończy się niepowodzeniem (jak w przypadku „x”). „c +” Otwiera plik do czytania i pisania; w przeciwnym razie zachowuje się tak samo jak „c”.

Dodatkowo w PHP 7.1.2 dodano opcję 'e', ​​którą można łączyć z innymi trybami. Ustawia flagę close-on-exec na deskryptorze otwartego pliku. Dostępne tylko w PHP skompilowanym w systemach zgodnych z POSIX.1-2008.

Tak więc dla opisanego zadania najlepszym trybem otwierania plików będzie „a”. Otwiera plik tylko do zapisu. Umieszcza wskaźnik pliku na końcu pliku. Jeśli plik nie istnieje, próbuje go utworzyć. W tym trybie fseek () nie działa, zapisy są zawsze dołączane.

Oto, czego potrzebujesz, jak już wskazano powyżej:

fopen("logs.txt", "a") 
Maxim Masiutin
źródło
0

Chociaż można to zrobić na wiele sposobów. Ale jeśli chcesz to zrobić w łatwy sposób i chcesz sformatować tekst przed zapisaniem go w pliku dziennika. Możesz w tym celu utworzyć funkcję pomocniczą.

if (!function_exists('logIt')) {
    function logIt($logMe)
    {
        $logFilePath = storage_path('logs/cron.log.'.date('Y-m-d').'.log');
        $cronLogFile = fopen($logFilePath, "a");
        fwrite($cronLogFile, date('Y-m-d H:i:s'). ' : ' .$logMe. PHP_EOL);
        fclose($cronLogFile);
    }
}
Robak PHP ...
źródło