Updated 2017 PHP code to automatically bid/buy an eBay auction item

Updated code to automatically bid on an eBay item, I’m currently using it myself if a loop of searched items.

Most of the changes are the query strings which is a lot more involved now. For testing use one cent items with free shipping.

	// MAIN BIDDING FUNCTION MAIN BIDDING FUNCTION
	// this function performs no checking on the input variables
	// $username  -  the eBay user name
	// $password  -  the eBay user password
	// $item      -  the eBay item number to bid on
	// $bid       -  the bid amount in local currency i.e. 5.67
	// $link      -  itemlink with referral, can leave empty i.e. ''
	function place_bid($username, $password, $item, $bid, $link) {

		$cookies = dirname(__FILE__).'/cookies.txt';
		
		//set success as default false
		$success = false;
		$bid_success = false;

		$curl = curl_init();
		curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, false);
		curl_setopt($curl, CURLOPT_USERAGENT, 'Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.4) Gecko/20030624 Netscape/7.1 (ax)');
		curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
		curl_setopt($curl, CURLOPT_FOLLOWLOCATION, true);
		curl_setopt($curl, CURLOPT_REFERER, $link);
		curl_setopt($curl, CURLOPT_COOKIEFILE, $cookies);
		curl_setopt($curl, CURLOPT_COOKIEJAR, $cookies);
		
		//query the sign-out page
		//curl_setopt($curl, CURLOPT_URL, "https://signin.ebay.com/ws/eBayISAPI.dll?SignIn&lgout=1");
		//$ret = curl_exec ($curl);
		
		//query the referal link page
		if ($link) {
			curl_setopt($curl, CURLOPT_URL, $link);
			$ret = curl_exec ($curl);
		}
		
		//IMPORTANT		
		//query the sign-in page to set the cookies
		curl_setopt($curl, CURLOPT_URL, 'https://signin.ebay.com/aw-cgi/eBayISAPI.dll?SignIn&campid=5337161990&customid=7');
		$ret = curl_exec ($curl);
		
		$data = [];
		$numbers = [];
		if (preg_match('%(<form name="SignInForm".*?<\/form>)%im', $ret, $regs)) {

			$dom = new DOMDocument;
			$dom->loadHTML($regs[0]);
			$nodes = $dom->getElementsByTagName('input');
			
			foreach($nodes as $node) {
				$name  = $node->getAttribute('name');
				$value = $node->getAttribute('value');
				//$size  = $node->getAttribute('size');
				$type  = $node->getAttribute('type');
				
				$data[$name] = $value;
				
				if (is_numeric($name)) {
					if ($type == 'text') {
						$data[$name] = $username;
					}
					if ($type == 'password') {
						$data[$name] = $password;
					}
				}
			}
		}
		
		unset($data['']);
		$data_str = http_build_query($data);
		
		//sign-in
		curl_setopt($curl, CURLOPT_URL, "https://signin.ebay.com/ws/eBayISAPI.dll?co_partnerId=2&siteid=0&UsingSSL=1");
		curl_setopt($curl, CURLOPT_CUSTOMREQUEST, 'POST');
		curl_setopt($curl, CURLOPT_POSTFIELDS, $data_str);
		$ret = curl_exec ($curl);
		
		if(curl_errno($curl)){
			ebaylog('Curl error: ' . curl_error($curl));
		}
		if (!$ret) {
			$ret = curl_exec ($curl);
			if(curl_errno($curl)){
				ebaylog('Curl error: ' . curl_error($curl));
			}
			if (!$ret) {
				$ret = curl_exec ($curl);
				if(curl_errno($curl)){
					ebaylog('Curl error: ' . curl_error($curl));
				}
			}
		}
		
		curl_setopt($curl, CURLOPT_URL, 'https://www.ebay.com/myb/WatchList');
		$ret = curl_exec ($curl);
		
		//test_write($ret);
		
		if(curl_errno($curl)){
			ebaylog('Curl error: ' . curl_error($curl));
		}
		if (!$ret) {
			$ret = curl_exec ($curl);
			if(curl_errno($curl)){
				ebaylog('Curl error: ' . curl_error($curl));
			}
			if (!$ret) {
				$ret = curl_exec ($curl);
				if(curl_errno($curl)){
					ebaylog('Curl error: ' . curl_error($curl));
				}
			}
		}

		
		
		//if (strpos($ret, '"loggedIn":true') === FALSE) {
		if ((strpos($ret, "userid={$username}") === FALSE) && (strpos($ret, "usr/{$username}") === FALSE)) {
			if (preg_match('%<b class="altTitle">(.*)</b>%', $ret, $regs)) {
				$err = $regs[1];
				ebaylog("\"{$err}\"");
				if (strpos($err, 'The alerts below') === 0) {
					ebaylog("{$item}: 'The alerts below' found, successful");
					//set it to succes
				}
			} else {
				ebaylog("{$item}: Failed signing in");
				if (preg_match('%<font face=".*?" size="3"><b>(.*?)</b></font>%', $ret, $regs)) {
					$err = $regs[1];
					ebaylog("\"{$err}\"");
				}
				
				//test_write($ret);
				goto end;
			}
			
			
		} else {
			ebaylog("{$item}: Success signing in");
		}
		
		
		//place the inital bid
		curl_setopt($curl, CURLOPT_URL, "https://offer.ebay.com/ws/eBayISAPI.dll?MakeBid&item={$item}&maxbid={$bid}&campid=5337161990&customid=7");
		$ret = curl_exec ($curl);
		if(curl_errno($curl)){
			ebaylog('Curl error: ' . curl_error($curl));
		}
		if (!$ret) {
			$ret = curl_exec ($curl);
		}

		if (preg_match_all('/(?:value="([-0-9a-zA-Z]*)" *)?name="stok"(?: *value="([-0-9a-zA-Z]*)")?/', $ret, $regs)) {
			$stok = $regs[1][0];
		} else {
			//Failed to get 'stok' value
			//try and determine why
			if (preg_match('%<div class="statusDiv">(.*?)</div>%', $ret, $regs)) {
				$err = $regs[1];
				ebaylog("'{$err}'");
				//if string starts with "Enter US $0.41 or more"
				if (stripos($err, 'Enter') === 0) {
					ebaylog("{$item}: 'Enter' found, aborting");
					//set it to success
					$success = true;
				} else if (stripos($err, 'To enter a') === 0) {
					ebaylog("{$item}: 'To enter a' found, aborting");
					//set it to success
					$success = true;
				} else if (stripos($err, 'Transaction Blocked') === 0) {
					ebaylog("{$item}: 'Transaction Blocked' found, aborting");
					//set it to success
					$success = true;
				}
				
			} else if (preg_match('%"\d*" - Invalid Item</div>%', $subject)) {
				ebaylog("{$item}: 'Invalid Item' found, aborting");
				test_write($ret);
				//set it to success
				$success = true;
			} else if (preg_match('%<div class="subTlt"><ul class="errList"><li>(.*?)</li></ul></div>%', $subject)) {
				ebaylog("{$item}: 'no longer available' found, aborting");
				test_write($ret);
				//set it to success
				$success = true;
			} else if (preg_match('%id="w\d-\d-_msg".*?>(.*?)</span>%', $ret, $regs)) {
				ebaylog("'{$regs[1]}'");
			} else if (preg_match('%<div\s+class\s*=\s*"(?:errRed|errBlk|errTitle|statusDiv)"\s*>(.*?)</div>%i', $ret, $regs)) {
				ebaylog("'{$regs[1]}'");
			} else {
				//don't know why so log the page
				ebaylog("{$item}: Failed to get 'stok' value");
				test_write($ret);
			}
			goto end;
		}
		
		if (preg_match_all('/(?:value="([-0-9a-zA-Z]*)" *)?name="uiid"(?: *value="([-0-9a-zA-Z]*)")?/', $ret, $regs)) {
			$uiid = $regs[1][0];
		} else {
			ebaylog("{$item}: Failed to get 'uiid' value");
			goto end;
		}
		

		if ($stok && $uiid) {
			ebaylog("{$item}: Success placing initial bid");
		} else {
			ebaylog("{$item}: Failed placing initial bid");
			goto end;
			
		}
		
		//confirm the bid
		curl_setopt($curl, CURLOPT_URL, "https://offer.ebay.com/ws/eBayISAPI.dll?MfcISAPICommand=MakeBid&maxbid={$bid}&quant=1&mode=1&stok={$stok}&uiid={$uiid}&co_partnerid=2&user={$username}&fb=0&item={$item}&campid=5337161990&customid=7");
		$ret = curl_exec ($curl);
		if(curl_errno($curl)){
			ebaylog('Curl error: ' . curl_error($curl));
		}
		if (!$ret) {
			$ret = curl_exec ($curl);
		}
		
		//perform a number of tests to determine if the bid was a success
		$bid_success = true;
		if (stripos($ret, "you're the first bidder") === FALSE) {
			if (stripos($ret, "you're the high bidder and currently in the lead") === FALSE) {
				if (stripos($ret, "you're currently the highest bidder") === FALSE) {
					$bid_success  = false;
					ebaylog("{$item}: Failed placing final bid");
					//try and determine why
					if (preg_match('%<div\s+class\s*=\s*"(?:errRed|errBlk|errTitle|statusDiv|title)"\s*>(.*?)</div>%i', $ret, $regs)) {
						$err = $regs[1];
						ebaylog("'{$err}'");
						if (stripos($err, 'Enter') === 0) {
							ebaylog("{$item}: 'Enter' found, aborting");
							//set it to success
							$bid_success = true;
						} else if (stripos($err, "You've just been outbid") === 0) {
							ebaylog("{$item}: 'You've just been outbid' found, aborting");
							//set it to success
							$bid_success  = true;
						} else if (stripos($err, "You're currently the high bidder,") === 0) {
							ebaylog("{$item}: 'You're currently the high bidder, but the reserve hasn't been met.' found, aborting");
							//set it to success
							$bid_success  = true;
						}
					} else {
						//we don't know why it failed so write the data
						test_write($ret);
					}
				}
			}
		}
		
		if ($bid_success) {
			ebaylog("{$item}: Success placing final bid");
			$success = true;
		}
		
		end:
		
		//close the curl session
		curl_close ($curl);
		
		if ($success) {
			ebaylog("{$item}: Success: {$username}");
		} else {
			ebaylog("{$item}: Failure: {$username}");
		}
		
		return $success;
	}
	
	//for testing
	function test_write($out) {
		$fh = fopen(dirname(__FILE__).'/'.date('Y-m-d H-i-s').'.html', 'w');
		fwrite($fh, $out);
		fclose($fh);
	}

	//simple logging function
	function ebaylog($msg) {
		$msg = "{$msg}\r\n";
		echo $msg;
		$fh = fopen(dirname(__FILE__).'/ebay-log.txt', 'a');
		fwrite($fh, date('Y-m-d H-i-s')." {$msg}");
		fclose($fh);
	}

Convert Drafix (QuickCAD) CAD file to DWG

Recently I had to convert a CAD file to DWG for a surveyor. I opened the CAD file up in a text editor and the third line read ‘Drafix Windows CAD’. I searched the web for the Drafix software and everyone had the same problem. Drafix CAD was no longer able to be purchased or downloaded from anywhere.

Further reading online, I found that Autodesk AutoSketch may be able to read these CAD files, so I borrowed a copy from my friend and who had AutoSketch 9. It managed to install successfully on my Windows 7 x64 machine, but I had problems running it. I used the inbuilt Windows Program Compatibility tool (search ‘compatibility’ in the start menu). I ran the tool and pointed it to the AutoSketch 9 install. Amazing it worked and I managed to read my CAD file perfectly. I then saved it to various different formats.

Is Principle and Interest (P&I) or Interest Only (IO) better on my investment loan?

Mortgages and interest rates, they are extremely confusing. Here is a recent problem I had, should I go Principle and Interest (P&I) or  Interest Only (IO) on an investment loan. Initially, these seams an obvious choice, go the IO and deposit the saved principle payments into your owner occupied offset, as you are unable to claim the interest at tax time. But this gets a bit more complicated when the P&I interest rate is slightly lower.

Here is how to work it out.

Lets assume your Owner Occupied rate is 4%, IO investment is 5% and P&I investment is 4.8% (0.2% discount). Loan amount is $500,000, payment over 30 years.

To work out the principle payments each month the Excel formula PMT can be used.

=PMT(4.8%/12, 30*12, 500000)

Which results in monthly payments of $2,623 or yearly payments of $31,480. This is the amount that won’t be able to offset the Owner Occupied at 4%, this is equal to $1,259 a year.

If the P&I and IO rates were the same, we wouldn’t want this loss and stick to the IO, but it isn’t the case. at 4.8% interest first year is $16,800, whilst IO at 5% is $17,500, a difference of $700. 

In this case, P&I costs $559 more a year, and it would be better to go IO, even at a slightly higher rate. Simply, right? Well, not quite.

As investment loans are tax deductible, comparing the interest only isn’t a fair comparison. In a situation where P&I is more cost effective then IO initially, it is worth then calculate the interest payable after factoring the tax deduction. It may make the IO more favourable. But if it does, the savings differences may be negligible compared to other factors.

CloudSight API PHP example

Here is an example PHP function for the CloudSight API, given there are not many examples online.

Simply input your API key and the url which could be either a local or internet file, the function will return the string description of the image.

	function cloudsightapi($key, $file_url) {
		
		$parse = parse_url($file_url);
		
		$size = getimagesize($file_url);
		$boundary = md5(time());
		
		$ch = curl_init();
		curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
		curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
		curl_setopt($ch, CURLOPT_URL, "https://api.cloudsightapi.com/image_requests");
		
		if (isset($parse['host'])) {
			$headers = array('Authorization: CloudSight '.$key, "Content-Type:multipart/form-data");
			
			$postFields = array(
				'image_request' => array(
					'remote_image_url'  => $file_url,
					'locale' => 'en-US'
				)
			);
			
			$body = http_build_query($postFields);
		
		} else {
			$headers = array('Authorization: CloudSight '.$key, "Content-Type:multipart/form-data; boundary=".$boundary);
			
			$body  = '';
			$body .= '--'.$boundary."\r\n";
			$body .= 'Content-Disposition: form-data; name="image_request[locale]"'."\r\n\r\n";
			$body .= "en-US"."\r\n";
			$body .= '--'.$boundary."\r\n";
			$body .= 'Content-Disposition: form-data; name="image_request[image]"; filename="'.basename($file_url).'"'."\r\n";
			$body .= 'Content-Type: '.$size['mime']."\r\n";
			$body .= 'Content-Transfer-Encoding: multipart/form-data'."\r\n\r\n";
			$body .= file_get_contents($file_url)."\r\n";
			$body .= '--'.$boundary .'--'."\r\n\r\n";
			
		}
		
		curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
		curl_setopt($ch, CURLOPT_POST, true);
		curl_setopt($ch, CURLOPT_POSTFIELDS, $body);

		$ret = curl_exec($ch);
		$json = json_decode($ret, true);
		
		$token = $json['token'];
		$status = $json['status'];
		
		while ($status == 'not completed') {
			
			//grab the result
			curl_setopt($ch, CURLOPT_POST, false);
			curl_setopt($ch, CURLOPT_POSTFIELDS, null);
			curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'GET');
			curl_setopt($ch, CURLOPT_URL, 'https://api.cloudsightapi.com/image_responses/'.$token);
			$ret = curl_exec($ch);
			
			$json = json_decode($ret, true);
			
			$token = $json['token'];
			$status = $json['status'];
			
			//print_R($json);
			
			sleep(1);
		}
			
		$label = $json['name'];
		
		curl_close($ch);
		
		return $label;
	
	}

Automatically reboot a TP-LINK TD-W8960N Modem through PHP script

I recently got a bit fed up of the ADSL2+ speeds I was getting and constant line resyncing. I thought I would set up a script to automatically reboot the modem when sleeping.

It turns out that previously it was very simply to reboot TP-LINK modems, but it has got a lot more difficult recently. This page, which I initially found through googling, lead me on a wild goose chase more then anything else. It turns out it was better to start from scratch, with the comments helping me to work out the username/password hashing.

One of the advantages with my script below, is I also capture the sync speeds, and you could use that to determine if the modem should be rebooted.

Naturally in my goto PHP language. Code below, simply modify username, password and modem IP.

	$username = 'admin';
	$password = 'XXXXXX';
	$ip = '192.168.1.1';

	// code below
	$ip = "http://{$ip}/";
	
	$auth_enc =  base64_encode($username.':'.$password);
	
	date_default_timezone_set('Australia/Perth');
	$cookies = dirname(__FILE__).'/cookies-tplink.txt';
	
	//delete the existing cookie file, important
	unlink($cookies);
	
	$ch = curl_init();
	curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
	curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
	curl_setopt($ch, CURLOPT_COOKIEFILE, $cookies);
	curl_setopt($ch, CURLOPT_COOKIEJAR, $cookies);
	curl_setopt($ch, CURLOPT_COOKIE, 'Authorization=Basic '.$auth_enc.';path=/');
	curl_setopt($ch, CURLOPT_REFERER, $ip);
	curl_setopt($ch, CURLOPT_URL, $ip);
	curl_setopt($ch, CURLOPT_HTTPAUTH, CURLAUTH_BASIC);
	$output = curl_exec($ch);
	
	//grab the connection information
	curl_setopt($ch, CURLOPT_URL, $ip.'info.html');
	$output = curl_exec($ch);

	preg_match_all('%<td class=\\\\"dataStyle\\\\">(\d*?)</td>%im', $output, $result, PREG_PATTERN_ORDER);
	$Upstream = $result[1][0];
	$Downstream = $result[1][1];
	var_dump($Upstream);
	var_dump($Downstream);
	
	//grab session key from reboot router page
	curl_setopt($ch, CURLOPT_URL, $ip.'resetrouter.html');
	$output = curl_exec($ch);
	
	if (preg_match('/var sessionKey=\'(.*?)\';/im', $output, $regs)) {
		$sessionKey = $regs[1];
	}
	var_dump($sessionKey);
	
	//reboot the modem
	if ($sessionKey && false) {
		curl_setopt($ch, CURLOPT_URL, $ip.'rebootinfo.cgi?sessionKey='.$sessionKey);
		$output = curl_exec($ch);
		echo "Modem has been rebooted\r\n";
	}
	
	curl_close($ch);

What are my consumer rights if a price decreases? (Australia)

I thought I would answer a question that I had recently, where I purchased and paid for a product, and then only a week later the product went on sale for lower. Unfortunately, there are no statutory consumer rights if the price decreases, unlike those for manufactures warranty, acceptable quality and fit for purpose. But thankfully, a lot of stores have very favourable return policies.

Many stores allow you to return a product if you simply change your mind, for example Ikea (WA) has a 90 day return policy, Super Amart a 30 day return policy, Big W a 30 day return policy on non-electrical items, Officeworks and Bunnings don’t have any time-limit on their returns. These are only a few examples. Now, generally, if stores offer these return policies, they generally understand that if the price decreases within this period, you should be entitled to a refund in the difference in price.

The reason for this is there is nothing stopping you from buying the product at the discounted price and then returning it on the older receipt with the higher price. The stores would probably prefer this as it means they get a returned product in original packaging.

For my recent transaction, after the store said they could not do anything about the price reduction, only when I explained I wanted to return the item and buy it at the lower price, they got the picture and put through a refund of the price difference.

 

How to pass the PMI Project Management Professional Certification PMP exam

Having recently passed my PMI PMP exam on the first try, I thought I would share my thoughts on how to also pass the PMP exam.

The resources

The resources I used were quite limited.

  • PMBOK – I read through once very early on when I was completing the 36 hours of coursework and never used it again.
  • PMP Exam Prep by Rita Mulcahy, was a key resource, and I’ll explain more on that shortly.
  • The PMP Exam: How to Pass on Your First Try by Andy Crowe, another key resource and very easy to read.
  • Head First PMP, Book by Andrew Stellman, an online recommendation with the other two resources, but I didn’t like the graphic format and didn’t get through the first chapter.
  • PMI PMP Exam Prep by Pocket Prep, Inc. android app, I used this more as a motivational tool and training reminders.

The questions

The PMP questions are all situational, and in my opinion the practise questions in the above resources a lot easier.

  • Plenty of network diagrams which were easy marks
  • Plenty of basic Earned Value questions, like given PV, EV and AC, what is the status of schedule and budget.
  • No ethics questions.
  • A lot of change control management questions.

The learning

Instead of memorising the process group and knowledge area map, I should have been memorising Rita Mulcahy’s process diagram. These would have helped significantly in the situation, especially for the planning domain which I was Moderately Proficient.

Airbnb coupon code new signup $50 AUD with referral

Here is an Airbnb coupon code, get $50 AUD when you take a first trip of $100 AUD or more using out referral link below:

www.airbnb.com/c/shydzik

You can also get $100 AUD when you welcome your first guest as a host.