<?php
//////////////////////////////////////////////////////////////////////////
// Automatically Lists Something on Amazon for Sale based on UPC
//
// Written By: Andy Pavlo - hide@address.com
// Created On: Sometime in the summer of 2002
//
// No guarentees that this will work since it is dependant on what
// the Amazon store looks like
//
// Sooner or later I'll add some better documentation, but it should be
// somewhat self-explantory
//
// And yes I know the code looks worse then a hooker after Mardi Gras!!
//////////////////////////////////////////////////////////////////////////
//
// Condition Values
//
define("CONDT_NEW", 100);
define("CONDT_USED_LIKE_NEW", 210);
define("CONDT_USED_VERY_GOOD", 220);
define("CONDT_USED_GOOD", 230);
define("CONDT_USED_ACCEPTABLE", 240);
define("CONDT_COLLECTIBLE_LIKE_NEW", 310);
define("CONDT_COLLECTIBLE_VERY_GOOD", 320);
define("CONDT_COLLECTIBLE_GOOD", 330);
define("CONDT_COLLECTIBLE_ACCEPTABLE", 340);
class amazon_sell {
var $error;
var $upc;
var $price;
var $postal_code;
var $condition;
var $comments;
var $commision;
var $end_date;
var $zshop_id;
var $exchange_id;
var $remove_reason;
var $price_max;
var $price_min;
var $price_recommended;
var $price_average;
//
// If the list price they want to sell at is higher then allowed,
// they can make it so it automatically lowers it
//
var $lower_price_to_max = false;
var $lower_price_to_min = false;
var $lower_price_to_recommended = false;
var $lower_price_to_average = false;
var $shipping_stnd_credit;
var $shipping_intl_credit;
var $shipping_prir_credit;
var $shipping_intl = false;
var $shipping_prir = false;
//
// Possible Condition Values
// 100: New
// 210: Used - Like New
// 220: Used - Very Good
// 230: Used - Good
// 240: Used - Acceptable
// 310: Collectible - Like New
// 320: Collectible - Very Good
// 330: Collectible - Good
// 340: Collectible - Acceptable
//
var $condition;
var $login_email;
var $login_pass;
var $session_id;
//
// Private URLs we need to post the item
//
var $_homepage = "http://www.amazon.com:80/exec/obidos/subst/home/home.html";
var $_upc_post = "http://s1.amazon.com/exec/varzea/sdp/sai-condition/ref=sdp_slp_sell2/";
var $_condt_post = "http://s1.amazon.com/exec/varzea/sdp/sai-price/";
var $_info_post = "http://s1.amazon.com/exec/varzea/sdp/sai-confirm/";
var $_login_post = "http://s1.amazon.com/exec/varzea/register/process-login/";
var $_confirm_post = "http://s1.amazon.com/exec/varzea/sdp/sai-thank-you/";
var $_remove_post = "http://s1.amazon.com/exec/varzea/cancel-fixed-price-exchange-confirmation/";
//
// Private things
//
var $_cookie_jar;
var $comments_char_limt = 70;
var $error_font_color = "#A00000";
var $login_fields = Array();
var $logged_in = false;
var $_post_condition_upc = false;
var $jurisdiction_id = false;
//
// Dir to store cookies
//
var $cookie_dir = "/tmp/"; // With ending slash
//-------------------------------------------------------------------------------
// Constructor
//-------------------------------------------------------------------------------
function amazon_sell() {
//
// Create our cookie jar
//
$this->_cookie_jar = $cookie_dir.uniqid("AMAZONCOOKIE");
//
// Try to login now
//
$this->_amazon_start_session();
}
//-------------------------------------------------------------------------------
// post_item()
//-------------------------------------------------------------------------------
function post_item() {
if (!$this->validate_price()) {
return (false);
}
if (!$this->_amazon_post_information()) {
return (false);
}
//
// Now that we posted information, we can log and post the item!
//
if (!$this->_amazon_post_item()) {
return (false);
}
return (true);
}
//-------------------------------------------------------------------------------
// remove_item()
//-------------------------------------------------------------------------------
function remove_item() {
if (!$this->exchange_id) {
$this->setError("Cannot Remove Item because Exchange ID is Empty.");
return (false);
}
if (!$this->_amazon_login()) {
return (false);
}
if (!$this->_amazon_post_removal()) {
return (false);
}
return (true);
}
//-------------------------------------------------------------------------------
// Accessors
//-------------------------------------------------------------------------------
function getCommission() { return ($this->commission); }
function getCondition() { return ($this->condition); }
function getConditionInput() { return ($this->getConditionMainType()."-".$this->getConditionSubType()); }
function getEndDate() { return ($this->end_date); }
function getZShopId() { return ($this->zshop_id); }
function getExchangeId() { return ($this->exchange_id); }
function getRemoveReason() { return ($this->remove_reason); }
function willShipIntl() { return ($this->shipping_intl ? true : false); }
function willShipPriority() { return ($this->shipping_prir ? true : false); }
function getConditionMainType() {
if ($this->condition < 200) {
$ret = "new";
} elseif ($this->condition < 300) {
$ret = "used";
} elseif ($this->condition < 400) {
$ret = "collectible";
} else {
$ret = false;
}
return ($ret);
}
function getConditionSubType() {
$sub = $this->condition % 100;
switch ($sub) {
case (0): $ret = "new";
break;
case (10): $ret = "mint";
break;
case (20): $ret = "verygood";
break;
case (30): $ret = "good";
break;
case (40): $ret = "acceptable";
break;
default: $ret = false;
}
return ($ret);
}
//-------------------------------------------------------------------------------
// Mutators
//-------------------------------------------------------------------------------
function setUPC($val) { $this->upc = ereg_replace(" |-", "", $val); }
function setListPrice($val) { $this->price = sprintf("%.2f", $val); }
function setCondition($val) { $this->condition = $val; }
function setComments($val) { $this->comments = $val; }
function setPostalCode($val) { $this->postal_code = $val; }
function setLoginEmail($val) { $this->login_email = $val; }
function setLoginPassword($val) { $this->login_pass = $val; }
function setZShopId($val) { $this->zshop_id = $val; }
function setExchangeId($val) { $this->exchange_id = $val; }
function setRemoveReason($val) { $this->remove_reason = $val; }
function setShipIntnl($val) { $this->shipping_intl = $val; }
function setShipPriority($val) { $this->shipping_prir = $val; }
//-------------------------------------------------------------------------------
// Price Change Behavior
// This will alter what the behavior is when the price you give is not acceptable
// by Amazon. It helps to go through the listing process manually to see
// how this all works
//-------------------------------------------------------------------------------
function setPriceToMax() {
$this->lower_price_to_max = true;
$this->lower_price_to_min = false;
$this->lower_price_to_recommended = false;
$this->lower_price_to_average = false;
}
function setPriceToMin() {
$this->lower_price_to_max = false;
$this->lower_price_to_min = true;
$this->lower_price_to_recommended = false;
$this->lower_price_to_average = false;
}
function setPriceToRecommended() {
$this->lower_price_to_max = false;
$this->lower_price_to_min = false;
$this->lower_price_to_recommended = true;
$this->lower_price_to_average = false;
}
function setPriceToAverage() {
$this->lower_price_to_max = false;
$this->lower_price_to_min = false;
$this->lower_price_to_recommended = false;
$this->lower_price_to_average = true;
}
function disableSetPrice() {
$this->lower_price_to_max = false;
$this->lower_price_to_min = false;
$this->lower_price_to_recommended = false;
$this->lower_price_to_average = false;
}
//-------------------------------------------------------------------------------
// Errors
//-------------------------------------------------------------------------------
function getError() { return ($this->error); }
function setError($val) { $this->error = $val; }
//-------------------------------------------------------------------------------
// validate_price()
//
// Description: Makes sure the price they're trying to sell at is less then
// the maximum price Amazon will allow
//-------------------------------------------------------------------------------
function validate_price() {
if (!$this->price) {
$this->setError("List Price is Empty.");
return (false);
}
if (!$this->price_max) {
if (!$this->_amazon_post_condition()) {
return (false);
}
}
//
// Check if the price needs to be under a max price or over a min price
//
if (!empty($this->price_max)) {
if ($this->price > $this->price_max) {
//
// Lower it to the max price
//
if ($this->lower_price_to_max) {
if (empty($this->price_max)) {
$this->setError("Tried to set list price to max price but max price was empty.");
return (false);
}
$this->price = $this->price_max;
//
// Lower it to the recommended price
//
} elseif ($this->lower_price_to_recommended) {
if (empty($this->price_recommended)) {
$this->setError("Tried to set list price to recommended but recommended price was empty.");
return (false);
}
$this->price = $this->price_recommended;
//
// Lower it to the average price
//
} elseif ($this->lower_price_to_average) {
if (empty($this->price_average)) {
$this->setError("Tried to set list price to average price but average price was empty.");
return (false);
}
$this->price = $this->price_average;
//
// They didn't want to sell it for lower, so error
//
} else {
$this->setError("Your list price (\$".sprintf("%.2f", $this->price).") ".
"is greater then Amazon's max price (\$$this->price_max)");
return (false);
}
} // OVER MAX
//
// Check if they are under the min
//
} elseif (!empty($this->price_min)) {
if ($this->price < $this->price_min) {
//
// Raise it to the min price
//
if ($this->lower_price_to_min) {
if (empty($this->price_min)) {
$this->setError("Tried to set list price to min price but min price was empty.");
return (false);
}
$this->price = $this->price_min;
//
// Raise it to the recommended price
//
} elseif ($this->lower_price_to_recommended) {
if (empty($this->price_recommended)) {
$this->setError("Tried to set list price to recommended but recommended price was empty.");
return (false);
}
$this->price = $this->price_recommended;
//
// Raise it to the average price
//
} elseif ($this->lower_price_to_average) {
if (empty($this->price_average)) {
$this->setError("Tried to set list price to average price but average price was empty.");
return (false);
}
$this->price = $this->price_average;
//
// They didn't want to sell it for higher, so error
//
} else {
$this->setError("Your list price (\$".sprintf("%.2f", $this->price).") ".
"is less then Amazon's min price (\$$this->price_min)");
return (false);
}
} // UNDER MIN
}
return (true);
}
//-------------------------------------------------------------------------------
// _amazon_login()
//
// Description: We'll try to login into the Amazon system so we can start the
// selling process
//-------------------------------------------------------------------------------
function _amazon_login() {
if ($this->logged_in) return (true);
if (!$this->session_id) $this->_amazon_start_session();
foreach ($this->login_fields AS $key => $val) {
$post_fields .= "$key=$val&";
}
$post_fields .= "input-login-email=$this->login_email&".
"input-login-customer=existing&".
"password=$this->login_pass";
if (!$result = $this->_post_form($this->_login_post, $post_fields)) {
$this->setError("No Response From Amazon After We Tried to Login.");
return (false);
}
//
// Check for errors
//
$temp = $this->_trim_array(explode("\n", strip_tags($result, "<input><font><form>")));
$count = count($temp);
$cur_error = false;
$this->login_fields = Array();
for ($ctr = 0; $ctr < $count; $ctr++) {
//
// See if we found an error Errors (all error message will be wrapped with a red font
//
if (stristr($temp[$ctr], $this->error_font_color)) {
$cur_error .= trim(strip_tags($temp[$ctr]));
}
} // END FOR LOOP
//
// Check if we bombed somehow
//
if ($cur_error) {
$this->setError($cur_error);
return (false);
}
$this->logged_in = true;
return ($result);
}
//-------------------------------------------------------------------------------
// _amazon_post_removal()
//
// Description: Fuck Amazon. I hate it
//-------------------------------------------------------------------------------
function _amazon_post_removal() {
$post_fields = "selling-exchange-id=$this->exchange_id&".
"cancel-reason=$this->remove_reason";
if (!$result = $this->_post_form($this->_remove_post, $post_fields)) {
$this->setError("Could not post form to remove item.");
return (false);
}
//
// Check for errors
//
$temp = $this->_trim_array(explode("\n", strip_tags($result, "<font>")));
$count = count($temp);
$cur_error = false;
$this->login_fields = Array();
for ($ctr = 0; $ctr < $count; $ctr++) {
//
// See if we found an error Errors (all error message will be wrapped with a red font
// We want the 2nd error
//
if (stristr($temp[$ctr], $this->error_font_color)) {
$cur_error = trim(strip_tags($temp[$ctr]));
}
} // END FOR LOOP
//
// Check if we bombed somehow
//
if ($cur_error) {
$this->setError($cur_error);
return (false);
}
return (true);
}
//-------------------------------------------------------------------------------
// _amazon_post_condition()
//
// Description: We can now post to them what the condition is of the item
//-------------------------------------------------------------------------------
function _amazon_post_condition() {
//
// Check if we already went through this form for this upc
//
if (($this->upc == $this->_post_condition_upc) &&
$this->_post_condition_upc) return (true);
if (!$this->session_id) $this->_amazon_start_session();
if (!$this->upc) {
$this->setError("UPC number is empty.");
return (false);
}
if (!$this->condition) {
$this->setError("Condition is empty.");
return (false);
}
$post_fields = "sdp-sai-asin=$this->upc&".
"sdp-sai-condition-type=".$this->getConditionInput();
if (!$result = $this->_post_form($this->_condt_post, $post_fields)) {
$this->setError("No Response From Amazon After We Submitted Condition Information.");
return (false);
}
//
// We now take our result and get information about the product we're trying to list
//
$temp = $this->_trim_array(explode("\n", strip_tags($result, "<input>")));
$count = count($temp);
for ($ctr = 0; $ctr < $count; $ctr++) {
//
// Maxium Price
//
if (stristr($temp[$ctr], "Maximum allowable price")) {
$ctr++;
$this->price_max = trim(str_replace("\$", "", $temp[$ctr]));
//
// Manimum Price
//
} elseif (stristr($temp[$ctr], "Minimum allowable price")) {
$ctr++;
$this->price_min = trim(str_replace("\$", "", $temp[$ctr]));
//
// Recommended Price
//
} elseif (stristr($temp[$ctr], "Recommended price")) {
$ctr++;
$this->price_recommended = trim(str_replace("\$", "", $temp[$ctr]));
//
// Average Price
//
} elseif (stristr($temp[$ctr], "Average sales price")) {
$ctr++;
$this->price_average = strtok(trim(str_replace("\$", "", $temp[$ctr])), " ");
//
// Standard Shipping Credit
//
} elseif (stristr($temp[$ctr], "Standard Shipping:")) {
$ctr += 2;
$this->shipping_stnd_credit = trim(str_replace("(\$", "", $temp[$ctr]));
//
// International Shipping Credit
//
} elseif (stristr($temp[$ctr], "International Shipping:")) {
$ctr++;
$this->shipping_intl_credit = trim(str_replace("(\$", "", $temp[$ctr]));
//
// Priority Shipping Credit
//
} elseif (stristr($temp[$ctr], "Expedited Shipping:")) {
$ctr++;
$this->shipping_prir_credit = trim(str_replace("(\$", "", $temp[$ctr]));
//
// We specifically need to store the jurisdiction id
//
} elseif (strstr($temp[$ctr], "jurisdiction")) {
if (eregi("<input type=\"hidden\" name=\"selling-jurisdiction-id\" value=(.*)>", $temp[$ctr], $args)) {
$this->jurisdiction_id = $args[1];
}
} // else echo $temp[$ctr]."\n";
} // END FOR LOOP
//
// Set this var so this function is called again we don't have to go through it all again
//
$this->_post_condition_upc = $this->upc;
return (true);
}
//-------------------------------------------------------------------------------
// _amazon_post_information()
//
// Description: So let's now post information like the price, condition, location
// and shipping options
//-------------------------------------------------------------------------------
function _amazon_post_information() {
if (!$this->postal_code) {
$this->setError("Postal Code is Empty.");
return (false);
}
if (!$this->price) {
$this->setError("List Price is Empty. ($this->price)");
return (false);
}
$post_fields = "sdp-sai-asin=$this->upc&".
"sdp-sai-condition-type=".$this->getConditionInput()."&".
"sdp-sai-condition-comments=".urlencode($this->comments)."&".
"selling-asking-price=$this->price&".
"selling-location-postal-code=$this->postal_code".
($this->willShipIntl() ? "&selling-shipping=will-ship-intl" : "").
($this->willShipPriority() ? "&selling-priority-shipping=Y" : "");
if (!$result = $this->_post_form($this->_info_post, $post_fields)) {
$this->setError("No Reponse From Amazon After We Posted Item Information");
return (false);
}
//
// Grab all the hidden fields we need to login now, or check for errors;
//
$temp = $this->_trim_array(explode("\n", strip_tags($result, "<input><font><form>")));
$count = count($temp);
$cur_error = false;
$this->login_fields = Array();
for ($ctr = 0; $ctr < $count; $ctr++) {
//
// So far there's no errors, so collect login hidden fields
//
if (eregi("<input type=hidden name=\"(.*)\" value=\"(.*)\">", $temp[$ctr], $args) && !$cur_error) {
$this->login_fields[$args[1]] = $args[2];
//
// See if we found an error Errors (all error message will be wrapped with a red font
//
} elseif (stristr($temp[$ctr], $this->error_font_color) && stristr($temp[$ctr], "Please enter")) {
$cur_error .= trim(strip_tags($temp[$ctr]));
}
} // END FOR LOOP
//
// Check if we bombed somehow
//
if ($cur_error) {
$this->setError($cur_error);
$this->login_fields = false;
return (false);
}
return (true);
}
//-------------------------------------------------------------------------------
// _amazon_post_item()
//
// Description: This will handle the final page and post the item
//-------------------------------------------------------------------------------
function _amazon_post_item() {
if (!$result = $this->_amazon_login()) {
return (false);
}
if (!$this->jurisdiction_id) {
$this->setError("Jurisdiction ID is Empty.");
return (false);
}
$temp = $this->_trim_array(explode("\n", $result));
$count = count($temp);
$cur_error = false;
$first_form = false;
$this->login_fields = Array();
for ($ctr = 0; $ctr < $count; $ctr++) {
//
// Start grabbing fields after the first </form>
//
if (!$first_form) {
if (stristr($temp[$ctr], "</form>")) {
$first_form = true;
}
} else {
//
// Get hidden fields
//
if (eregi("<input type=\"hidden\" name=\"(.*)\" value=\"(.*)\">", $temp[$ctr], $args)) {
$confirm_fields[$args[1]] = $args[2];
//
// Amazon Sales Commission
//
} elseif (stristr($temp[$ctr], "Amazon commission")) {
$ctr++;
$this->commision = trim(str_replace("\$", "", $temp[$ctr]));
}
}
}
//
// For some reason this field doesn't get passed along and we can't post without it
//
$confirm_fields["selling-jurisdiction-id"] = $this->jurisdiction_id;
$post_fields = "";
foreach ($confirm_fields AS $key => $val) {
$post_fields .= "$key=$val&";
}
if (!$result = $this->_post_form($this->_confirm_post, $post_fields)) {
$this->setError("No Response From Amazon After Item Was Added.");
return (false);
}
//
// Grab Final Information About The Listing
//
$temp = $this->_trim_array(explode("\n", strip_tags($result, "<input><form><a>")));
$count = count($temp);
$zshop_url = false;
for ($ctr = 0; $ctr < $count; $ctr++) {
//
// Get the end date
//
if (stristr($temp[$ctr], "End time")) {
$ctr++;
$temp_end_date = $temp[$ctr];
if (ereg("([0-9]{2})/([0-9]{2})/([0-9]{4}) ([0-9]{2}):([0-9]{2}):([0-9]{2})", $temp[$ctr], $args)) {
$this->end_date = mktime($args[4], $args[5], $args[6], $args[1], $args[2], $args[3]);
}
//
// Or the link that we need to get to grab the zShop Id
// This link will also have the exchange id in it
//
} elseif (stristr($temp[$ctr], "varzea/ts/exchange-glance")) {
$zshop_url = trim(strip_tags($temp[$ctr]))."/$this->session_id";
if (eregi(".*/exchange-glance/(.*)/$this->session_id", $zshop_url, $args)) {
$this->exchange_id = $args[1];
}
}
}
//
// Make sure we have the URL
//
if (!$zshop_url) {
$this->setError("Item has been posted but could not extract zShop URL to collect zShop ID");
return (false);
}
//
// And the Exchange Id
//
if (!$this->exchange_id) {
$this->setError("Item has been posted but could not collect the exchange ID.");
return (false);
}
//
// Now get the Zshop ID
//
if (!$result = $this->_get_page($zshop_url, false)) {
$this->setError("Item has been posted but could not retrieve zShop Product Page.");
return (false);
}
$temp = explode("\n", strip_tags($result));
$count = count($temp);
for ($ctr = 0; $ctr < $count; $ctr++) {
if (stristr($temp[$ctr], "zShops ID")) {
$ctr++;
$this->zshop_id = trim($temp[$ctr]);
}
}
//
// Make sure we have the zShop Id
//
if (!$this->zshop_id) {
$this->setError("Item has been posted but could not collect zShop ID");
return (false);
}
return (true);
}
//-------------------------------------------------------------------------------
// _amazon_start_session()
//
// Description: Goes to the Amazon homepage, which will start the session,
// We'll get the session-id from the Headers, as well store
// cookies they throw at us in the cookie jar
//-------------------------------------------------------------------------------
function _amazon_start_session() {
if (!$result = $this->_get_page($this->_homepage, true)) {
$this->setError("Could not start session with Amazon.");
return (false);
}
//
// Go through the header and get the session-id value
//
$temp = explode("\n", $result);
$count = count($temp);
for ($ctr = 0; $ctr < $count; $ctr++) {
if (ereg(".* session-id=(.*); path", $temp[$ctr], $args)) {
$this->session_id = $args[1];
break;
}
}
return ($this->session_id ? true : false);
}
//-------------------------------------------------------------------------------
// _post_form()
//
// Description: Standard function that allows us to post information to Amazon
// and we simply return the resulting page
//-------------------------------------------------------------------------------
function _post_form($url, $post_fields) {
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url.$this->session_id);
curl_setopt($ch, CURLOPT_COOKIEFILE, $this->_cookie_jar);
curl_setopt($ch, CURLOPT_COOKIEJAR, $this->_cookie_jar);
curl_setopt($ch, CURLOPT_RETURNTRANSFER,1);
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_POSTFIELDS, $post_fields);
$result = curl_exec($ch);
curl_close ($ch);
return ($result);
}
//-------------------------------------------------------------------------------
// _get_page()
//
// Description: Standard function that allows returns the page requested
//-------------------------------------------------------------------------------
function _get_page($url, $get_header = false) {
$header_opt = ($get_header ? 1 : 0);
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER,1);
curl_setopt($ch, CURLOPT_HEADER, $header_opt);
curl_setopt($ch, CURLOPT_COOKIEJAR, $this->_cookie_jar);
$result = curl_exec($ch);
curl_close ($ch);
return ($result);
}
function dump_cookies() {
echo "-------------------\n".
"COOKIES: $this->_cookie_jar\n";
$fp = fopen($this->_cookie_jar, "r");
fpassthru($fp);
fclose($fp);
echo "\n-------------------\n";
return (true);
}
function _trim_array($arr) {
$new_arr = Array();
$count = count($arr);
for ($ctr = 0; $ctr < $count; $ctr++) {
$arr[$ctr] = trim($arr[$ctr]);
if ($arr[$ctr]) {
$new_arr[] = $arr[$ctr];
}
}
return ($new_arr);
}
} // END OF CLASS
?>