web-dev-qa-db-fra.com

Quelle est la différence entre les modes fopen "r +" et "rw +" en PHP?

De nombreuses réponses ici dans Stack Overflow utilisent fopen($file, "rw+"), mais le manuel ne répertorie pas le mode "rw+", il n'y a que le mode "r+" (ou mode "w+").

Je me demandais donc, à quoi sert le mode "rw+"? Quelle est la différence entre fopen($file,"rw+" ou "r+"? Je pose cette question car il n'y a pas de documentation sur le "rw+" mode.

Une approche consiste à considérer que les modes sont additifs, mais je n'ai trouvé aucune mention de la combinaison des modes dans la page de manuel fopen (en plus, quel est le sens de combiner "r" avec "w+", si "w+" le rend déjà lisible?). Mais surtout, le mode w+ tronque le fichier, tandis que rw+ ne le tronque pas (ils ne peuvent donc pas être additifs). Il n'y a probablement pas de mode rw+, malgré son utilisation par les utilisateurs de Stack Overflow. Peut-être que cela fonctionne parce que l'analyseur ignore la lettre "w", car le mode rw+ semble être === r+?

Pour clarifier ma question: quel est le mode "rw+", c'est-à-dire en quoi diffère-t-il des autres modes? Je n'ai reçu que deux réponses dans les commentaires: soit que je devais vérifier la documentation (j'ai déjà vérifié et revérifié) et une mauvaise réponse, qui disait qu'elle était égale à "w+" (ce n'est pas le cas). "w+" tronque le fichier, contrairement à "rw+".

Voici un script pour les tests (cela prouve que w+ tronque le fichier, mais pas rw+):

<?php 
$file = "somefile"; 
$fileOpened = fopen($file, "w"); 
fwrite($fileOpened, "0000000000000000000"); 
fclose($fileOpened);  

$fileOpened = fopen($file, "rw+"); 
fwrite($fileOpened, "data"); 
fclose($fileOpened); 
$fileOpened = fopen($file, "r"); 
$output = fgets($fileOpened); 
echo "First, with 'rw+' mode:<br>".$output; 

$fileOpened = fopen($file, "w+"); 
fwrite($fileOpened, "data"); 
fclose($fileOpened); 
$fileOpened = fopen($file, "r"); 
$output = fgets($fileOpened); 
echo "<br><br><br>Now with only 'w+' mode:<br>".$output; 
?>
58
flen

Je pense que vous avez à peu près compris cela. Bien que je suppose, vous voulez une réponse faisant autorité.

Il est vrai que la documentation ne mentionne pas "rw+". Pourtant, il y a quelque chose de mieux: code source PHP !


The Rabbit Hole

J'ai eu du mal à naviguer dans le code source jusqu'à ce que je trouve le code source de la série d'articles PHP pour PHP Developers ( Part 1 , Part 2 , Partie , Partie 4 ). Je sais que les liens sautent entre deux sites, cette série est branchée comme ça. Au fait, je n'ai pas ne trouve pas la partie 5 annoncée.

Remarque : Ces articles sont anciens, ils parlent de PHP 5.4.

Voyons ce que fopen fait réellement ... laissez-nous tomber dans le terrier du lapin ...

Nous examinons d'abord la définition de la fonction (que j'ai trouvée en suivant les conseils de la partie liée 2 ci-dessus). Je remarque qu'il utilise php_stream_open_wrapper_ex , que je trouvé ailleurs , il utilise simplement _php_stream_open_wrapper_ex que l'on trouve dans stream.c .

Qu'est-ce que _php_stream_open_wrapper_ex faire avec mode? Il le passe à stream_opener .

Vous recherchez la définition de stream_opener m'a amené au type php_stream_wrapper_ops dans php_streams.h .

Recherche d'utilisations de type php_stream_wrapper_ops m'a conduit à plain_wrapper.c .

Il y a en fait beaucoup d'initialisations de php_stream_wrapper_ops qui permettent d'ouvrir différentes choses. Nous examinons php_fopen_wrapper.c car il a une initialisation de php_stream_wrapper_opsstream_opener est php_plain_files_stream_opener.

Nous y arrivons ...

php_plain_files_stream_opener est plus bas dans le même fichier . Il délègue à php_stream_fopen_rel .

php_streams.h définit php_stream_fopen_rel en utilisant _php_stream_fopen. Ce qui est de retour sur plain_wrapper.c .

Finalement, _php_stream_fopen appels php_stream_parse_fopen_modes . Qui prendra la chaîne et affichera quelques drapeaux, Yay!


Pays des merveilles

Jetons un œil à php_stream_parse_fopen_modes :

PHPAPI int php_stream_parse_fopen_modes(const char *mode, int *open_flags)
{
    int flags;

    switch (mode[0]) {
        case 'r':
            flags = 0;
            break;
        case 'w':
            flags = O_TRUNC|O_CREAT;
            break;
        case 'a':
            flags = O_CREAT|O_APPEND;
            break;
        case 'x':
            flags = O_CREAT|O_EXCL;
            break;
        case 'c':
            flags = O_CREAT;
            break;
        default:
            /* unknown mode */
            return FAILURE;
    }

    if (strchr(mode, '+')) {
        flags |= O_RDWR;
    } else if (flags) {
        flags |= O_WRONLY;
    } else {
        flags |= O_RDONLY;
    }

#if defined(O_CLOEXEC)
    if (strchr(mode, 'e')) {
        flags |= O_CLOEXEC;
    }
#endif

#if defined(O_NONBLOCK)
    if (strchr(mode, 'n')) {
        flags |= O_NONBLOCK;
    }
#endif

#if defined(_O_TEXT) && defined(O_BINARY)
    if (strchr(mode, 't')) {
        flags |= _O_TEXT;
    } else {
        flags |= O_BINARY;
    }
#endif

    *open_flags = flags;
    return SUCCESS;
}

Pour résumé, c'est ce qu'il fait (en ignorant les détails):

  1. Il prend le premier caractère de mode et vérifie s'il s'agit de r, w, a, x, c. S'il en reconnaît un, il met le drapeau approprié. Sinon, nous avons un FAILURE.

  2. Il recherche + quelque part dans la chaîne et définit les indicateurs appropriés.

  3. Il recherche e, n et t (selon les directives du préprocesseur) quelque part dans la chaîne et définit les indicateurs appropriés.

  4. Renvoie SUCCESS.


Retour au monde réel

Tu as demandé:

Quelle est la différence entre les modes fopen "r +" et "rw +" en PHP?

Rien. PHP se soucie seulement que la chaîne commence par "r" et a un "+". Le "w" est ignoré.

Note finale : Bien qu'il soit tentant de jouer avec et d'écrire des trucs comme "read+", soyez prudent, car cette lettre pourrait un jour avoir un sens. Il ne serait pas compatible à terme. En fait, dans un certain contexte, "e" a déjà un sens. Je suggère plutôt de m'en tenir à la documentation.


Merci pour l'excuse de jeter un œil au PHP.

68
Theraot