martes, 27 de septiembre de 2011

Upload de QPixmap a Php

Hoy tuve que enfrentarme a la tarea de subir una imagen desde un Programita en C++ a un Script en web de PHP.
Al inicio pensé que no seria complicado pero después de un rato me di cuenta que era la tarea era "infernal".
Mi primera opción fue usar CURL, pero despúes de varios intento fallidos me decline por QT.
Qt tiene una serie de clases para manejo de Network. Sin embargo la mayoría a quedado obsoleta dejando muy pocas en juego.
Al final me decidí por hacerlo con QNetworkAccessManager. Veamos código primero y despúes la explicación.

Prueba Conceptual:

Form en HTML

Enviar un nuevo archivo:

Codigo PHP para subir imagenes

$target_path = "uploads/";

$target_path = $target_path . basename( $_FILES['userfile']['name']); 

if(move_uploaded_file($_FILES['userfile']['tmp_name'], $target_path)) {
    echo "The file ".  basename( $_FILES['userfile']['name']). " has been uploaded";
} else{
    echo "There was an error uploading the file, please try again!";
}

Nota:
No mucho que explicar aca, un form que sube cualquier cosa. Esto se lo manda al PHP y lo salva en una carpeta de upload.

Ahora lo que intenso hacer es simular el request del browser con C++ con QT.

void UploadManager::upload(QString url, QPixmap img){
    QNetworkAccessManager *manager = new QNetworkAccessManager(this);
    connect(manager, SIGNAL(finished(QNetworkReply*)),
    this, SLOT(downloadFinished(QNetworkReply*)));
    QByteArray bytes;
    QBuffer buffer(&bytes);
    buffer.open(QIODevice::WriteOnly);
    img.save(&buffer, "PNG");
    QByteArray multipartform;
    QString crlf("\r\n");
    QString boundaryStr("---------------------------109074266748897678777839994");
    QString boundary="--"+boundaryStr+crlf;
    QString filename = "test.png";
    multipartform.append(boundary.toAscii());
    multipartform.append(QString("Content-Disposition: form-data; name=\"userfile\"; filename=\"" + filename + "\"" + crlf).toAscii());
    multipartform.append(QString("Content-Type: text/plain" + crlf + crlf).toAscii());
    multipartform.append(bytes);
    multipartform.append(QString(crlf + "--" + boundaryStr + "--" + crlf).toAscii());
    QNetworkRequest request;
    request.setUrl(QUrl(QString("http://127.0.0.1/PruebasConceptuales/upload/subearchivo.php")));
    request.setHeader(QNetworkRequest::ContentTypeHeader, "multipart/form-data; boundary=" + boundaryStr);
    manager->post(request, multipartform);
}

Explicación:

Básicamente, lo que hacemos es construir el Request que usa Firefox. Se sabe que cuando se va a subir una imagen el Archivo pasa por un proceso de Base64. Curiosamente el QPixmap simplemente lo convierto en un flujo de Bits (lineas 5 - 8). Y con eso basta para subir. Despúes seguidamente hacemos otro Array de Bits con el cual empezamos a meter todos los datos para simular el post (Lineas 8 -18). Creamos un QNetworkRequest y le decimos al QNetworkAccessManager que use el request y que le pase todos los datos con manager->post(request, multipartform);

Cualquier consulta no duden en comentar :P

2 comentarios:

  1. Respuestas
    1. el unico detalle es que no me funciono el toAscii() pero cambiándolo por toLocal8Bit() va como la seda!!!

      Eliminar

AEM hablemos del arquetipo 11

Cuando creamos un proyecto con AEM. Siempre es importante saber que arquetipo estamos usando. Pues esto me determinara que source, herramien...