Yosiet Serga

Members
  • Content Count

    13
  • Joined

  • Last visited

About Yosiet Serga

  • Rank
    Newbie

Recent Profile Visitors

179 profile views
  1. Hola buenas tardes, tenía tiempo que no pasaba por aquí, ya está todo solucionado, era una conversión utf8 que hacía ilegible la información para API, eliminé la conversión utf8, lo modifiqué para que se envíe la información tal cual como llega y todo funciona bien Ya está resuelto por mi lado, muchas gracias a todos por el apoyo
  2. Olá, sim, finalmente, eu poderia integrar a API do ML em meu aplicatiOlá, finalmente, eu poderia integrar a API do ML em meu aplicativo Eu tinha que carregar as imagens primeiro, e depois ligar de imagens ID com o produto Eu ainda não posso colocar minhas próprias imagens para ML, mas pelo menos eu posso duplicar publicações e outro perfil
  3. Les dejo una captura de pantalla del resultado, los productos SI SE PUBLICAN, pero las imágenes nada que se cargan
  4. En es función, se publican los productos hacia X cuenta de ML autorizada public function publish_products($data) { if ($this->get_token() && $this->get_meli_id()) { $requestData['method'] = 'post'; $requestData['headers']['Content-Type'] = 'application/json'; $requestData['post'] = str_replace('\\','',$data); $response = $this->fetch("/items", $requestData); if (isset($response['json']['error'])) { $this->addActivity(array( 'description'=>'No se pudo publicar el producto '. $data['title'] .' en el perfil '. $this->meli_id .'. Error: '. $response['json']['error'] .' - '. $response['json']['message'] .' - '. $response['json']['status'], 'type'=>'publish', 'object_id'=>$this->get_meli_id(), 'object_type'=>'customer' )); if (!empty($_SESSION['reportToEmail'])) { mail($_SESSION['reportToEmail'], "ML Importer", 'No se pudo publicar el producto ' . $data['title'] . ' en el perfil ' . $this->meli_id . '. Error: ' . $response['json']['error'] . ' - ' . $response['json']['message'] . ' - ' . $response['json']['status'] . ' - ' . serialize($response['json']['cause']) ); } return $response['json']; } else { $this->addActivity(array( 'description'=>'Se publicó con éxito el producto '. $data['tile'] .' en el perfil '. $this->meli_id, 'type'=>'publish', 'object_id'=>$this->get_meli_id(), 'object_type'=>'customer' )); if (!empty($_SESSION['reportToEmail'])) { mail($_SESSION['reportToEmail'], "ML Importer", 'Se publicó con éxito el producto ' . $data['tile'] . ' en el perfil ' . $this->meli_id); } } } else { $this->redirect($this->oauth_url); } } NOTA: El producto SI SE PUBLICA, el único dato que queda inexistente, es la imagen del producto, es decir, se publican con una foto genérica de ML indicando "Sin Foto". La data que se envía a ML, llega al email que coloquen
  5. En esta funci[on se descargan los productos de una cuenta ML public function import_products() { if ($this->get_token() && $this->get_meli_id()) { if (!$db || !($db instanceof Necoyoad_Db)) { $db = new Necoyoad_Db(DB_DRIVE, DB_HOST, DB_USER, DB_PWD, DB_NAME); } $response = $this->fetch("/users/{$this->get_meli_id()}/items/search"); $existente = 0; $nuevo = 0; $total = count($response['body]->results); foreach ($response['body']->results as $k => $v) { $resp = $this->fetch("/items/{$v}"); $desc = $this->fetch("/items/{$v}/description"); if ($resp['body']) { $meli_product_id = $resp['body']->id; $query = $db->query("SELECT * AS total FROM ". DB_PREFIX ."product WHERE `meli_product_id` = '" . $db->escape($meli_product_id) . "'"); if (empty($query->rows)) { $data = array(); $c = 0; $folder = __DIR__.'/../../../../images/data'; foreach ($resp['body']->pictures as $img) { mail($_SESSION['reportToEmail'], "ML Importer", 'Importancion de producto ' . '. MESSAGE: ' . "\n\r-------------------- PRODUCT IMG FROM REQUEST -----------------------\n\r". serialize($img). "\n\r-------------------- /PRODUCT IMG FROM REQUEST ----------------------\n\r"); if (!$img->url) continue; if (($c%2) == 0) { $fc = file_get_contents($img->url); if (!is_dir($folder)) { mkdir($folder,0777); } if (!is_dir($folder .'/'. date('m-y'))) { mkdir($folder .'/'. date('m-y'), 0777); } $img_name = 'meli-'. $this->get_meli_id() .'-'. time().mt_rand(100000,9999999) . (substr($img->url, strrpos($img->url, '.'))); $img_file = $folder .'/'. date('m-y') .'/'. $img_name; $f = fopen($img_file, 'w+'); fwrite($f, $fc); fclose($f); $data['Images'][$c]['source'] = 'http://rumat.com.ar/newapi/images/data/'. date('m-y') .'/'. $img_name; } else { $data['Images'][$c]['source'] = $img->url; } mail($_SESSION['reportToEmail'], "ML Importer", 'Importancion de producto ' . '. MESSAGE: ' . "\n\r-------------------- PRODUCT NEW IMAGE TO UPLOAD -----------------------\n\r". $data['Images'][$c]['source']. "\n\r-------------------- /PRODUCT NEW IMAGE TO UPLOAD ----------------------\n\r"); $c++; } $varis = array(); foreach ($resp['body']->variations as $i => $variation) { foreach ($variation->attribute_combinations as $j => $combination) { $varis[$i]['attribute_combinations'][$j] = array( 'id'=>$combination->id, 'value_id'=>$combination->value_id ); } $varis[$i]['available_quantity'] = $variation->available_quantity; $varis[$i]['price'] = $variation->price; $varis[$i]['picture_ids'] = $variation->picture_ids; } $db->query("INSERT INTO ". DB_PREFIX ."product SET ". "`meli_id` = '". $db->escape($this->get_meli_id()) ."',". "`meli_product_id` = '". $db->escape($meli_product_id) ."',". "`meli_category_id` = '". $db->escape($resp['body']->category_id) ."',". "`name` = '". $db->escape($resp['body']->title) ."',". "`currency_id` = '". $db->escape($resp['body']->currency_id) ."',". "`available_quantity` = '". $db->escape($resp['body']->available_quantity) ."',". "`buying_mode` = '". $db->escape($resp['body']->buying_mode) ."',". "`listing_type_id` = '". $db->escape($resp['body']->listing_type_id) ."',". "`condition` = '". $db->escape($resp['body']->condition) ."',". "`description` = '". $db->escape($desc['body']->text) ."',". "`price` = '". $db->escape($resp['body']->price) ."',". "`image` = '". str_replace("'","\'",serialize($data['Images'])) ."'". (!$varis) ? '' : ",`variations` = '". str_replace("'","\'",serialize($varis)) ."'" ); $id = $db->getLastId(); $db->query("INSERT INTO `". DB_PREFIX ."property` SET ". "`object_id` = '". $id ."',". "`object_type` = 'product',". "`group` = 'meli',". "`key` = 'product_data',". "`value` = '". serialize($resp['body']) ."'" ); $this->addActivity(array( 'description'=>'Se importó con éxito el producto '. $resp['body']->title .' del perfil '. $this->get_meli_id(), 'type'=>'import', 'object_id'=>$this->get_meli_id(), 'object_type'=>'customer' )); $nuevo++; } else { $existente++; $this->addActivity(array( 'description'=>'Intento de importar el producto '. $resp['body']->title .' del perfil '. $this->get_meli_id() .', ya existe!', 'type'=>'import', 'object_id'=>$this->get_meli_id(), 'object_type'=>'customer' )); } if (!empty($_SESSION['reportToEmail'])) { mail($_SESSION['reportToEmail'], "ML Importer", 'Importancion de producto ' . '. MESSAGE: ' . "\n\r-------------------- PRODUCT IMPORTED -----------------------\n\r". serialize($resp['body']). "\n\r-------------------- /PRODUCT IMPORTED ----------------------\n\r"); } } } $this->addActivity(array( 'description'=>'Se importaron '. $total .' productos del perfil '. $this->get_meli_id() .'. '. $nuevo .' productos nuevos y '. $existente .' productos existentes', 'type'=>'import', 'object_id'=>$this->get_meli_id(), 'object_type'=>'customer' )); if (!empty($_SESSION['reportToEmail'])) { mail($_SESSION['reportToEmail'], "ML Importer", 'Se importaron ' . $total . ' productos del perfil ' . $this->get_meli_id() . '. ' . $nuevo . ' productos nuevos y ' . $existente . ' productos existentes a las ' . date('d-m-Y h:s:i')); } } else { $this->redirect(); } } NOTA: Cambié el código para que utilice la URL de la imagen ya existente en el servidor de ML al hacer una división y el resto sea cero, y descargue la imagen al servidor local y utilice la url desde rumat.com.ar al hacer la división y el resto sea distinto de cero.
  6. PORTUGUÉS A aplicação faz ambos, primeiro baixar todos os produtos criados pela perfil X ml, e, por outro lado, pública ou carregar todos os produtos a partir de um perfil de ML de origem. Em outras palavras, todas as publicações migra de um perfil para outro. ESPAÑOL La app hace las dos cosas, por una parte descarga todos los productos creados por X perfil de ML, y por el otro lado, publica o carga todos los productos desde un perfil de ML de origen. En otras palabras, migra todas las publicaciones desde un perfil hacia otro.
  7. PORTUGUÉS Ok, eu acho que eu não entendo, porque tudo é feito, tudo o que peço é: Por que não publicar imagens usando a estrutura JSON sugerido na documentação ML? Publiquei todo o código e demonstração que queria revê-lo. Alguém aqui pode me orientar sobre que um aspecto? ESPAÑOL Ok, creo que aún no me hago entender, ya todo está hecho, lo único que pregunto es: ¿Por qué las imágenes no se publican usando la estructura Json sugerida en la documentación de ML? Publiqué todo el código y el demo para que el que quisiera revisarlo. ¿Alguien aquí puede orientarme en ese único aspecto?
  8. Pueden usar esta herramienta para leer mejor los contenidos de las variables y los mensajes del logger de la app que envía al email: http://www.unserialize.me/
  9. PORTUGUÉS Sobre a questão de permissões de arquivos e pastas, sem erros, pode até mesmo ver que o e-mail chegar URLs salvas imagens, você pode consultá-lo no navegador. No código que você pode ver quando pastas são criadas com todas as permissões ativadas ESPAÑOL Por el tema de los permisos de archivos y carpetas, no hay errores, incluso pueden ver que al email llegan las URL de las imágenes guardadas, pueden consultarla en el navegador. En el código pueden ver cuando las carpetas se crean con todos los permisos habilitados [...] $folder = __DIR__.'/../../../../images/data'; foreach ($resp['body']->pictures as $img) { mail($_SESSION['reportToEmail'], "ML Importer", 'Importancion de producto ' . '. MESSAGE: ' . "\n\r-------------------- PRODUCT IMG FROM REQUEST -----------------------\n\r". serialize($img). "\n\r-------------------- /PRODUCT IMG FROM REQUEST ----------------------\n\r"); if (!$img->url) continue; $fc = file_get_contents($img->url); if (!is_dir($folder)) { mkdir($folder,0777); } if (!is_dir($folder .'/'. date('m-y'))) { mkdir($folder .'/'. date('m-y'), 0777); } $img_name = 'meli-'. $this->get_meli_id() .'-'. time().mt_rand(100000,9999999) . (substr($img->url, strrpos($img->url, '.'))); $img_file = $folder .'/'. date('m-y') .'/'. $img_name; $f = fopen($img_file, 'w+'); fwrite($f, $fc); fclose($f); $data['Images'][$c]['source'] = 'http://rumat.com.ar/newapi/images/data/'. date('m-y') .'/'. $img_name; mail($_SESSION['reportToEmail'], "ML Importer", 'Importancion de producto ' . '. MESSAGE: ' . "\n\r-------------------- PRODUCT NEW IMAGE TO UPLOAD -----------------------\n\r". $data['Images'][$c]['source']. "\n\r-------------------- /PRODUCT NEW IMAGE TO UPLOAD ----------------------\n\r"); $c++; } [...] NOTA: Pueden descargar la app desde github, pueden clonar el proyecto, pueden hacer las pruebas ustedes mismo desde sus servidores de desarrollo configurando virtual_hosts con un certificado ssl instalado de manera local para que prueben. Por eso les dejé publicado todos los recursos, para que hicieran pruebas reales. El error en el cual les pido ayuda, no es un error de la app, ni de la sintáxis, sino un problema con la data enviada a ML por la cual publica los productos sin las imágenes.
  10. PORTUGUÉS O nome do arquivo com microtime, etc. é apenas para evitar a possibilidade de que os arquivos são reescritas no futuro, ou seja, é apenas um nome de arquivo, não tem nada a ver com o problema que eu expressar. Quando Quer dizer, eu não vejo nenhum erro, eu quero dizer a resposta HTTP feita para a API URL usando o método RESTFUL não deuelve me nenhum erro, ou seja, ML não indica que há um erro nos dados enviados ou qualquer coisa simlar . Esta parte do error_reporting (0) de código; é simplesmente esconder o meu código de erros php, o código do ponto de vista da sintaxe está bem. É por isso que eu deixei nos links mostrar para experimentar o aplicativo e pode me dar uma sugestão mais precisa. ESPAÑOL El nombre de los archivos con microtime, etc. es solo para evitar la posibilidad que se reescriban los archivos en el futuro, es decir, es solo un nombre de archivo, no tiene nada que ver con el problema que expreso. Cuando me refiero a que no veo ningún error, me refiero a que la respuesta HTTP hecha hacia la url API usando el método RESTFUL no me deuelve ningún error, es decir, ML no me indica que exista algún error en la data enviada ni nada simlar. Esta parte del código error_reporting(0); es solo ocultar los errores de mi código php, el código desde el punto de vista de sintáxis está bien. Por eso les dejé los enlaces de la demostración para que prueben la app y puedan darme una sugerencia más acertada.
  11. Por favor, antes de que alguien me vaya a contestar refiriendo al website de la API de ML o me vaya a indicar que busque dentro del foro, problemas similares para ubicar la respuesta, les menciono que ya me he estudiado la documentación de la API nueva y vieja, he paseado por el foro y por internet por dos semanas en búsqueda de una solución, y honestamente no consigo nada, por ese motivo acudo al foro a ver si algún admin o algún experto me ayude con el problema. Les pido que prueben la app y revisen los resultados y los mensajes del log a ver que sucede. Muchas gracias.
  12. He desarrollado una clase modificada del SDK para PHP y con ella, una webapp para importar y publicar masivamente (básicamente es para migrar desde un perfil a otro). Demo: https://www.rumat.com.ar/newapi/ Repository: https://github.com/yosietserga/MELI-Importer-and-Publisher He colocado los mensajs del log que se envíen por email, para que les llegue el reporte con el log, deben ingresar el email en el campo de abajo. EL PROBLEMA El problema es el siguiente, tengo 4 semanas intentando que se publiquen las imágenes al crear el producto dentro de una cuenta ML, pero no logro que se vean o que las agarre. Al principio solo ubicaba el link de la misma imagen del producto proveniente de ML y la colocaba tal cual para ahorrar ancho de banda, tanto de ML como del importador, pero nada que funcionó. Cambiando la lógica, modifiqué el código para descargar la imagen al servidor, renombrarla y luego colcoar el link de la imagen descargada, pero el problema persiste. Ya en medidas desesperadas, coloqué la URL de una imagen X en internet para descartar cualquier error con el archivo en sí, y aún así, nada que funciona. Eso por un lado, por otra parte, a los productos que tienen variaciones o atributos (como los zapatos), al publicarlos usando la estructura sugerida por developers.mercadolibre.com, genera un error indicando que faltaron unos atributos que son obligatorios, al comparar el Array generado por la app, veo que se genera exactamente igual a la documentación de ML. No tengo idea de cuales son los errores ni en dónde se encuentran. Por favor, si lguien tiene mayor conocimiento sobre el asunto, por favor ayúdame. NOTA: Los mensajes de logs legan serializados, para leerlo con comodidad, deben usar alguna herramienta online que los estructure de manera más legible. ARCHIVOS La clase principal versionada de MELI es esta: <?php require_once(__DIR__.'/../../vendor/xhttp/xhttp.php'); require_once(__DIR__.'/../../vendor/meli/meli.php'); class Necoyoad_Meli { public $app_id; public $app_secret; public $token; public $refresh_token; public $expire; public $code; public $meli_id; private $handler; private $meli; private $redirectTo; private $request; private $session; private $oauth_url; public function __construct($app_id, $app_secret) { if (class_exists('xhttp')) { $this->handler = new xhttp; } else { $this->handler = new thisHandler; } $this->app_id = $app_id; $this->app_secret = $app_secret; $this->meli = new Meli($this->app_id, $this->app_secret); $this->request = new Necoyoad_Request; $this->session = new Necoyoad_Session; } public function initialize() { $this->oauth_url = $this->meli->getAuthUrl($this->getRedirectUrl()); } public function setRedirectUrl($url) { $this->redirectTo = $url; } public function getRedirectUrl() { return $this->redirectTo; } public function index() { $mlactions = array( 'import_products', 'publish_products', 'add_profile' ); $this->initialize(); if ($this->request->hasQuery('action')) { $_SESSION['mlaction'] = $this->request->getQuery('action'); } if ($this->request->getQuery('action') == 'add_profile') { $this->clear_code(); $this->clear_token(); $this->clear_refresh_token(); $this->clear_expire(); $this->redirect(); } if ($this->request->hasQuery('code') && !$this->get_code()) { $response = $this->authorize($this->request->getQuery('code'), $this->getRedirectUrl()); $this->set_code( $this->request->getQuery('code') ); $response['body'] = (object)json_decode($response['body']); if (isset($response['body']->access_token)) $this->set_token( $response['body']->access_token ); if (isset($response['body']->expires_in)) $this->set_expire( time() + $response['body']->expires_in ); if (isset($response['body']->refresh_token)) $this->set_refresh_token( $response['body']->refresh_token ); unset($_GET['code']); } if (!$this->get_code() && $this->request->hasQuery('meli')) { $this->clear_code(); $this->clear_token(); $this->clear_refresh_token(); $this->clear_expire(); $this->redirect(); } $this->check_expire( $this->get_expire() ); if ($this->get_token()) { if (isset($_SESSION['mlaction']) && in_array($_SESSION['mlaction'], $mlactions)) { $result = $this->{$_SESSION['mlaction']}(); } else { $this->clear_code(); $this->clear_token(); $this->clear_refresh_token(); $this->clear_expire(); } } else { $this->clear_code(); $this->clear_token(); if ($this->request->hasQuery('meli')) { $this->redirect(); } } if (isset($_REQUEST['logout'])) { $this->clear_code(); $this->clear_token(); $this->clear_refresh_token(); $this->clear_expire(); } if ($this->request->hasQuery('error')) { return array( 'error'=>$this->request->getQuery('error'), 'error_description'=>$this->request->getQuery('error_description') ); } elseif (isset($result)) { return $result; } } public function clear_code() { unset($this->code); unset($_SESSION['mlcode']); } public function clear_token() { unset($this->token); unset($_SESSION['mltoken']); } public function clear_meli_id() { unset($this->meli_id); unset($_SESSION['mlmeli_id']); } public function clear_refresh_token() { unset($this->refresh_token); unset($_SESSION['mlrefresh_token']); } public function clear_expire() { unset($this->expire); unset($_SESSION['mlexpire']); } public function get_code() { return isset($this->code) ? $this->code : $_SESSION['mlcode']; } public function set_code($code) { $this->code = $_SESSION['mlcode'] = $code; } public function get_token() { return isset($this->token) ? $this->token : $_SESSION['mltoken']; } public function set_token($token) { $this->token = $_SESSION['mltoken'] = $token; } public function get_refresh_token() { return isset($this->refresh_token) ? $this->refresh_token : $_SESSION['mlrefresh_token']; } public function set_refresh_token($refresh_token) { $this->refresh_token = $_SESSION['mlrefresh_token'] = $refresh_token; } public function get_expire() { return isset($this->expire) ? $this->expire : $_SESSION['mlexpire']; } public function set_expire($time) { $this->expire = $_SESSION['mlexpire'] = $time; } public function get_meli_id() { return isset($this->meli_id) ? $this->meli_id : $_SESSION['mlmeli_id']; } public function set_meli_id($meli_id) { $this->meli_id = $_SESSION['mlmeli_id'] = $meli_id; } public function check_expire($time) { if(isset($time) && $time < time()) { // Make the refresh proccess $refresh = $this->refreshToken(); if (isset($refresh->error)) { return array( 'error'=>$refresh->error, 'status'=>$refresh->status, 'message'=>$refresh->message ); } else { // Now we create the sessions with the new parameters $this->set_token( $refresh->access_token ); $this->set_refresh_token( $refresh->refresh_token ); $this->set_expire( time() + $refresh->expires_in ); } } } public function add_profile() { if ($this->get_token()) { $response = $this->fetch('/users/me'); return $this->addCustomerFromMeli(array( 'company' => $response['body']->nickname, 'firstname' => $response['body']->first_name, 'lastname' => $response['body']->last_name, 'email' => $response['body']->email, 'meli_id' => $response['body']->id, 'meli_token' => $_SESSION['mltoken'], 'meli_refresh'=> $_SESSION['mlrefresh_token'], 'meli_expire' => $_SESSION['mlexpire'], 'meli_code' => $_SESSION['mlcode'] )); } else { $this->redirect(); } } public function delete_profile($id) { $this->deleteCustomerFromMeli($id); } public function get_profiles($data = null) { return $this->getProfiles($data); } public function get_products($data = null) { return $this->getProducts($data); } public function get_activities($data = null) { return $this->getActivities($data); } public function import_products() { if ($this->get_token() && $this->get_meli_id()) { if (!$db || !($db instanceof Necoyoad_Db)) { $db = new Necoyoad_Db(DB_DRIVE, DB_HOST, DB_USER, DB_PWD, DB_NAME); } $response = $this->fetch("/users/{$this->get_meli_id()}/items/search"); $existente = 0; $nuevo = 0; $total = count($response['body']->results); foreach ($response['body']->results as $k => $v) { $resp = $this->fetch("/items/{$v}"); $desc = $this->fetch("/items/{$v}/description"); if ($resp['body']) { $meli_product_id = $resp['body']->id; $query = $db->query("SELECT * AS total FROM ". DB_PREFIX ."product WHERE `meli_product_id` = '" . $db->escape($meli_product_id) . "'"); if (empty($query->rows)) { $data = array(); $c = 0; $folder = __DIR__.'/../../../../images/data'; foreach ($resp['body']->pictures as $j => $img) { if (!$img->url) continue; $fc = file_get_contents($img->url); if (!is_dir($folder)) { mkdir($folder,0777); } if (!is_dir($folder .'/'. date('m-y'))) { mkdir($folder .'/'. date('m-y'), 0777); } $img_name = 'meli-'. $this->get_meli_id() .'-'. time().mt_rand(100000,9999999) . (substr($img->url, strrpos($img->url, '.'))); $img_file = $folder .'/'. date('m-y') .'/'. $img_name; $f = fopen($img_file, 'w+'); fwrite($f, $fc); fclose($f); $data['Images'][$c]['source'] = 'http://rumat.com.ar/newapi/images/data/'. date('m-y') .'/'. $img_name; $c++; } $varis = array(); foreach ($resp['body']->variations as $i => $variation) { foreach ($variation->attribute_combinations as $j => $combination) { $varis[$i]['attribute_combinations'][$j] = array( 'id'=>$combination->id, 'value_id'=>$combination->value_id ); } $varis[$i]['available_quantity'] = $variation->available_quantity; $varis[$i]['price'] = $variation->price; $varis[$i]['picture_ids'] = $variation->picture_ids; } $db->query("INSERT INTO ". DB_PREFIX ."product SET ". "`meli_id` = '". $db->escape($this->get_meli_id()) ."',". "`meli_product_id` = '". $db->escape($meli_product_id) ."',". "`meli_category_id` = '". $db->escape($resp['body']->category_id) ."',". "`name` = '". $db->escape($resp['body']->title) ."',". "`currency_id` = '". $db->escape($resp['body']->currency_id) ."',". "`available_quantity` = '". $db->escape($resp['body']->available_quantity) ."',". "`buying_mode` = '". $db->escape($resp['body']->buying_mode) ."',". "`listing_type_id` = '". $db->escape($resp['body']->listing_type_id) ."',". "`condition` = '". $db->escape($resp['body']->condition) ."',". "`description` = '". $db->escape($desc['body']->text) ."',". "`price` = '". $db->escape($resp['body']->price) ."',". "`image` = '". str_replace("'","\'",serialize($data['Images'])) ."'". (!$varis) ? '' : ",`variations` = '". str_replace("'","\'",serialize($varis)) ."'" ); $id = $db->getLastId(); $db->query("INSERT INTO `". DB_PREFIX ."property` SET ". "`object_id` = '". $id ."',". "`object_type` = 'product',". "`group` = 'meli',". "`key` = 'product_data',". "`value` = '". serialize($resp['body']) ."'" ); $this->addActivity(array( 'description'=>'Se importó con éxito el producto '. $resp['body']->title .' del perfil '. $this->get_meli_id(), 'type'=>'import', 'object_id'=>$this->get_meli_id(), 'object_type'=>'customer' )); $nuevo++; } else { $existente++; $this->addActivity(array( 'description'=>'Intento de importar el producto '. $resp['body']->title .' del perfil '. $this->get_meli_id() .', ya existe!', 'type'=>'import', 'object_id'=>$this->get_meli_id(), 'object_type'=>'customer' )); } if (!empty($_SESSION['reportToEmail'])) { mail($_SESSION['reportToEmail'], "ML Importer", 'Importancion de producto ' . '. MESSAGE: ' . "\n\r-------------------- PRODUCT IMPORTED -----------------------\n\r". serialize($varis). "\n\r-------------------- /PRODUCT IMPORTED ----------------------\n\r"); } } } $this->addActivity(array( 'description'=>'Se importaron '. $total .' productos del perfil '. $this->get_meli_id() .'. '. $nuevo .' productos nuevos y '. $existente .' productos existentes', 'type'=>'import', 'object_id'=>$this->get_meli_id(), 'object_type'=>'customer' )); if (!empty($_SESSION['reportToEmail'])) { mail($_SESSION['reportToEmail'], "ML Importer", 'Se importaron ' . $total . ' productos del perfil ' . $this->get_meli_id() . '. ' . $nuevo . ' productos nuevos y ' . $existente . ' productos existentes a las ' . date('d-m-Y h:s:i')); } } else { $this->redirect(); } } public function publish_products($data) { if ($this->get_token() && $this->get_meli_id()) { $requestData['method'] = 'post'; $requestData['headers']['Content-Type'] = 'application/json'; $requestData['post'] = str_replace('\\','',$data); $response = $this->fetch("/items", $requestData); if (isset($response['json']['error'])) { $this->addActivity(array( 'description'=>'No se pudo publicar el producto '. $data['title'] .' en el perfil '. $this->meli_id .'. Error: '. $response['json']['error'] .' - '. $response['json']['message'] .' - '. $response['json']['status'], 'type'=>'publish', 'object_id'=>$this->get_meli_id(), 'object_type'=>'customer' )); if (!empty($_SESSION['reportToEmail'])) { mail($_SESSION['reportToEmail'], "ML Importer", 'No se pudo publicar el producto ' . $data['title'] . ' en el perfil ' . $this->meli_id . '. Error: ' . $response['json']['error'] . ' - ' . $response['json']['message'] . ' - ' . $response['json']['status'] . ' - ' . serialize($response['json']['cause']) ); } return $response['json']; } else { $this->addActivity(array( 'description'=>'Se publicó con éxito el producto '. $data['tile'] .' en el perfil '. $this->meli_id, 'type'=>'publish', 'object_id'=>$this->get_meli_id(), 'object_type'=>'customer' )); if (!empty($_SESSION['reportToEmail'])) { mail($_SESSION['reportToEmail'], "ML Importer", 'Se publicó con éxito el producto ' . $data['tile'] . ' en el perfil ' . $this->meli_id); } } } else { $this->redirect($this->oauth_url); } } public function escape($str) { if (isset($str)) { if ($str !== mb_convert_encoding(mb_convert_encoding($str, 'UTF-32', 'UTF-8'), 'UTF-8', 'UTF-32')) $str = mb_convert_encoding($str, 'UTF-8', mb_detect_encoding($str)); $str = htmlentities($str, ENT_NOQUOTES, 'UTF-8'); $str = preg_replace('`&([a-z]{1,2})(acute|uml|circ|grave|ring|cedil|slash|tilde|caron|lig);`i', '\1', $str); $str = html_entity_decode($str, ENT_NOQUOTES, 'UTF-8'); $str = preg_replace(array('`[^a-z0-9]`i', '`[-]+`'), '-', $str); $str = strtolower(trim($str, '-')); return $str; } else { return false; } } private function addCustomerFromMeli($data, $db = null) { if (!$db || !($db instanceof Necoyoad_Db)) { $db = new Necoyoad_Db(DB_DRIVE, DB_HOST, DB_USER, DB_PWD, DB_NAME); } if (!$this->getCustomerByMeli($data, $db)) { $sql = "INSERT INTO " . DB_PREFIX . "customer SET " . "`firstname` = '" . $db->escape($data['firstname']) . "'," . "`lastname` = '" . $db->escape($data['lastname']) . "'," . "`company` = '" . $db->escape($data['company']) . "'," . "`email` = '" . $db->escape($data['email']) . "'," . "`meli_id` = '" . $db->escape($data['meli_id']) . "'," . "`meli_token` = '" . $db->escape($data['meli_token']) . "'," . "`meli_refresh_token` = '" . $db->escape($data['meli_refresh']) . "'," . "`meli_expire` = '" . $db->escape($data['meli_expire']) . "'," . "`meli_code` = '" . $db->escape($data['meli_code']) . "'"; $query = $db->query($sql); $id = $db->getLastId(); $this->addActivity(array( 'description'=>'Se agregó con éxito un nuevo perfil '. $data['meli_id'] .' '. $data['company'], 'type'=>'new_profile', 'object_id'=>$data['meli_id'], 'object_type'=>'customer' )); if (!empty($_SESSION['reportToEmail'])) { mail($_SESSION['reportToEmail'], "ML Importer", 'Se agregó con éxito un nuevo perfil ' . $data['meli_id'] . ' ' . $data['company']); } return $id; } else { return false; } } private function deleteCustomerFromMeli($id, $db = null) { if (!$db || !($db instanceof Necoyoad_Db)) { $db = new Necoyoad_Db(DB_DRIVE, DB_HOST, DB_USER, DB_PWD, DB_NAME); } $db->query("DELETE FROM " . DB_PREFIX . "property WHERE ". "`object_id` IN ". "(SELECT meli_id FROM " . DB_PREFIX . "customer WHERE `id` = '" . $db->escape($id) . "') ". "AND object_type = 'customer'"); $db->query("DELETE FROM " . DB_PREFIX . "property WHERE ". "`object_id` IN ". "(SELECT meli_id FROM " . DB_PREFIX . "customer WHERE `meli_id` = '" . $db->escape($id) . "') ". "AND object_type = 'customer'"); $db->query("DELETE FROM " . DB_PREFIX . "property WHERE ". "`object_id` NOT IN (SELECT id FROM " . DB_PREFIX . "product) ". "AND object_type = 'product'"); $db->query("DELETE FROM " . DB_PREFIX . "customer WHERE `meli_id` = '" . $db->escape($id) . "'"); $db->query("DELETE FROM " . DB_PREFIX . "product WHERE `meli_id` = '" . $db->escape($id) . "'"); $this->addActivity(array( 'description'=>'Se eliminó con éxito perfil '. $id, 'type'=>'delete_profile', 'object_id'=>$id, 'object_type'=>'customer' )); if (!empty($_SESSION['reportToEmail'])) { mail($_SESSION['reportToEmail'], "ML Importer", 'Se eliminó con éxito perfil ' . $id); } } private function getProfiles($data = null, $db = null) { if (!$db || !($db instanceof Necoyoad_Db)) { $db = new Necoyoad_Db(DB_DRIVE, DB_HOST, DB_USER, DB_PWD, DB_NAME); } $sql = "SELECT * FROM `". DB_PREFIX ."customer` "; if (!empty($data['meli_id'])) { $criteria[] = " LCASE(`meli_id`) LIKE '%". $db->escape(strtolower($data['meli_id'])) ."%'"; } if (!empty($data['email'])) { $criteria[] = " LCASE(`email`) LIKE '%". $db->escape(strtolower($data['email'])) ."%'"; } if (!empty($data['company'])) { $criteria[] = " LCASE(`company`) LIKE '%". $db->escape(strtolower($data['company'])) ."%'"; } if (!empty($criteria)) { $sql .= " WHERE ". implode(" AND ", $criteria); } $query = $db->query($sql); return $query->rows; } private function getProducts($data = null, $db = null) { if (!$db || !($db instanceof Necoyoad_Db)) { $db = new Necoyoad_Db(DB_DRIVE, DB_HOST, DB_USER, DB_PWD, DB_NAME); } $sql = "SELECT * FROM `". DB_PREFIX ."product` "; if (!empty($data['meli_id'])) { $criteria[] = " LCASE(`meli_id`) LIKE '%". $db->escape(strtolower($data['meli_id'])) ."%'"; } if (!empty($data['meli_product_id'])) { $criteria[] = " LCASE(`meli_product_id`) LIKE '%". $db->escape(strtolower($data['meli_product_id'])) ."%'"; } if (!empty($data['name'])) { $criteria[] = " LCASE(`name`) LIKE '%". $db->escape(strtolower($data['name'])) ."%'"; } if (!empty($criteria)) { $sql .= " WHERE ". implode(" AND ", $criteria); } $query = $db->query($sql); return $query->rows; } private function getActivities($data = null, $db = null) { if (!$db || !($db instanceof Necoyoad_Db)) { $db = new Necoyoad_Db(DB_DRIVE, DB_HOST, DB_USER, DB_PWD, DB_NAME); } $sql = "SELECT * FROM `". DB_PREFIX ."activity` "; if (!empty($data['type'])) { $criteria[] = " LCASE(`type`) = '". $db->escape(strtolower($data['meli_id'])) ."'"; } if (!empty($data['object_type'])) { $criteria[] = " LCASE(`object_type`) = '". $db->escape(strtolower($data['object_type'])) ."'"; } if (!empty($criteria)) { $sql .= " WHERE ". implode(" AND ", $criteria); } if (isset($data['sort'])) { $sql .= " ORDER BY `". $data['sort'] ."` "; } else { $sql .= " ORDER BY `date_added` "; } if (isset($data['order'])) { $sql .= $data['order']; } else { $sql .= " DESC "; } if (isset($data['start']) && isset($data['limit'])) { $sql .= " LIMIT ". (int)$data['start'] .",". (int)$data['limit']; } elseif (isset($data['limit'])) { $sql .= " LIMIT ". (int)$data['limit']; } $query = $db->query($sql); return $query->rows; } private function getCustomerByMeli($data, $db = null) { if (!$db || !($db instanceof Necoyoad_Db)) { $db = new Necoyoad_Db(DB_DRIVE, DB_HOST, DB_USER, DB_PWD, DB_NAME); } $sql = "SELECT * FROM ". DB_PREFIX ."customer WHERE ". "`email` = '". $db->escape($data['email']) ."' ". "OR `meli_id` = '". $db->escape($data['meli_id']) ."'"; $query = $db->query($sql); return $query->num_rows; } private function redirect() { echo "<script>location.href = '{$this->oauth_url}'</script>"; } private function fetch($uri, $data=null) { $url = 'https://api.mercadolibre.com'; $response = $this->handler->fetch($url . $uri . '?access_token=' . $_SESSION['mltoken'], $data); $response['body'] = (object)json_decode($response['body']); return $response; } private function authorize($code, $redirect_uri) { $requestData['method'] = 'post'; $requestData['post'] = 'code=' . $code . '&client_id=' . $this->app_id . '&client_secret=' . $this->app_secret . '&redirect_uri=' . urlencode($redirect_uri) . '&grant_type=authorization_code'; $this->addActivity(array( 'description'=>'Se solicitó acceso a un perfil con el ML Code '. $code .'', 'type'=>'authorization_code', 'object_id'=>$this->get_meli_id(), 'object_type'=>'customer' )); return $this->handler->fetch('https://api.mercadolibre.com/oauth/token', $requestData); } private function refreshToken() { $requestData['method'] = 'post'; $requestData['post'] = 'refresh_token=' . $this->refresh_token . '&client_id=' . $this->app_id . '&client_secret=' . $this->app_secret . '&grant_type=refresh_token'; $response = $this->handler->fetch('https://api.mercadolibre.com/oauth/token', $requestData); if (isset($response['json']['error'])) { $this->addActivity(array( 'description'=>'No se pudo renovar el token para el perfil '. $this->meli_id .'. No existe o es incorrecto. Error: '. $response['json']['error'] .' - '. $response['json']['message'] .' - '. $response['json']['status'], 'type'=>'refresh_token', 'object_id'=>$this->get_meli_id(), 'object_type'=>'customer' )); return (object)$response['json']; } else { $this->addActivity(array( 'description'=>'Se renovó con éxito el token para el perfil '. $this->meli_id, 'type'=>'refresh_token', 'object_id'=>$this->get_meli_id(), 'object_type'=>'customer' )); return (object)json_decode($response['body']); } } private function addActivity($data, $db = null) { if (!$db || !($db instanceof Necoyoad_Db)) { $db = new Necoyoad_Db(DB_DRIVE, DB_HOST, DB_USER, DB_PWD, DB_NAME); } $sql = "INSERT INTO `". DB_PREFIX ."activity` SET ". "`object_id` = '". $db->escape($data['object_id']) ."',". "`object_type` = '". $db->escape($data['object_type']) ."',". "`description` = '". $db->escape($data['description']) ."',". "`icon` = '". $db->escape($data['icon']) ."'"; $query = $db->query($sql); } } class thisHandler { public function fetch($url, $options = null) { return $this->request($url, $options); } private function request($url, $options = null) { if (!isset($options['method']) || !in_array($options['method'], array('GET','POST','PUT','DELETE'))) { $options['method'] = 'GET'; } if (isset($options['content']) && !empty($options['content'])) { if (is_array($options['content'])) { $options['content'] = http_build_query($options['content']); } else { $options['content'] = urlencode($options['content']); } } $context = stream_context_create($options); $resp['url'] = $url; $resp['request'] = $context; $resp['body'] = file_get_contents($url, false, $context); return $resp; } } El archivo donde se instancia el proceso de la información, es este: <?php error_reporting(0); require_once('config.php'); require_once('src/Necoyoad/autoload.php'); $session = new Necoyoad_Session; $request = new Necoyoad_Request; $meli = new Necoyoad_Meli(MELI_APP_ID, MELI_APP_SECRET); $meli->setRedirectUrl(MELI_REDIRECT_URL); $result = $meli->initialize(); if ($request->hasPost('reportToEmail')) { $_SESSION['reportToEmail'] = $request->getPost('reportToEmail'); } $importer = $meli->get_profiles(array('meli_id'=>$request->getPost('profileToImport'))); if (isset($importer[0]['meli_id']) && $request->hasQuery('import_products')) { $meli->set_refresh_token( $importer[0]['meli_refresh_token'] ); $meli->set_token( $importer[0]['meli_token'] ); $meli->set_expire( $importer[0]['meli_expire'] ); $meli->set_code( $importer[0]['meli_code'] ); $meli->set_meli_id( $importer[0]['meli_id'] ); $meli->check_expire( $meli->get_expire() ); $meli->import_products(); } $exporter = $meli->get_profiles(array('meli_id'=>$request->getPost('profileToExport'))); if (isset($exporter[0]['meli_id']) && $request->hasQuery('publish_products')) { $meli->clear_refresh_token(); $meli->clear_token(); $meli->clear_expire(); $meli->clear_code(); $meli->clear_meli_id(); $meli->set_refresh_token( $exporter[0]['meli_refresh_token'] ); $meli->set_token( $exporter[0]['meli_token'] ); $meli->set_expire( $exporter[0]['meli_expire'] ); $meli->set_code( $exporter[0]['meli_code'] ); $meli->set_meli_id( $exporter[0]['meli_id'] ); $meli->check_expire( $meli->get_expire() ); $total = $published = $error = 0; foreach ($meli->get_products(array('meli_id'=>$importer[0]['meli_id'])) as $product) { $data['title'] = $product['name']; $data['category_id'] = $product['meli_category_id']; $data['price'] = ((int)$product['price'] <= 0) ? 100 : (float)$product['price']; $data['currency_id'] = (is_null($product['currency_id'])) ? 'ARS' : $product['currency_id']; $data['available_quantity'] = ($product['available_quantity'] <= 0) ? 1 : $product['available_quantity']; $data['buying_mode'] = $product['buying_mode']; $data['listing_type_id'] = ($product['listing_type_id'] == 'free') ? 'bronze' : $product['listing_type_id']; $data['condition'] = $product['condition']; $data['description'] = $product['description']; if ($product['variations']) $data['variations'] = str_replace("\'","'",unserialize($product['variations'])); $data['pictures'] = array( array('source'=>'http://rumat.com.ar/newapi/images/data/07-16/meli-118503685-14677759556325976.jpg') ); $data['pictures'] = str_replace("\'","'",unserialize($product['image'])); $result = $meli->publish_products($data); if ($result['error']) { $error_log .= "\n\r-------------------- SUCCESS -----------------------\n\r"; $error_log .= serialize($result); $error_log .= "\n\r-------------------- /SUCCESS ----------------------\n\r"; $error++; } else { $error_log = ""; $published++; } $total++; } if (!empty($_SESSION['reportToEmail'])) { mail($_SESSION['reportToEmail'], "ML Importer", 'Se intentaron publicar ' . $total . ' productos en el perfil ' . $meli->get_meli_id() . '. Se publicaron: ' . $published . ' y dieron error: ' . $error . '. MESSAGE: ' . $error_log); } } if ($request->hasQuery('getActivities')) { header('Cache-Control: no-cache, must-revalidate'); header('Expires: Mon, 26 Jul 1997 05:00:00 GMT'); header('Content-Type: application/json'); echo json_encode($meli->get_activities(array( 'order'=>'DESC', 'sort'=>'date_added', 'limit'=>20 ))); } if ($request->hasQuery('deleteProfile') && $request->hasPost('id')) { $meli->delete_profile($request->getPost('id')); } y el archivo HTML que integra todo: <?php error_reporting(0); require_once('config.php'); require_once('src/Necoyoad/autoload.php'); $session = new Necoyoad_Session; $request = new Necoyoad_Request; $meli = new Necoyoad_Meli(MELI_APP_ID, MELI_APP_SECRET); $meli->setRedirectUrl(MELI_REDIRECT_URL); $result = $meli->index(); ?> <!doctype html> <html class="no-js" lang="en" dir="ltr"> <head> <meta charset="utf-8"> <meta http-equiv="x-ua-compatible" content="ie=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Necoyoad Meli Manager</title> <link rel="stylesheet" href="css/foundation.css"> <link rel="stylesheet" href="https://code.jquery.com/ui/1.12.0-rc.2/themes/smoothness/jquery-ui.css"> <link rel="stylesheet" href="css/app.css"> </head> <body> <div class="row"> <div class="large-12 columns"> <h1 style="text-align:center"><img src="https://upload.wikimedia.org/wikipedia/commons/d/d4/MercadoLibre_logo.PNG" alt="MercadoLibre Manager" width="300" /></h1> </div> </div> <div class="row"> <div class="large-12 columns"> <div class="callout"> <p>INSTRUCCIONES: Para importar y exportar productos autom[aticamente, los usuarios deben estar registrados en la aplicación previamente. Para agregar nuevos usuarios haga click en el botón <i>Agregar Usuario</i></p> <div class="row"> <div class="large-4 medium-4 columns"> <p> <a href="index.php?action=add_profile&meli=1" class="button">Agregar Usuario</a> </p> <p> <ul id="profilesWrapper"> <?php foreach ($meli->get_profiles() as $profile) { ?> <?php if (empty($profile['meli_id'])) continue; ?> <li data-meli_id="<?php echo $profile['meli_id']; ?>"> <button class="button" aria-label="Dismiss alert" type="button" onclick="deleteProfile('<?php echo $profile['meli_id']; ?>');" style="padding:0.5em" data-close> <span aria-hidden="true">×</span> Eliminar </button> <br /> <?php echo $profile['company']; ?><br /> <?php echo $profile['email']; ?> </li> <?php } ?> </ul> </p> </div> <div class="large-8 medium-8 columns"> <div class="large-6 medium-6 columns"> <p> Arrastre hasta aquí el perfil de donde desea <b>Descargar</b> productos </p> <div id="importerWrapper"> <ul> <li class="placeholder"><img src="images/avatar01.jpg" alt="Download" /></li> </ul> </div> </div> <div class="large-6 medium-6 columns"> <p> Arrastre hasta aquí el perfil donde desea <b>Publicar</b> productos </p> <div id="exporterWrapper"> <ul> <li class="placeholder"><img src="images/avatar02.jpg" alt="Upload" /></li> </ul> </div> </div> <div class="large-12 medium-12 columns"> <a class="button" style="width:100%" href="#" onclick="downloadUploadProfile();return false;">Importar / Exportar</a> <br /> <input type="email" id="reportToEmail" name="reportToEmail" value="" placeholder="Ingresa el email a reportar" /> </div> </div> </div> <input type="hidden" value="" id="profileToImport" name="profileToImport" /> <input type="hidden" value="" id="profileToExport" name="profileToExport" /> <div class="row"> <div class="large-12 medium-12 columns"> <div id="activitiesWrapper"> <ul> <li></li> </ul> </div> </div> </div> </div> </div> </div> <script src="js/vendor/jquery.js"></script> <script src="js/vendor/what-input.js"></script> <script src="js/vendor/foundation.js"></script> <script src="https://code.jquery.com/ui/1.12.0-rc.2/jquery-ui.min.js"></script> <script src="js/app.js"></script> </body> </html>