PHP Paypal IPN Script

Posted 29 Jan 2010 — by admin
Category php

Simple script for posting a valid response back to Paypal service after a sale is completed using the Paypal Instant Checkout payment method.

<?php
// read the post from PayPal system and add 'cmd'
$req = 'cmd=_notify-validate';

foreach ($_POST as $key => $value) {
  $value = urlencode(stripslashes($value));
  $req .= "&$key=$value";
}

// post back to PayPal system to validate
$header .= "POST /cgi-bin/webscr HTTP/1.0\r\n";
$header .= "Content-Type: application/x-www-form-urlencoded\r\n";
$header .= "Content-Length: " . strlen($req) . "\r\n\r\n";
$fp = fsockopen ('ssl://www.paypal.com', 443, $errno, $errstr, 30);

// assign posted variables to local variables
$item_name        = $_POST['item_name'];
$item_number      = $_POST['item_number'];
$payment_status   = $_POST['payment_status'];
$payment_amount   = $_POST['mc_gross'];
$payment_currency = $_POST['mc_currency'];
$txn_id           = $_POST['txn_id'];
$receiver_email   = $_POST['receiver_email'];
$payer_email      = $_POST['payer_email'];

if (!$fp) {
// HTTP ERROR
} else {
  fputs ($fp, $header . $req);
  while (!feof($fp)) {
    $res = fgets ($fp, 1024);
    if (strcmp ($res, "VERIFIED") == 0) {
      // check the payment_status is Completed
      // check that txn_id has not been previously processed
      // check that receiver_email is your Primary PayPal email
      // check that payment_amount/payment_currency are correct
      // process payment
    } else if (strcmp ($res, "INVALID") == 0) {
      // log for manual investigation
    }
  }
fclose ($fp);
}

I grabbed this script from Paypal Docs… I never can find the info I need w/in their site so I’m posting here for reference. https://www.paypal.com/us/cgi-bin/webscr?cmd=p/pdn/ipn-codesamples-pop-outside#php

Listing Files and Directories with PHP

Posted 27 Jan 2010 — by admin
Category php

Listing all files and directories using PHP 5.

<?php
$files = array(); $dir = dir(".");
while(false!==($file=$dir->read())):
  if(($file{0}!=".") && ($file{0}!="~") && (substr($file, -3)!="LCK")
    && ($file!=basename($_SERVER["PHP_SELF"]))):
      $files[$file] = stat($file); //
    endif;
endwhile;
$dir->close(); ksort($files); ?>

<table border=1 cellpadding=5>
<tr><th>Name</th><th>Size</th><th>Date</th></tr>
<?php foreach($files as $name => $stats): ?>
  <tr>
    <td><?php print $name;?></td>
    <td><?php print $stats['size']; ?></td>
    <td><?php print date("m-d-Y h:ia", $stats['mtime']); ?></td>
  </tr>
<?php endforeach; ?></table>

Highlight String in PHP

Posted 23 Jan 2010 — by admin
Category php

Function for highlighting text/strings in PHP.

$content = file_get_contents("http://php.net/");

print highlight("PHP", $content);

function highlight($match, $string){
  return str_ireplace($match, "<span style='background:yellow'>$match</span>", $string);
}

Will output something like this

Highlighted PHP.Net

Highlighted PHP.Net

***Notice all the styles are gone :( … would need to parse the document body to maintain stylesheet and other ‘php’ strings that might be in resources paths.

Absolutize Relative Links Using PHP and Preg_Replace_Callback

Posted 13 Jan 2010 — by admin
Category php

I was in the market for a simple php script to replace hrefs with their absolute paths from scraped web pages. I wrote one myself. I used the preg_replace_callback function so that I could pass the parsed results as a single variable.

<?php
$domain = "http://seanbehan.com";
$pattern = "/\bhref=[\"|'](.*?)[\"|']/";
$string = file_get_contents($domain);

// prepends relative links w/ $domain skips returns the match if already absolute
function replace_href($match){
  global $domain;
  if(substr($match[1], 0, 7)!=="http://" && substr($match[1],0,8)!=="https://"){
    return "href='".$domain.$match[1]."'";
  } else {
    return "href='".$match[1]."'s";
  }
}
print preg_replace_callback($pattern, "replace_href", $string);

Hello Rack

Posted 15 Dec 2009 — by admin
Category ruby

What is Rack?

Rack provides a minimal, modular and adaptable interface for developing web applications in Ruby. By wrapping HTTP requests and responses in the simplest way possible, it unifies and distills the API for web servers, web frameworks, and software in between (the so-called middleware) into a single method call.

- Rack API Docs


Create and name your file config.ru If rack isn’t installed get it with this command

gem install rack

In your config.ru file

require 'rubygems'
require 'rack'

class HelloRack
  def call(env)
    [200, {"Content-Type" => "text/html"}, "Hello Rack!"]
  end
end

Rack::Handler::Mongrel.run HelloRack.new, :P ort => 8888

Check out http://m.onkey.org/2008/11/17/ruby-on-rack-1

The survey for people who make websites

Posted 15 Dec 2009 — by admin
Category Web Development

I took the survey!


Click here to take it →

Placing an Authenticity Token in a Rails Form

Posted 14 Dec 2009 — by admin
Category Ruby on Rails
 <%= hidden_field_tag :authenticity_token, form_authenticity_token %>

Managing Timestamps in MySQL with a Trigger

Posted 10 Dec 2009 — by admin
Category Databases

MySQL doesn’t support having two columns with time stamping on both initialization and/or on updating at the same time. It would be nice to be able to do *this* where the created_at column gets the current_timestamp on initialization and the updated_at gets changed on updating the row.

# like so doesn't work...
create table entries(
  body blob,
  created_at datetime default current_timestamp,
  updated_at timestamp default current_timestamp on update current_timestamp
);

Seems like a feature a lot of folks would like. There are two work-arounds. The first is baking it into your application code with something like

create table entries(
  body blob,
  created_at datetime default null,
  updated_at timestamp default current_timestamp on update current_timestamp
);
insert into entries (body, created_at) values ('hello world', now());

The second way is to create a trigger and call the trigger on your insert action on a row.

create table entries (
  body  blob,
  created_at datetime default null,
  updated_at timestamp default null on update current_timestamp
);
create trigger init_created_at before insert on entries for each row set new.created_at = now();

Now whenever a new row is created the trigger will be executed and set the time to the current timestamp. You can forget about the created_at column in your code because it’s not meant to be changed.

Grab a Twitter Status without the Twitter API

Posted 09 Dec 2009 — by admin
Category php

Quick and dirty way to grab the users status messages without having to go through the twitter api (not having to authenticate that is). You can grab the RSS feed and indicate the number of statuses returned with the count param. I wrote this function for my blog in PHP. It uses the curl extension so if it’s not installed type

apt-get install php5-curl

Otherwise you’ll have to use the fsockopen function. Then it’s just a matter of parsing the XML and getting at what data you want. I just want one status so I’m accessing the element directly, rather than looping over the returned data set.

<php
function latest_twitter_status_message(){
        // grab the rss feed link from some user, like me and indicate the count in the url
	$host = "http://twitter.com/statuses/user_timeline/11036982.rss?count=1";
	// using curl
	$ch = curl_init($host);
	curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
	curl_setopt($ch, CURLOPT_HEADER, 0);
	$data = curl_exec($ch);
	curl_close($ch);
	$doc = new SimpleXmlElement($data, LIBXML_NOCDATA);
	return "{$doc->channel->item[0]->description}";
}

Mod_Python and Web.py on Ubuntu

Posted 09 Dec 2009 — by admin
Category Python

Download

First install mod_python for Apache and then restart/reload the server.

apt-get install libapache2-mod-python
/etc/init.d/apache2 force-reload
apache2ctl restart

Next grab the web.py framework from webpy.org. You can grab the tar or use easy_install depending on your setup.

wget http://webpy.org/static/web.py-0.33.tar.gz
tar xzvf web.py.tar.gz
cd web
sudo python setup.py install
# or if you use easy_install
easy_install web.py

Download this file http://www.aminus.net/browser/modpython_gateway.py?rev=106&format=raw This python package can (with this version) go anywhere in your python path “sys.path”. However, I placed it in the wsgiref directory. I’m running python2.6 so I did the following

# after downloading
mv modpython_gateway.py /usr/lib/python2.6/wsgiref/modpython_gateway.py

It’s important to remember that in the VirtualHost file you create the PythonHandler directive will need to reference this module. If you place it outside of the wsgiref directory remember to change the directive as well.

The VirtualHost

Now we need to create a VirtualHost for our application. You can run web.py apps without apache and this is good for development mode. To do this the command is

python pcode.py 4567

where the pcode.py is your web.py application filename and the 4567 is the port number you want to start the server on. I think it defaults to 8080. If you’re running apache or another web server port 80 will be in use. This is where mod_python (or cgi or fastcgi) come into play.

<VirtualHost *>
  ServerName py.seanbehan.com
  DocumentRoot /var/www/python/myapp

   #Aliases can trip you up! Pay attention here
   Alias /myapp /var/www/python/myapp
   <Directory /var/www/python/myapp>
      <IfModule python_module>
        PythonPath "sys.path +['/var/www/python/myapp']"
        AddHandler python-program .py
        # modpython_gateway is a file you'll need to download and place in wsgiref
        PythonHandler wsgiref.modpython_gateway::handler
        # This is your python program
        PythonOption wsgi.application pcode::main
        PythonOption SCRIPT_NAME /myapp
        PythonDebug on
      </IfModule>
    </Directory>
</VirtualHost>

Web.py Application

Web.py applications can be very simple. Everything can be placed in one file. In this example I created a file “pcode.py” and saved it to “/var/www/python/myapp/pcode.py”. The contents look like this

import web #this is the web.py frameword
web.webapi.internalerror = web.debugerror #lets capture errors for debugging

# map paths to classes
urls = (
    "/", "hello"
)

# this is the main from the PythonOption wsgi.application pcode::main from our VirtualHost
main = web.application(urls, globals()).wsgifunc()

class hello:
    def GET(self):
        #  web.header... otherwise you'll be prompted to save the file rather than view it in the browser
        web.header('Content-type','text/html')
        yield "Finally got web.py to work!"

if __name__ == "__main__":
    main.run()

Save the file, reload apache and visit the location on the web (In my case py.seanbehan.com/pcode.py/). Remember to include that last “/” after the pcode.py. You might get a “not found” message from web.py otherwise.

Pretty URLs

You can get pretty urls like “py.seanbehan.com/hello/world” if you use the mod_rewrite apache module.

a2enmod rewrite

You can either set up the rewrite rules in your VirtualHost or in a .htaccess file. I’ll do the .htaccess so I don’t have to reload the server for the changes to take effect.

In the same directory as your pcode.py file create a file “.htaccess” and in it place this code

<IfModule mod_rewrite.c>
  RewriteEngine on
  RewriteBase /
  RewriteCond %{REQUEST_URI} !^/icons
  RewriteCond %{REQUEST_URI} !^/favicon.ico$
  RewriteCond %{REQUEST_URI} !^(/.*)+code.py/
  RewriteRule ^(.*)$ pcode.py/$1 [PT]
</IfModule>

Troubleshooting

I ran into some trouble with the Alias in the VirtualHost file. It looks like this

Alias /myapp /var/www/python/myapp

This will map incoming urls to the full path on the filesystem so that your python program will run properly. I kept getting the not found error message from web.py without it. There might be a better way to set this up but this is how I got it to work.

Here are some additional resources I found helpful
http://wiki.slicehost.com/doku.php?id=install_mod_wsgi_on_ubuntu_gutsy

http://webpy.org/install
http://dready.org/blog/2009/01/29/webpy-with-mod_python-on-apache/
http://www.devisland.net/help/webpy.shtml