elhacker.net cabecera Bienvenido(a), Visitante. Por favor Ingresar o Registrarse
¿Perdiste tu email de activación?.

 

 


Tema destacado: Curso de javascript por TickTack


+  Foro de elhacker.net
|-+  Programación
| |-+  Programación C/C++ (Moderadores: Eternal Idol, Littlehorse, K-YreX)
| | |-+  Enviar archivo con HTTP POST a servidor PHP.
0 Usuarios y 1 Visitante están viendo este tema.
Páginas: [1] Ir Abajo Respuesta Imprimir
Autor Tema: Enviar archivo con HTTP POST a servidor PHP.  (Leído 4,430 veces)
Kaxperday


Desconectado Desconectado

Mensajes: 702


The man in the Middle


Ver Perfil WWW
Enviar archivo con HTTP POST a servidor PHP.
« en: 11 Marzo 2016, 13:27 pm »

Hola, a todos llevo muchos días sin estar al tanto del foro, pero he vuelto a programar un poco, y he tenido un problema para enviar un archivo con HTTP POST, os dejo el código del cliente C++ y del servidor PHP.

Hay otros métodos como PUT pero no me interesan. Quiero enviarlo por POST que funciona para todo tipo de archivos. La idea es que al subirlo envio 2 variables, una con el nombre del archivo y su extensión y otra con el contenido del archivo en binario. Quizás pueda tener que ver con el fallo.

Ojo, solo quiero subir todos los bytes del archivo y su nombre en 2 variables (nombre y contenido), y con el script PHP guardarlo. La idea sería poner cifrado a los bytes del archivo y desencriptarlo en el PHP, pero eso ya más adelante. Pero por eso necesito enviar el archivo en una variable como un array de bytes.

Código
  1. //_path C:\\Users\\User\\Desktop\\bicieta.jpg
  2. bool tracker::send_file(std::string _path)
  3. {
  4. WSADATA wsa;
  5. SOCKET sock;
  6. sockaddr_in addr;
  7. std::string data;
  8. std::string peticion;
  9.  
  10. WSAStartup(MAKEWORD(2, 0), &wsa);
  11.  
  12. if ((sock = socket(AF_INET, SOCK_STREAM, 0)) == SOCKET_ERROR){
  13. WSACleanup();
  14. return CODIGO::ERR_RED;
  15. }
  16.  
  17. memset(&addr, 0, sizeof(addr));
  18. addr.sin_family = AF_INET;
  19. addr.sin_port = htons(IPPORT_HTTP);
  20. addr.sin_addr.s_addr = inet_addr("71.60.170.21");//ip
  21. domain = "web.com";//quitar
  22. std::ifstream filer(_path, std::ifstream::ate | std::ifstream::binary);
  23. int size = filer.tellg();
  24. char* buffer = new char[size];
  25. filer.seekg(0, std::ios::beg);
  26. filer.read(buffer, size);
  27. filer.close();
  28.  
  29. char aux[8];
  30. int len;
  31. data = "n=" + _path.substr(_path.find_last_of('\\') + 1) + "&c=";
  32. len = data.size();
  33. data += std::string(buffer, size);
  34. len = len + size;
  35. _itoa(len, aux, 10);
  36.  
  37. peticion += "POST /catcher.php HTTP/1.1\r\n";
  38. peticion += "Host: " + domain + "\r\n";
  39. //peticion += "Cookie: " + cookie + "\r\n";
  40. peticion += "Content-type: application/octet-stream\r\n";//multipart/form-data también he probado..
  41. peticion += "Content-length: " + std::string(aux);// data.length();
  42. peticion += "\r\n\r\n";
  43. peticion += data;
  44.  
  45. if (connect(sock, (struct sockaddr*)&addr, sizeof(addr)) == SOCKET_ERROR){
  46. closesocket(sock);
  47. WSACleanup();
  48. return CODIGO::ERR_RED;
  49. }
  50.  
  51. if (send(sock, peticion.c_str(), peticion.length(), 0) == SOCKET_ERROR){
  52. closesocket(sock);
  53. WSACleanup();
  54. return CODIGO::ERR_RED;
  55. }
  56.  
  57. char respuesta[1024];
  58. memset(respuesta, 0, sizeof(respuesta));
  59. if (recv(sock, respuesta, 1024, 0) == SOCKET_ERROR){
  60. closesocket(sock);
  61. WSACleanup();
  62. return CODIGO::ERR_RED;
  63. }
  64.  
  65. return CODIGO::CORRECTO;
  66. }
  67.  

Código
  1. <?
  2. $name = htmlspecialchars($_POST["n"]);
  3. $content = htmlspecialchars($_POST["c"]);
  4. file_put_contents($name, $content);
  5. ?>
  6.  

Bueno el cliente funciona sin problemas, sin embargo el php me dice que la variable "c" esta vacía. "empty". Luego la función salta error, pero no entiendo porque cuando le estoy enviando el contenido a la variable "c".

Edito: Y sí el código no es de lo mejorcito estoy de pruebas xd, hay chapuzillas y faltan cosas para que quede la función como tal.

Un saludo y gracias.

Edito: Bueno lo acabo de enviar como application/octet-stream y me daba error de que el filename estaba vacio que no se porque, de todas maneras lo elimine y dije que el server pusiera el nombre y solo mandar el contenido de la imagen, y se ha subido con éxito solo que al ver la imagen me dice que hay error y no me deja verla :""D.. bueno quizas no lo habra porque tiene 0 bytes.. por lo mismo que me daba error de que el nombre estaba vacio, la variable del contenido también esta vacia, quizás sea por el htmlgetspecialchars.

Lo suyo sería hacerlo con el boundary.. pero no entiendo porque de esta manera no deja. Solo quiero mandar los bytes en una variable cifrados y que al llegar los desencripte y los meta en un archivo.

Bueno continuando un poco la mejor manera creo que es enviandolo con el application/x-www-form-urlencoded, recibe la variable del nombre correctamente y el contenido a medias 1,900kb cuando el archivo es de 80kb, así que luego al abrir la foto me dice que no la puede mostrar. Creo que es el htmlgetspecialchars que lo corta al encontrar un caracter o algo porque los 80kb se mandan por wireshark. Sin el specialshars se corta en el 1,6kb XD.

Habrá un caracter nulo que corte el array o algo :).

Seguramente haya que usar octet-stream pero en el PHP me aparecen nulas cuando las mando con ese formato.


« Última modificación: 11 Marzo 2016, 14:04 pm por Kaxperday » En línea

Cuando el poder económico parasita al político ningún partido ni dictador podrá liberarnos de él. Se reserva el 99% ese poder.
kub0x
Enlightenment Seeker
Colaborador
***
Desconectado Desconectado

Mensajes: 1.486


S3C M4NI4C


Ver Perfil
Re: Enviar archivo con HTTP POST a servidor PHP.
« Respuesta #1 en: 11 Marzo 2016, 14:54 pm »

La propia API de Win32 ofrece funciones para enviar datos a un servidor HTTP bajo POST.

Primero llama a HttpOpenRequest -> https://msdn.microsoft.com/en-us/library/windows/desktop/aa384233%28v=vs.85%29.aspx

Y después llama a HttpSendRequest -> https://msdn.microsoft.com/en-us/library/windows/desktop/aa384247%28v=vs.85%29.aspx

(Así te dejas de sockets y tanta manualidad ;) )

Para enviar los datos cifrados emplea HTTPS (TLS) o cifrálos bajo AES con una clave que este alojada en ambos extremos.

Saludos.


En línea

Viejos siempre viejos,
Ellos tienen el poder,
Y la juventud,
¡En el ataúd! Criaturas Al poder.

Visita mi perfil en ResearchGate

Kaxperday


Desconectado Desconectado

Mensajes: 702


The man in the Middle


Ver Perfil WWW
Re: Enviar archivo con HTTP POST a servidor PHP.
« Respuesta #2 en: 13 Marzo 2016, 20:00 pm »

Hola socio, gracias por la respuesta. Como recomendastes he dejado de usar sockets y he pasado a usar las APIs.

El código sin embargo no funciona, os comento más abajo, primero lo muestro:

Código
  1. bool tracker::send_file(std::string _path)
  2. {
  3. HINTERNET hi;
  4. DWORD dwBytes;
  5.  
  6. if ((hi = InternetOpen(NULL, INTERNET_OPEN_TYPE_DIRECT, NULL, NULL, 0)) == NO_ERROR){
  7. return false;
  8. }
  9.  
  10. if ((hi = InternetConnect(hi, L"web.com", INTERNET_DEFAULT_HTTP_PORT,
  11. NULL, NULL, INTERNET_SERVICE_HTTP, 0, 0)) == NO_ERROR){
  12. std::cout << "error en connect";
  13. InternetCloseHandle(hi);
  14. return false;
  15. }
  16.  
  17. DWORD dwOpenRequestFlags = INTERNET_FLAG_IGNORE_REDIRECT_TO_HTTP |
  18. INTERNET_FLAG_IGNORE_REDIRECT_TO_HTTPS |
  19. INTERNET_FLAG_KEEP_CONNECTION |
  20. INTERNET_FLAG_NO_AUTO_REDIRECT |
  21. INTERNET_FLAG_NO_COOKIES |
  22. INTERNET_FLAG_NO_CACHE_WRITE |
  23. INTERNET_FLAG_NO_UI |
  24. INTERNET_FLAG_RELOAD;
  25.  
  26. if ((hi = HttpOpenRequest(hi,
  27. L"POST",
  28. L"/catcher.php",
  29. L"HTTP/1.1",
  30. NULL, NULL,
  31. dwOpenRequestFlags, 0)) == NO_ERROR){
  32. std::cout << "error en openrequest";
  33. InternetCloseHandle(hi);
  34. return false;
  35. }
  36.  
  37. std::string boundary = "-----------------------------autoupdater1234";
  38. std::string headers;
  39. headers += "Host: web.com\r\n";
  40. headers += "Content-Type: multipart/form-data; boundary=" + boundary;
  41.  
  42. HttpAddRequestHeadersA(hi, headers.c_str(), headers.length(), HTTP_ADDREQ_FLAG_ADD);
  43.  
  44. std::string request;
  45. std::string body;
  46.  
  47. std::ifstream filer("C:\\Users\\User\\Desktop\\ciclista.jpg", std::ifstream::ate | std::ifstream::binary);
  48. int size = filer.tellg();
  49. char* buffer = new char[size];
  50. filer.seekg(0, std::ios::beg);
  51. filer.read(buffer, size);
  52. filer.close();
  53. std::string content = std::string(buffer, size);
  54.  
  55. /*Body*/
  56. body += boundary + "\r\n";
  57. body += "Content-Disposition: form-data; name=\"archivo\"; filename=\"ciclista.jpg\"\r\n";
  58. body += "Content-Type: image/jpeg\r\n\r\n";//application/octet-stream\r\n\r\n multipart/form-data\r\n\r\n
  59. body += content;
  60. body += "\r\n";
  61. body += boundary + "\r\n";
  62. body += "Content-Disposition: form-data; name=\"boton\"\r\n";//"\r\n\r\n"
  63. body += "Enviar archivo\r\n";
  64. body += boundary + "--\r\n";
  65.  
  66. int a = body.length();
  67. char aux[10];
  68. _itoa(a, aux, 10);
  69.  
  70. /*Headers*/
  71. //request += "Host: web.com\r\n";
  72. request += "Content-Type: multipart/form-data; boundary=" + boundary + "\r\n";
  73. request += "Content-Length: " + std::string(aux) + "\r\n\r\n";//"\r\n";
  74.  
  75. //HttpAddRequestHeadersA(hi, request.c_str(), request.length(), HTTP_ADDREQ_FLAG_ADD);
  76.  
  77. /*Body*/
  78. request += body;
  79. std::cout << request.substr(0, 600) << request.substr(request.length() - 200, 200);
  80. //InternetSetOption(hi, INTERNET_OPTION_USERNAME, "username\0", 9);
  81. //InternetSetOption(hi, INTERNET_OPTION_PASSWORD, "password\0", 9);
  82. std::cout << body.length() << "  " << request.length() << std::endl;
  83. if (HttpSendRequest(hi, NULL, 0, (LPVOID)request.c_str(), request.length())== NO_ERROR){
  84. std::cout << "error send req";
  85. InternetCloseHandle(hi);
  86. return false;
  87. }
  88.  
  89. std::string res;
  90. char ch;
  91. while (InternetReadFile(hi, &ch, 1, &dwBytes))
  92. {
  93. if (dwBytes != 1)break;
  94. res += ch;
  95. }
  96.  
  97. InternetCloseHandle(hi);
  98. std::cout << res;
  99. }
  100.  

Y ahora os dejo lo que tengo en el PHP:

Código
  1. <form action="" method="post" enctype="multipart/form-data">
  2.    Subir archivo:
  3.    <input type="file" name="archivo" id="Seleccionar archivo" />
  4.    <input type="submit" name="boton" value="Enviar archivo" />
  5. </form>
  6.  
  7. <?php
  8. if($_FILES["archivo"]["name"]){
  9.      if ($_FILES["archivo"]["error"] > 0) {
  10.        echo $_FILES["archivo"]["error"] . "<br/>";
  11.      } else {
  12.          // Si no hubo ningun error, hacemos otra condicion para asegurarnos que el archivo no sea repetido
  13.          if (file_exists("" . $_FILES["archivo"]["name"])) {
  14.            echo $_FILES["archivo"]["name"] . " ya existe. ";
  15.          } else {
  16.           // Si no es un archivo repetido y no hubo ningun error, procedemos a subir a la carpeta /archivos, seguido de eso mostramos la imagen subida
  17.            move_uploaded_file($_FILES["archivo"]["tmp_name"],
  18.            "" . $_FILES["archivo"]["name"]);
  19.            echo "Archivo Subido <br />";
  20.          }
  21.      }
  22. }
  23. ?>
  24.  

Bueno, con el navegador funciona perfectamente y sube el archivo, y con mozilla firefox usando http live headers he tratado de copiar prácticamente los campos sin éxito, he estado buscando bastantes códigos (se que no es una buena solución, es lo peor que se puede hacer) pero de nada han servido.

Básicamente hay que delimitar el archivo por el boundary, la variable "content-length" pongo en ella todo lo que mando en el body es decir el contenido del archivo, el los boundary, Content-Disposition etc.

Citar
POST /catcher.php HTTP/1.1
Host: web.com
User-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64; rv:42.0) Gecko/20100101 Firefox/42.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: es-ES,es;q=0.8,en-US;q=0.5,en;q=0.3
Accept-Encoding: gzip, deflate
DNT: 1
Referer: http://web.com/catcher.php
Connection: keep-alive
Content-Type: multipart/form-data; boundary=---------------------------283331266631290
Content-Length: 80890
-----------------------------283331266631290
Content-Disposition: form-data; name="archivo"; filename="ciclista.jpg"
Content-Type: image/jpeg
ÿØÿá824tn017ct09134n9t7n190347tv09q0924nct09DATOS ARCHIVO0QWECTQWTCQWT
Q48Y1V 384YNC09834NUTC
-----------------------------283331266631290
Content-Disposition: form-data; name="boton"

Enviar archivo
-----------------------------283331266631290--


Bien, ahora la petición que envío yo capturada con wireshark:

Citar
POST /catcher.php HTTP/1.1
Host: web.com
Content-Length: 81003
Connection: keep-alive
Cache-Control: no-cache

Content-Type: multipart/form-data; boundary=-----------------------------autoupdater1234
Content-Length: 80888
-----------------------------autoupdater1234
Content-Disposition: form-data; name="archivo"; filename="ciclista.jpg"
Content-Type: image/jpeg
q4w98n8934qynqv893y4ntARCHIVOQ0WY4CTN184
QWETCQWETQWTVQWETV
-----------------------------autoupdater1234
Content-Disposition: form-data; name="boton"

Enviar archivo
-----------------------------autoupdater1234--

Me salen 2 content-length pero aun corrigiendo eso falla, ahí ando. La cosa es que el content-length que "se supone estaría bien" es el que calculo yo que es el tamaño del body, pero la funcion automaticamente me pone el otro (el de toda la peticion incluyendo la cabecera), ¿como puedo cambiar eso?.

Un saludo y gracias. :)
« Última modificación: 13 Marzo 2016, 20:02 pm por Kaxperday » En línea

Cuando el poder económico parasita al político ningún partido ni dictador podrá liberarnos de él. Se reserva el 99% ese poder.
Páginas: [1] Ir Arriba Respuesta Imprimir 

Ir a:  

Mensajes similares
Asunto Iniciado por Respuestas Vistas Último mensaje
COMO ENVIAR UN ARCHIVO DE CLIENTE-SERVIDOR EN JAVA
Java
lexoazul 1 9,349 Último mensaje 16 Octubre 2009, 16:58 pm
por Debci
Enviar un archivo a un servidor « 1 2 »
Programación C/C++
Vaagish 11 6,163 Último mensaje 9 Febrero 2014, 07:31 am
por xv0
[?] Conexión HTTP Post
Java
MeCraniDOS 4 2,923 Último mensaje 6 Marzo 2014, 13:32 pm
por ThinkByYourself
Enviar mail sin formato mime (plain text)
.NET (C#, VB.NET, ASP)
dep_serg 1 2,558 Último mensaje 6 Febrero 2015, 07:10 am
por __Alvaro 2015__
[Duda] Como enviar informacion al servidor sin el metodo POST ni GET
Desarrollo Web
Flamer 2 2,566 Último mensaje 16 Marzo 2016, 08:42 am
por adastra
WAP2 - Aviso Legal - Powered by SMF 1.1.21 | SMF © 2006-2008, Simple Machines