Transfert SFTP en PHP fonction ssh2_sftp

#1
Bonjour,

j'avais un cron qui fonctionnait bien depuis pas mal de mois pour le transfert d'un fichier texte journalier. D'un seul coup j'ai une erreur systématique sur la fonction:

$sftpStream = @fopen($sftpUrl, 'w');

avec $sftpUrl="ssh2.sftp://Resource id #10/transferts/2017-01-09_14-20_export.csv"

L'administrateur du serveur cible me précise qu'il n'y eu aucune modification de leur config. Est-ce que cela pourrait provenir d'une mise à jour de PHP ou toute mise à jour liée au protocole de communication SFTP sur la plateforme PH ?

A noter que Resource id #10 est un cast string du retour de la fonction: resource ssh2_sftp ( resource $session )

référence code source utilisé:
http://php.net/ssh2_sftp

extrait source:

Code:
   if (!function_exists("ssh2_connect"))
    {
        write_file($log,"function ssh2_connect doesn't exist",true);
        fclose($log);
        die();
    }
    $connection = ssh2_connect($ftp_host, 22);
    if(!$connection)
    { // connexion
        write_file($log,"La connexion ssh2_connect $ftp_host a echoue.",true);
        fclose($log);
        die();
    }
    if (!ssh2_auth_password($connection, $ftp_user_name, $ftp_user_pass))
    { // identification
        write_file($log,"La connexion ssh2_auth_password $ftp_host a echoue. user:$ftp_user_name pass:$ftp_user_pass",true);
        fclose($log);
        ssh2_exec($connection, 'exit');
        die();
    }
 
    $sftp        = @ssh2_sftp($connection); // initialise un sous-systeme SFTP
    if (!$sftp)
       throw new Exception("erreur sur initialisation sous-systeme SFTP");

        $target_file = $target_path . $target_file;
        $sftpUrl     = "ssh2.sftp://".$sftp.$target_file;
    $sftpStream  = @fopen($sftpUrl, 'w');   // creation flux pour fichier cible
 
    if (!$sftpStream)
       throw new Exception("erreur sur creation ficher cible: $sftpUrl");
 
Dernière édition par un modérateur:

PH-Quentin

Administrator
#2
Bonjour MarcMarin,

Merci pour votre message, êtes-vous certain que "Resource id #10" est bien un string et non un objet contenant une erreur ? Avez-vous tenté en hardcodant l'host SFTP?

Pourriez-vous SVP activer l'affichage des erreurs dans votre script PHP afin que nous soyons en mesure de diagnostiquer la cause du problème ? Pour ce faire, il suffit de rajouter ces deux lignes de code en dessous de la valide PHP à savoir "<?php"

Code:
error_reporting( E_ALL );
@ini_set( 'display_errors', 1 );
Une fois ces deux lignes rajoutées, je vous invite à lancer votre code et nous indiquer le message d'erreur retourné !

J'attends votre retour (d'erreur) !
Quentin
 
#3
Bonjour et merci Quentin pour votre implication sur cette problématique.

alors en hardcodant la fonction sous la forme:

PHP:
ssh2.sftp://user:[email protected]:22/path/to/filename
çà marche ! ;-) ce qui veut donc dire que la fonction

PHP:
$sftp = @ssh2_sftp($connection)
ne renvoie pas false mais un 'Resource id #10'

Alors que la connexion en amont se passe bien.
PHP:
$connection = ssh2_connect($ftp_host, 22);
if(!$connection)
...
if (!ssh2_auth_password($connection, $ftp_user_name, $ftp_user_pass))
...
finalement pourquoi passer par ces 3 dernières fonctions alors qu’apparemment on peut directement passer tous les paramètres par ssh2.sftp

Certains d'ailleurs se posent la question sur Resource id #10 ici:

http://stackoverflow.com/questions/1466737/cant-get-sftp-to-work-in-php

Concernant le log des erreurs error_reporting(E_ALL ) puisque la fin de la ligne de commande du cron contient >/dev/null 2>&1
comment la rediriger vers un log ? j'ai essayé de remplacer /dev/null par /logs/syslog.log (puique l'espace dispose déjà d'un répertoire logs)
Quel est la bonne pratique ?

merci d'avance
 
Dernière édition par un modérateur:

PH-Quentin

Administrator
#5
Bonjour et merci Quentin pour votre implication sur cette problématique.

alors en hardcodant la fonction sous la forme:

ssh2.sftp://user:p[email protected]:22/path/to/filename

çà marche ! ;-) ce qui veut donc dire que la fonction
$sftp = @ssh2_sftp($connection)
ne renvoie pas false mais un 'Resource id #10'

Alors que la connexion en amont se passe bien.
$connection = ssh2_connect($ftp_host, 22);
if(!$connection)
...
if (!ssh2_auth_password($connection, $ftp_user_name, $ftp_user_pass))
...

finalement pourquoi passer par ces 3 dernières fonctions alors qu’apparemment on peut directement passer tous les paramètres par ssh2.sftp

Certains d'ailleurs se posent la question sur Resource id #10 ici:

http://stackoverflow.com/questions/1466737/cant-get-sftp-to-work-in-php

Concernant le log des erreurs error_reporting(E_ALL ) puisque la fin de la ligne de commande du cron contient >/dev/null 2>&1
comment la rediriger vers un log ? j'ai essayé de remplacer /dev/null par /logs/syslog.log (puique l'espace dispose déjà d'un répertoire logs)
Quel est la bonne pratique ?

merci d'avance
Rebonjour,

Je suis content d'apprendre que nous avançons dans le debug du code !

Lorsque que je regarde la documentation de PHP.net, je constate que la valeur de retour de la fonction ssh2_sftp n'est pas un booléen mais bien une ressource !

Cependant un peu plus bas dans les exemples nous pouvons effectivement voir ce code qui permet de vérifier si la connexion SFTP à eu lieu avec succès ou pas:



Après il faut bien comprendre que dans cette variable vous n'avez pas le hostname/chemin du serveur mais bien une ressource de connexion, si vous souhaitez donc initialiser une connexion avec fopen, d'après mon expérience il va falloir ré-indiquer le hostname/nom du fichier à atteindre en utilisant une autre variable de type string.

Vous pouvez pas exemple voir le type d'une variable PHP en utilisant gettype comme ceci:

Code:
echo gettype($sftp), "<br>\n";
Bien à vous,
Quentin
 
#6
je suis bien d'accord avec vous Quentin, cette construction de fonction fopen est bien curieuse

PHP:
$sftp = ssh2_sftp($connection);
$stream = fopen("ssh2.sftp://$sftp/path/to/file", 'w');
d'autant plus qu'on la retrouve dans plein de documents PHP y compris dans votre lien:

Code:
$stream = @fopen("ssh2.sftp://$sftp$remote_file", 'w')
et de plus elle m'avait pas posé de problème à moi et à d'autres.

donc puisqu'il suffit de remplacer par une string du user/hostname, c'est ce que je vais faire et au diable les complications ! ;-)

Merci en tout cas.
 
Dernière édition par un modérateur:
Haut