Search

Change Language

Sunday, July 17, 2011

Implementing Moneybookers Payment Gateway with PHP

Today we will integrate a Payment gateway in our website. We are going to implement Moneybookers Payment Gateway. Moneybookers provide an easily customizable payment gateway that can be implemented without much headache. You just need to create two accounts on Moneybookers, one for the Merchant and other for the Buyer. Then send a request to Moneybookers to convert these accounts into test accounts (for testing purpose). This is a manual process as Moneybookers provide no sandbox account like PayPal for the developers. After your account has been approved as test account, you can start using it for transactions.
Moneybookers payment gateway gives you two options for the payment, either you can transfer the buyer to Moneybookers payment page or you can embed the iframe into your own page which looks more elegant. Here we will be following the second one i.e the iframe.

Database structure:
Create table 'payment_details' as:
_________________________________________________
CREATE TABLE `payment_status` (
  `order_id` int(11) NOT NULL AUTO_INCREMENT,
  `transaction_id` varchar(255) DEFAULT NULL,
  `amount` float(10,2) DEFAULT NULL,
  `status` int(1) DEFAULT NULL,
  `payment_type` varchar(20) DEFAULT NULL,
  `user_id` int(11) DEFAULT NULL,
  `username` varbinary(255) DEFAULT NULL,
  PRIMARY KEY (`order_id`)
)
_________________________________________________



Create the payment page:
We will include our payment form inthis page using an iframe. This is simple and doesn't need anything special. We will pass the necessary information with the URL of the iframe as:
<iframe src="http://yoursite.com/payment-form?email=<?php echo $email ?>&fname=<?php echo $FirstName ?>&lname=<?php echo $LastName ?>&address=<?php echo $Address ?>&address2=<?php echo $Address2 ?>&city=<?php echo $City ?>&postal_code=<?php echo $PostalCode ?>&country=<?php echo $CountryId ?>&state=<?php echo $State ?>" name="payment" height="600" width="610" border="0">
 </iframe>

Create the payment form:
Payment page starts with a form with a number of hidden fields for the payment process. We will autosubnit this form to proceed to the next step of payment.
<html>
<head>
<title>MoneyBookers by WebSpeaks.in</title>
</head>
<body>
<?php
$email = $_GET['email'];
$fname = $_GET['fname'];
$lname = $_GET['lname'];
$address = $_GET['address'];
$address = $_GET['address'];
$address2 = $_GET['address2'];
$city = $_GET['city'];
$postal_code = $_GET['postal_code'];
$country = $_GET['country'];
$state = $_GET['state'];
 
$price = 10;
?>
<form action="https://www.moneybookers.com/app/payment.pl" target="_self" name="payment_form">
 
 <input type="hidden" name="pay_to_email" value="your_merchant_email"> 
 <input type="hidden" name="pay_from_email" value="<?php echo $email ?>">
 <input type="hidden" name="return_url" value="http://yoursite.com/payment_success.php"> <!-- URL to redirect after payment success -->
 <input type="hidden" name="cancel_url" value="http://yoursite.com/payment_cancel.php">  <!-- URL to redirect after payment cancel -->
 <input type="hidden" name="status_url" value="http://yoursite.com/payment_status.php"> <!-- URL to get the payment response (not visible to user, called on backend) -->
 <input type="hidden" name="language" value="EN"> <!-- Language of payment -->
 
 <input type="hidden" name="hide_login" value="1">  <!-- Whether to show the tiny login form with the payment form, no in our case -->
 
 <!-- Specifies a target in which the return_url value will be called upon successful payment from customer.  -->
 <!-- 1 = '_top', 2 = '_parent', 3 = '_self', 4= '_blank' -->
 <input type="hidden" name="return_url_target" value="1">  
 <input type="hidden" name="cancel_url_target" value="1"> 
 
 <!-- Custom fields for your own needs -->
 <input type="hidden" name="merchant_fields" value="name, username, order_amount, user_id"> <!-- List all your custom fields here (comma separated, max 5)-->
 <input type="hidden" name="name" value="<?php echo $fname. ' '.$lname ?>"> <!-- Value of Custom 'name' -->
 <input type="hidden" name="username" value="<?php echo $username ?>">  <!-- Value of Custom 'username' -->
 <input type="hidden" name="order_amount" value="<?php echo $price ?>"> <!-- Value of Custom 'order_amount' -->
 <input type="hidden" name="user_id" value="<?php echo $user_id ?>">  <!-- Value of Custom 'user_id' -->
 
 <input type="hidden" name="amount_description" value="Testing Amount">  <!-- Description of the amount -->
 <input type="hidden" name="amount" value="<?php echo $price ?>">  <!-- Amount to be charged -->
 <input type="hidden" name="currency" value="GBP">   <!-- Currency of payment -->
 <input type="hidden" name="firstname" value="<?php echo $fname ?>">   <!-- Firstname of buyer, need for autofilling -->
 <input type="hidden" name="lastname" value="<?php echo $lname ?>">    <!-- Lastname of buyer, need for autofilling -->
 <input type="hidden" name="email" value="<?php echo $email ?>">    <!-- Email of buyer, need for autofilling -->
 <input type="hidden" name="address" value="<?php echo $address ?>">     <!-- Address of buyer, need for autofilling -->
 <input type="hidden" name="city" value="<?php echo $city ?>">     <!-- City of buyer, need for autofilling -->
 <input type="hidden" name="state" value="<?php echo $state ?>">     <!-- State of buyer, need for autofilling -->
 <input type="hidden" name="postal_code" value="<?php echo $postal_code ?>">     <!-- Postal_code of buyer, need for autofilling -->
 <input type="hidden" name="country" value="<?php echo $country ?>">     <!-- Country code of buyer, need for autofilling -->
 <input type="hidden" name="detail1_description" value="New Product">      <!-- Description heading of the payyment, shown after payment has been made -->
 <input type="hidden" name="detail1_text" value="<?php echo $product ?>">      <!-- Detailed description of the payment, shown after payment has been made -->
 <input type="hidden" name="confirmation_note" value="Thanks for purchasing Voodoo Video!"> <!-- Confirmation message to be shown after payment has been made --> 
 
 <p>
  <input type="submit" class="submitBtn">

Receive Payment Status:

In the payment form we have specified the 'status_url' field. This field specifies the URL on which the Moneybookers sends the status of the payment. It is URL to which the transaction details will be posted after the payment process is complete. Alternatively, you may specify an email address to which you would like to receive the results. If the status_url is omitted, no transaction details will be sent to the Merchant. 
Detailed status description 
‘2’ Processed – This status is sent when the transaction is processed and the funds have been received on your Moneybookers account. 
‘0’ Pending – This status is sent when the customers pays via the pending bank transfer option. Such transactions will auto-process IF the bank transfer is received by Moneybookers. We strongly recommend that you do NOT process the order/transaction in your system upon receipt of a pending status from Moneybookers. 
‘-1’ Cancelled – Pending transactions can either be cancelled manually by the sender in their online account history or they will auto-cancel after 14 days if still pending. ‘-2’ Failed – This status is sent when the customer tries to pay via Credit Card or Direct debit but our provider declines the transaction. If you do not accept Credit Card or Direct debit payments via Moneybookers (see page 16) then you will never receive the failed status. 
‘-3’ Chargeback – This status could be received only if your account is configured to receive chargebacks. If this is the case, whenever a chargeback is received by Moneybookers, a -3 status will be posted on the status_url for the reversed transaction. 

Create payment_status.php as:

$status = $_POST['status']/*Status of transaction*/
$username = $_POST['username'];/*Custom field*/
$user_id = $_POST['user_id'];/*Custom field*/
$amount = $_POST['amount'];/*Amount of transaction*/
$payment_type = $_POST['payment_type'];/*Type of Payment*/
$mb_transaction_id = $_POST['mb_transaction_id'];/*Moneybookers transaction id*/
 
/*save transaction details in database*/
mysql_query("INSERT INTO `payment_details` (`transaction_id`, `amount`, `status`, `payment_type`, `user_id`, `username`) VALUES ('".$mb_transaction_id."', '".$amount."', '".$status."', '".$payment_type."', '".$user_id."', '".$username."') "

Payment Success Page:
<?php
echo "Your payment has been received. Thanks for purchasing our product.";
?>

Payment Cancel Page:

<?php
echo "Your payment has been cancelled. Please try again.";
?>

Wednesday, June 8, 2011

IPv6 Day: Kicking the tires of a next-gen Net today

The computing industry has begun a major 24-hour test today to work the kinks out of IPv6, a disruptive but necessary overhaul of the Internet's inner workings.
Starting at midnight, Universal Coordinated Time on June 8--or 5 p.m. PT today--dozens of companies lit up servers, Web sites, and network infrastructure that communicate using Internet Protocol version 6. The test, called World IPv6 Day, provides a bit of deadline, albeit one that's more artificial and less pressing than the Y2K bug's January 1, 2000, zero hour.
Unfortunately, the IPv6 test could disrupt the Net for some people who have badly configured hardware or software, with a Web site taking more than two minutes to load instead of a few seconds. Fortunately, though, the problem probably won't affect very many people, and the test will help identify any trouble spots.
Yahoo estimates 0.05 percent of visitors to its Web site will see very slow response when their computers request IPv6 information that can't actually be received. That's a tiny percentage, but multiplied by Yahoo's huge traffic, it's still something like 30,000 to 50,000 people a day, said Adam Bechtel, the vice president for Yahoo's Infrastructure Group, who's overseeing the company's IPv6 transition.
"It is significant. We have been notifying users," for example, by adding a notice on the Yahoo home page to notify users if their network connection may be broken, Bechtel said. "We've had over a million hits to our IPv6 help page."
What will the network look like for those who are affected?
"These users will experience a range of symptoms which could include slow page load times--really slow, like several minutes, not just a little slow," said Owen DeLong, who runs the professional services division at Hurricane Electric, a back-end Internet service provider that has had a concentrated IPv6 program for years. "In fact, the most common characteristic symptom is that a page element will stall for 90 seconds, then load at normal speed at the end of that pause. In some cases, the pause could be as much as three minutes. Other symptoms could include simply being unable to reach certain Web sites and other intermittent connection issues.
"These users should contact their ISP for help in troubleshooting these issues as soon as they notice them," DeLong said. "This will allow the ISPs to identify the problems their customers are having and work on identifying resolutions to those problems before we try this again."
World IPv6 Day began at Google, Facebook, and Yahoo, and since then has spread to many other companies. It's overseen by the Internet Society, a standards and advocacy group.
Though some number of ordinary folk will find out they have a problem with their Net connections, there's a bigger agenda at work here, too: to get sysadmins the world over to make the necessary steps to support IPv6.
World IPv6 Day has been a hard-to-miss warning flag, an occasion where chief information officers might pester the IT staff to get cracking on IPv6 if they haven't already. And for those who have begun, it's an opportunity to find out if operations really are up to snuff.
The amount of Internet traffic going through Hurricane Electric&#39;s IPv6 global backbone soared as World IPv6 Day began.
The amount of Internet traffic going through Hurricane Electric's IPv6 global backbone soared as World IPv6 Day began.
(Credit: Hurricane Electric)
Why bother?
IPv6 has one very compelling advantage over today's standard, IPv4: it accommodates vastly more Internet Protocol addresses--the numbers that are used to label every packet of data that traverses the Internet.
And guess what? The Internet has run out of IPv4 addresses, at the wholesale level at least, meaning that it's getting harder to secure a new address for your new start-up or Web service unless you happen to be one of the lucky few early Internet arrivals that have large tracts of the Internet address space.
As a result of a 1977 decision by Vint Cerf, an Internet guru who now works for Google, IPv4 has 2^32 addresses, or about 4.3 billion. The computing industry has stretched that number through techniques such as network address translation (NAT) that let multiple devices share a single IP address, but that poses network complications, and even with it, Internet service providers and mobile phone operators who have to hand out lots of IP addresses are running out.
IPv6, though, offers 2^128 addresses. If you do the math, that works out to 340,282,366,920,938,463,463,374,607,431,768,211,456, or 340 undecillion for short.
The big problem, though, is that IPv4 and IPv6 networks are incompatible. That means the transition is more complicated than, say, moving from USB 2 to USB 3, where your USB 2 camera plugs into a USB 3 port with no troubles or your USB 3 hard drive still works over a USB 2 connection.
On World IPv6 Day, companies will indicate to the Internet's Domain Name System (DNS) when they have IPv6 servers available. That means IPv6-capable equipment will find and use the servers rather than just sticking with the IPv4 versions.
Exercising this system with real-world traffic should be instructive, said John Curran, chief executive of the American Registry for Internet Numbers (ARIN), a group that doles out IP addresses
"Internet service providers will have the first opportunity to gain insight into potential customer issues via World IPv6 day," Curran said. "World IPv6 Day...provides an important test of IPv6 functionality in the global Internet while also reminding people that we are indeed running out of IPv4 address space."
IPv6 has been around for more than a decade, but without the exhaustion of IPv4 addresses, there wasn't much incentive to add support. Now that's changing.
"In the first quarter alone of 2011, ARIN had already received requests from more than 500 service providers for IPv6 address space," Curran said. "That's greater than 400 or so requests in the entirely of 2009 and suggests that requests for the 2011 year may be three times greater than approximately 700 requests received in the entirely of 2010."
Smooth transition?
The IPv6 transition is complicated, expensive, and drawn-out.
CompTIA, a trade group for information technology professionals, surveyed 400 U.S. IT and business decision-makers about the IPv6 transition. The result: "Just 31 percent of respondents believe the transition to IPv6 will be mostly smooth," the organization said.
Yahoo's been working on its transition for three years already. It concluded that it's impractical to rewrite all its own software to be IPv6-compatible, Bechtel said. For example, software to target ads to particular regions or to prevent site abuse sometimes rely on IPv4 addresses. Instead of rewriting all the code, Yahoo has put a layer of proxy servers in front of its Web site that intercepts traffic and routes it accordingly.
New software from the company includes IPv6 support, but the legacy code base will probably take four years to gradually replace, Bechtel said.
But if you're not in charge of servers and networks, it shouldn't be so rough.
One reason: browser makers have begun to address the matter. For example, Google's Chrome will check both IPv4 and IPv6 connections, then deliver Web pages from whichever produces results fastest. That should help sidestep the super-slow Web page loading time that will afflict misconfigured equipment.
And as the transition spreads from the Internet's core systems to the broadband network gear people have in their homes, the transition should be less disruptive.
"Most users will be unaware that their ISP has switched them over to using IPv6," said Timothy Winters, senior manager for the University of New Hampshire's InterOperability Laboratory, which tests home network equipment for IPv6 support. That equipment, though, is only just beginning to support IPv6 fully, so there's still work to be done.
The tech industry is responding to the challenge the way it knows best: with another logo on the product box. The UNH-IOH is working with another group, the IPv6 Forum, to create an "IPv6 Ready" logo.
A logo won't patch over the difficulties of the transition. But it is a real signal that the industry is coming to terms with the IPv6 shift.

Friday, May 13, 2011

Which Image Format is Best

This was originally posted on YourTotalSite on June 10, 2005
When developing a web site you may not think much about what image format you use but you could end up saving yourself or your organization a chunk of change in bandwidth costs by making your choice more wisely. On the web today there are three main image format types to choose from and all have their advantages and disadvantages. You have a choice of three different compressed image formats: GIF, JPEG or PNG. They each use different techniques to compress the image information.

GIF

GIF uses a lossless compression which means that no quality is lost in the compression. The uncompressed image stores its information in a linear fashion. Each line of pixels is read from left to right. An interlaced GIF file stores the lines of the image in a different order. First lines 4, 8, 12, 16 and 20 may be read in. Then lines 2, 6, 10, 14, and 18 and so on until the entire image is read. When the image is read in this way, a user with a slower internet connection may be able to understand or read the image before it has fully loaded.
The GIF format achieves its compression by removing repeated patterns within the GIF file and storing references to these sections in a list, also known as a hash. Images with horizontal lines of the same color or pattern benefit most from the GIF format. This would include images like background graphics, images with text and patterned images.
Another great advantage is the ability to create animated images. You’ve no doubt seen them throughout the internet. Especially if you were around for the heyday of the 90’s! An animated GIF is essentially a sequence of GIF files with some timing information included. Animated GIFs, however, can run into large file sizes awfully quickly and with very few frames of animation. While it may be a fairly ubiquitous format, if you have to do animation, you may be better off going with Macromedia Flash. If one frame is 15KB then 20 frames could suddenly find you well over 100KB just for one animated image.
Another advantage to GIF files is transparency. A color within the color table can be selected as the transparent color. In doing so, wherever that color occurs, you’ll be able to see through to the HTML background. One of the largest downfalls to the GIF format is its inability to have a color palette of more than 256 colors. This can create poor looking images when used on a photograph which may originally have thousands of different colors.

JPEG

JPEG uses a lossy compression which means that image quality is lost in the process of compressing the image. JPEG compression works by first converting the image from RGB to YUV which stores information about each pixel using brightness, hue and saturation. Then it reduces the amount of information it stores for hue and saturation since differences are less noticeable to the human eye. In trying to decrease the file size of the JPEG (for example, when using the quality slider in Photoshop), you'll tend to notice artifacts occur in flat color areas and especially near edges. As a result, JPEG is best used for images that have more of a variation in colors. For example, images with gradients or photographs can handle a lower quality setting with little noticeable loss in quality. Images with text or large solid backgrounds are best left for GIF or PNG.

PNG

PNG is the relative newcomer to the list of available image formats and it is a formidable one. It is similar to GIF in many ways but even better in others. It is lossless like GIF but supports 24 bit color, unlike GIF which only supports 8. PNG supports alpha transparency, whereas GIF only supports one-color transparency. PNG uses various compression filters to minimize overall image size and can apply different filters on a per-line basis to achieve higher compression. The big attraction to PNGs is its ability to do alpha transparency. Unfortunately, Internet Explorer currently doesn't have full support for it, although there are hacks out there that can pull it off.
If you are not using alpha transparency or do not need more than 256 colors then exporting as an 8-bit PNG is the way to go. On average, 8-bit PNG will be smaller in file size than GIF with absolutely no difference in image quality. PNG and GIF are also very similar in that they both work better with large lines of the same pattern or color. If you do not need alpha transparency but wish to use a color palette greater than 256 colors then you are looking at a 24-bit PNG. It'll be important to test between a 24-bit PNG and JPEG to see which achieves better results. PNG still suffers the same problem as GIF in that they cannot optimize photographs as well as JPEG can.

Is there a winner?

No format is best in all scenarios. Therefore, it's always best to play around with the various formats and compression levels to achieve the best results.
If you'd like to learn more on the history or inner workings of these file formats, be sure to check out the Wikipedia entries on GIF , JPEG , and PNG .

Amazon launches Simple Email Service

Amazon has launched a new API for sending email "in the cloud" called Simple Email Service.
Like other Amazon services, one of the biggest draws—besides using the solid infrastructure—is the pricing. You can send up to 2,000 emails a day absolutely free. After that, you're looking at 10 cents per thousand emails and 15 cents per GB of data transfer.
Some basic list management functionalities such as tracking bouncebacks and marked-as-spam are included but all other list management functionality is not. This is a simple API designed for people who wish to manage the process on their own and would be a great addition to those who are using other Amazon Web Services.
My first question was, "How do they stop spammers?" Amazon scans each email before it goes out and if it has questionable data, they'll stop it from sending. Good to know.

Impact on the market

My next thought was, "What does CampaignMonitor and MailChimp think of this?" To be clear, SES is not a direct competitor to either of these services. CampaignMonitor and MailChimp provide plenty of tools and a great interface for managing email campaigns and lists.
My thought goes in two directions.
One, could or would these services shift any of their infrastructure to take advantage of the SES services. I could foresee an adjusted pricing structure and a spot where I could enter my AWS API key.
The second thought I had is related in that other services could pop up that are full management applications like CampaignMonitor and MailChimp but built on the SES service and possibly providing more cost effective solutions. I would not be surprised to see at least a couple services running within the next six months doing just that.
For more direct competition, you'd need to look at Postmark which, like SES, provides an API for you to integrate email services easily with your web application. That they have API code for a number of languages is already an advantage over Amazon's service.
It'll be interesting to see how the market evolves over the next year.

Friday, April 8, 2011

Showing Product Image on Virtuemart Cart Page


Edit 4 files to show product thumbnails in shopping cart and the checkout process:

1. basket_b2c.html.php
2. ro_basket_b2c.html.php
3. basket.php
4. ro_basket.php

Files 1 & 2 are in:  /components/com_virtuemart/theme/templates/basket
Files 3 & 4 are in: /administrator/components/com_virtuemart/html

basket_b2c.html.php and ro_basket_b2c.html.php are themplates files used to display the chart.

At about line 32, add the following code to the 2 theme files:


Code:

<td><?php echo $product['product_thumb_image'] ?></td>


Then you have to add code to create the field 'product_thumb_image' in the product records.  To do that you must edit basket.php and ro_basket.php and add this code at line 90:

Code:

//prepare thumb image

if( $ps_product->get_field($_SESSION['cart'][$i]["product_id"], "product_thumb_image") ) {
$product_thumb_image = $ps_product->get_field($_SESSION['cart'][$i]["product_id"], "product_thumb_image");
}
else {
$product_thumb_image = 0;
}

if( $product_thumb_image ) {
if( substr( $product_thumb_image, 0, 4) != "http" ) {
if(PSHOP_IMG_RESIZE_ENABLE == '1') {
$product_thumb_image = $mosConfig_live_site."/components/com_virtuemart/show_image_in_imgtag.php?filename=".urlencode($product_thumb_image)."&newxsize=".PSHOP_IMG_WIDTH."&newysize=".PSHOP_IMG_HEIGHT."&fileout=";
}
else {
if( file_exists( IMAGEPATH."product/".$product_thumb_image )) {
$product_thumb_image = IMAGEURL."product/".$product_thumb_image;
}
else {
$product_thumb_image = IMAGEURL.NO_IMAGE;
}
}
}
}
else {
$product_thumb_image = IMAGEURL.NO_IMAGE;
}

$product_rows[$i]['product_thumb_image'] = "<a href=\"$url\">"
. "<img width=100 src= $product_thumb_image />"
. "</a><br />";
//end of prepare thumb image 

Getting Virtuemart Product Attributes Use Radio Buttons

Replace the complete code of the file:
components/com_virtuemart/themes/default/templates/product_details/includes/addtocart_advanced_attribute.tpl.php

with the following:
 

<?php if( !defined( '_VALID_MOS' ) && !defined( '_JEXEC' ) ) die( 'Direct Access to '.basename(__FILE__).' is not allowed.' );

foreach($attributes as $attribute) {      
    ?>
    <div class="vmAttribChildDetail" style="float: left;text-align:right;margin:3px;">
        <label for="<?php echo $attribute['titlevar'] ?>_field"><?php echo $attribute['title'] ?></label>:
    </div>
    <div class="vmAttribChildDetail" style="float: left;text-align:left;margin:3px;">
    <?php
    $chek = 1;
    foreach ( $attribute['options_list'] as $options_item )  { ?>
          <?php if( isset( $options_item['display_price']) ) : ?>
           <input type="radio" style="margin-top: 15px;"
            id="<?php echo $attribute['titlevar'] ?>_field"
            name="<?php echo $attribute['titlevar'].$attribute['product_id'] ?>"
            value="<?php echo $options_item['base_var'] ?>"
            <?php if ($chek==1) { echo " checked"; $chek=0; }; ?>
            >
            <?php echo $options_item['base_value'] ?> (
            <?php echo $options_item['sign'].$options_item['display_price']
            ?>)
          <br />
           <?php else : ?>
           <input type="radio" style="margin-top: 15px;"
            id="<?php echo $attribute['titlevar'] ?>_field"
            name="<?php echo $attribute['titlevar'].$attribute['product_id'] ?>"
            value="<?php echo $options_item['base_var'] ?>"
            <?php if ($chek==1) { echo " checked"; $chek=0; }; ?>
            >
            <?php echo $options_item['base_value']
            ?><br />
           <?php endif; ?>
    <?php } ?>
    </div>
    <br style="clear:both;" />
   
<?php
} ?>



Remember to save a coy of the original code just in case!
 

Showing Attributes in Product Browse page (Virtue Mart)

in home/administrator/components/com_virtuemart/html/shop.browse.php

// Add-to-Cart Button
      if (USE_AS_CATALOGUE != '1' && $product_price != ""
         && !stristr( $product_price, $VM_LANG->_('PHPSHOP_PRODUCT_CALL') )
         && !ps_product::product_has_attributes( $db_browse->f('product_id'), false )
         && $tpl->get_cfg( 'showAddtocartButtonOnProductList' ) ) {

---> Change 'true' by 'false'

home/components/com_virtuemart/themes/default/templates/browse/includes/addtocart_form.tpl.php

<?php if( !defined( '_VALID_MOS' ) && !defined( '_JEXEC' ) ) die( 'Direct Access to '.basename(__FILE__).' is not allowed.' ); [

$button_lbl = $VM_LANG->_('PHPSHOP_CART_ADD_TO');
$button_cls = 'addtocart_button';

require_once(CLASSPATH . 'ps_product_attribute.php' ); //Add this line
$ps_product_attribute = new ps_product_attribute; //Add this one too

if( CHECK_STOCK == '1' && !$product_in_stock ) {
   $button_lbl = $VM_LANG->_('VM_CART_NOTIFY');
   $button_cls = 'notify_button';
}
?>

<form action="<?php echo $mm_action_url ?>index.php" method="post" name="addtocart" id="addtocart<?php echo $i ?>" class="addtocart_form" <?php if( $this->get_cfg( 'useAjaxCartActions', 1 )) { echo 'onsubmit="handleAddToCart( this.id );return false;"'; } ?>>
    <?php echo $ps_product_attribute->list_advanced_attribute($product_id,$product_id); ?><br />
    <?php echo $ps_product_attribute->show_quantity_box($product_id,$product_id); ?><br />
   <input type="submit" class="<?php echo $button_cls ?>" value="<?php echo $button_lbl   ?>" title="<?php echo $button_lbl ?>" />
    <input type="hidden" name="category_id" value="<?php echo  @$_REQUEST['category_id'] ?>" />
    <input type="hidden" name="product_id" value="<?php echo $product_id ?>" />
    <input type="hidden" name="prod_id[]" value="<?php echo $product_id ?>" />
    <input type="hidden" name="page" value="shop.cart" />
    <input type="hidden" name="func" value="cartadd" />
    <input type="hidden" name="Itemid" value="<?php echo $sess->getShopItemid() ?>" />
    <input type="hidden" name="option" value="com_virtuemart" />
    <input type="hidden" name="set_price[]" value="" />
    <input type="hidden" name="adjust_price[]" value="" />
    <input type="hidden" name="master_product[]" value="" />
</form>


Add the two commented lines on line 6 (as shown above) And add this line

<?php echo $ps_product_attribute->list_advanced_attribute($product_id,$product_id); ?><br />
on line 16, just above

<?php echo $ps_product_attribute->show_quantity_box($product_id,$product_id); ?><br /> 

Showing Addtocart in Browsepage (Virtuemart)

In administrator/components/com_virtuemart/html/shop.browse.php, look for these lines (400-404):



// Add-to-Cart Button 
  if (USE_AS_CATALOGUE != '1' && $product_price != "" 
   && !stristr( $product_price, $VM_LANG->_('PHPSHOP_PRODUCT_CALL') )
   && !ps_product::product_has_attributes( $db_browse->f('product_id'), true )
   && $tpl->get_cfg( 'showAddtocartButtonOnProductList' ) ) {

1. Change the second parameter of product_has_attributes() to false:



// Add-to-Cart Button 
  if (USE_AS_CATALOGUE != '1' && $product_price != "" 
   && !stristr( $product_price, $VM_LANG->_('PHPSHOP_PRODUCT_CALL') )
   && !ps_product::product_has_attributes( $db_browse->f('product_id'), false )
   && $tpl->get_cfg( 'showAddtocartButtonOnProductList' ) ) {

(this allows the add-to-cart button on products with only simple attributes).
2. Remove the attribute check completely:


// Add-to-Cart Button 
  if (USE_AS_CATALOGUE != '1' && $product_price != "" 
   && !stristr( $product_price, $VM_LANG->_('PHPSHOP_PRODUCT_CALL') )
   && $tpl->get_cfg( 'showAddtocartButtonOnProductList' ) ) {

This allows the add-to-cart button on everything.

Thursday, March 24, 2011

Distance Finder ( Google Maps API )

Google maps is a free web mapping service application provided by Google. It offers lots of cool features (showing various map types, plotting points, showing routes, geocoding addresses). You can also add all these features to your website using the Google Maps APIs provided by Google. In this tutorial I will show you how to add some of these features to your site.
Download Script



Creating the web form for getting the two addresses

 <body bgcolor="#fff">
    <div id="form" style="width:100%; height:20%">
        <table align="center" valign="center">
            <tr>
                <td colspan="7" align="center"><b>Find the distance between two locations</b></td>
            </tr>
            <tr>
                <td colspan="7">&nbsp;</td>
            </tr>
            <tr>
                <td>First address:</td>
                <td>&nbsp;</td>
                <td><input type="text" name="address1" id="address1" size="50"/></td>
                <td>&nbsp;</td>
                <td>Second address:</td>
                <td>&nbsp;</td>
                <td><input type="text" name="address2" id="address2" size="50"/></td>
            </tr>
            <tr>
                <td colspan="7">&nbsp;</td>
            </tr>
            <tr>
                <td colspan="7" align="center"><input type="button" value="Show" onClick="initialize();"/></td>
            </tr>
        </table>
    </div>
    <center><div style="width:100%; height:10%" id="distance_direct"></div></center>
    <center><div style="width:100%; height:10%" id="distance_road"></div></center>
   
    <center><div id="map_canvas" style="width:70%; height:54%"></div></center>
</body>

Showing the map

<script type="text/javascript" src="http://maps.google.com/maps/api/js?sensor=true"></script>

<script type="text/javascript">

    var location1;
    var location2;
   
    var address1;
    var address2;

    var latlng;
    var geocoder;
    var map;
   
    var distance;
   
    // finds the coordinates for the two locations and calls the showMap() function
    function initialize()
    {
        geocoder = new google.maps.Geocoder(); // creating a new geocode object
       
        // getting the two address values
        address1 = document.getElementById("address1").value;
        address2 = document.getElementById("address2").value;
       
        // finding out the coordinates
        if (geocoder)
        {
            geocoder.geocode( { 'address': address1}, function(results, status)
            {
                if (status == google.maps.GeocoderStatus.OK)
                {
                    //location of first address (latitude + longitude)
                    location1 = results[0].geometry.location;
                } else
                {
                    alert("Geocode was not successful for the following reason: " + status);
                }
            });
            geocoder.geocode( { 'address': address2}, function(results, status)
            {
                if (status == google.maps.GeocoderStatus.OK)
                {
                    //location of second address (latitude + longitude)
                    location2 = results[0].geometry.location;
                    // calling the showMap() function to create and show the map
                    showMap();
                } else
                {
                    alert("Geocode was not successful for the following reason: " + status);
                }
            });
        }
    }
       
    // creates and shows the map
    function showMap()
    {
        // center of the map (compute the mean value between the two locations)
        latlng = new google.maps.LatLng((location1.lat()+location2.lat())/2,(location1.lng()+location2.lng())/2);
       
        // set map options
            // set zoom level
            // set center
            // map type
        var mapOptions =
        {
            zoom: 1,
            center: latlng,
            mapTypeId: google.maps.MapTypeId.HYBRID
        };
       
        // create a new map object
            // set the div id where it will be shown
            // set the map options
        map = new google.maps.Map(document.getElementById("map_canvas"), mapOptions);
       
        // show route between the points
        directionsService = new google.maps.DirectionsService();
        directionsDisplay = new google.maps.DirectionsRenderer(
        {
            suppressMarkers: true,
            suppressInfoWindows: true
        });
        directionsDisplay.setMap(map);
        var request = {
            origin:location1,
            destination:location2,
            travelMode: google.maps.DirectionsTravelMode.DRIVING
        };
        directionsService.route(request, function(response, status)
        {
            if (status == google.maps.DirectionsStatus.OK)
            {
                directionsDisplay.setDirections(response);
                distance = "The distance between the two points on the chosen route is: "+response.routes[0].legs[0].distance.text;
                distance += "<br/>The aproximative driving time is: "+response.routes[0].legs[0].duration.text;
                document.getElementById("distance_road").innerHTML = distance;
            }
        });
       
        // show a line between the two points
        var line = new google.maps.Polyline({
            map: map,
            path: [location1, location2],
            strokeWeight: 7,
            strokeOpacity: 0.8,
            strokeColor: "#FFAA00"
        });
       
        // create the markers for the two locations       
        var marker1 = new google.maps.Marker({
            map: map,
            position: location1,
            title: "First location"
        });
        var marker2 = new google.maps.Marker({
            map: map,
            position: location2,
            title: "Second location"
        });
       
        // create the text to be shown in the infowindows
        var text1 = '<div id="content">'+
                '<h1 id="firstHeading">First location</h1>'+
                '<div id="bodyContent">'+
                '<p>Coordinates: '+location1+'</p>'+
                '<p>Address: '+address1+'</p>'+
                '</div>'+
                '</div>';
               
        var text2 = '<div id="content">'+
            '<h1 id="firstHeading">Second location</h1>'+
            '<div id="bodyContent">'+
            '<p>Coordinates: '+location2+'</p>'+
            '<p>Address: '+address2+'</p>'+
            '</div>'+
            '</div>';
       
        // create info boxes for the two markers
        var infowindow1 = new google.maps.InfoWindow({
            content: text1
        });
        var infowindow2 = new google.maps.InfoWindow({
            content: text2
        });

        // add action events so the info windows will be shown when the marker is clicked
        google.maps.event.addListener(marker1, 'click', function() {
            infowindow1.open(map,marker1);
        });
        google.maps.event.addListener(marker2, 'click', function() {
            infowindow2.open(map,marker1);
        });
       
        // compute distance between the two points
        var R = 6371;
        var dLat = toRad(location2.lat()-location1.lat());
        var dLon = toRad(location2.lng()-location1.lng());
       
        var dLat1 = toRad(location1.lat());
        var dLat2 = toRad(location2.lat());
       
        var a = Math.sin(dLat/2) * Math.sin(dLat/2) +
                Math.cos(dLat1) * Math.cos(dLat1) *
                Math.sin(dLon/2) * Math.sin(dLon/2);
        var c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1-a));
        var d = R * c;
       
        document.getElementById("distance_direct").innerHTML = "<br/>The distance between the two points (in a straight line) is: "+d;
    }
   
    function toRad(deg)
    {
        return deg * Math.PI/180;
    }
</script>

FireBug in Internet Explorer

Firebug In Internet Explorer
Working : Copy this Script  to the URL ..


javascript:var%20firebug=

Friday, March 18, 2011

Php Pagination Script



<!--+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1. Code to connect to your DB - place or include your code to connect to database.                                                +
2. $tbl_name - your table name.                                                                                                    +
3. $adjacents - how many adjacent pages should be shown on each side.                                                            +
4. $targetpage - is the name of file ex. I saved this file as pagination.php, my $targetpage should be "pagination.php".        +
5. $limit - how many items to show per page.                                                                                    +
6. "SELECT column_name - change to your own column.                                                                                +
7. Replace your own while..loop here - place your code to echo results here.                                                    +
                                                                                                                                +   
                                                                                                                                +
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++   
-->   
<?php
    /*
        Place code to connect to your DB here.
    */
    include('config.php');    // include your code to connect to DB.

    $tbl_name="";        //your table name
    // How many adjacent pages should be shown on each side?
    $adjacents = 3;
   
    /* 
       First get total number of rows in data table. 
       If you have a WHERE clause in your query, make sure you mirror it here.
    */
    $query = "SELECT COUNT(*) as num FROM $tbl_name";
    $total_pages = mysql_fetch_array(mysql_query($query));
    $total_pages = $total_pages[num];
    
    /* Setup vars for query. */
    $targetpage = "filename.php";     //your file name  (the name of this file)
    $limit = 2;                                 //how many items to show per page
    $page = $_GET['page'];
    if($page) 
        $start = ($page - 1) * $limit;             //first item to display on this page
    else
        $start = 0;                                //if no page var is given, set start to 0
    
    /* Get data. */
    $sql = "SELECT column_name FROM $tbl_name LIMIT $start, $limit";
    $result = mysql_query($sql);
    
    /* Setup page vars for display. */
    if ($page == 0) $page = 1;                    //if no page var is given, default to 1.
    $prev = $page - 1;                            //previous page is page - 1
    $next = $page + 1;                            //next page is page + 1
    $lastpage = ceil($total_pages/$limit);        //lastpage is = total pages / items per page, rounded up.
    $lpm1 = $lastpage - 1;                        //last page minus 1
    
    /* 
        Now we apply our rules and draw the pagination object. 
        We're actually saving the code to a variable in case we want to draw it more than once.
    */
    $pagination = "";
    if($lastpage > 1)
    {    
        $pagination .= "<div class=\"pagination\">";
        //previous button
        if ($page > 1) 
            $pagination.= "<a href=\"$targetpage?page=$prev\">« previous</a>";
        else
            $pagination.= "<span class=\"disabled\">« previous</span>";    
        
        //pages    
        if ($lastpage < 7 + ($adjacents * 2))    //not enough pages to bother breaking it up
        {    
            for ($counter = 1; $counter <= $lastpage; $counter++)
            {
                if ($counter == $page)
                    $pagination.= "<span class=\"current\">$counter</span>";
                else
                    $pagination.= "<a href=\"$targetpage?page=$counter\">$counter</a>";                    
            }
        }
        elseif($lastpage > 5 + ($adjacents * 2))    //enough pages to hide some
        {
            //close to beginning; only hide later pages
            if($page < 1 + ($adjacents * 2))        
            {
                for ($counter = 1; $counter < 4 + ($adjacents * 2); $counter++)
                {
                    if ($counter == $page)
                        $pagination.= "<span class=\"current\">$counter</span>";
                    else
                        $pagination.= "<a href=\"$targetpage?page=$counter\">$counter</a>";                    
                }
                $pagination.= "...";
                $pagination.= "<a href=\"$targetpage?page=$lpm1\">$lpm1</a>";
                $pagination.= "<a href=\"$targetpage?page=$lastpage\">$lastpage</a>";        
            }
            //in middle; hide some front and some back
            elseif($lastpage - ($adjacents * 2) > $page && $page > ($adjacents * 2))
            {
                $pagination.= "<a href=\"$targetpage?page=1\">1</a>";
                $pagination.= "<a href=\"$targetpage?page=2\">2</a>";
                $pagination.= "...";
                for ($counter = $page - $adjacents; $counter <= $page + $adjacents; $counter++)
                {
                    if ($counter == $page)
                        $pagination.= "<span class=\"current\">$counter</span>";
                    else
                        $pagination.= "<a href=\"$targetpage?page=$counter\">$counter</a>";                    
                }
                $pagination.= "...";
                $pagination.= "<a href=\"$targetpage?page=$lpm1\">$lpm1</a>";
                $pagination.= "<a href=\"$targetpage?page=$lastpage\">$lastpage</a>";        
            }
            //close to end; only hide early pages
            else
            {
                $pagination.= "<a href=\"$targetpage?page=1\">1</a>";
                $pagination.= "<a href=\"$targetpage?page=2\">2</a>";
                $pagination.= "...";
                for ($counter = $lastpage - (2 + ($adjacents * 2)); $counter <= $lastpage; $counter++)
                {
                    if ($counter == $page)
                        $pagination.= "<span class=\"current\">$counter</span>";
                    else
                        $pagination.= "<a href=\"$targetpage?page=$counter\">$counter</a>";                    
                }
            }
        }
        
        //next button
        if ($page < $counter - 1) 
            $pagination.= "<a href=\"$targetpage?page=$next\">next »</a>";
        else
            $pagination.= "<span class=\"disabled\">next »</span>";
        $pagination.= "</div>\n";        
    }
?>

    <?php
        while($row = mysql_fetch_array($result))
        {
    
        // Your while loop here
    
        }
    ?>

<?=$pagination?>
     

Sunday, March 13, 2011

CSS transforms

Rotation 
<style type="text/css">
.rotation {
    -moz-transform: rotate(-20deg);
    background-color:#000;
    width:500px;
    height:500px;
   -webkit-transform: rotate(-20deg);
   -o-transform: rotate(-20deg);
   margin:100px;
}
.skew {
    -moz-transform: skewx(10deg) translatex(150px);
    -moz-transform-origin: bottom left;
    -webkit-transform: skewx(10deg) translatex(150px);
    -webkit-transform-origin: bottom left;
    -o-transform: skewx(10deg) translatex(150px);
    -o-transform-origin: bottom left;
      margin:100px;
}
</style>

<div class="rotation">
  <iframe src="http://www.genioplus.blogspot.com/" width="500" height="500"></iframe>
</div>

<div class="skew">
  <iframe src="http://genioplus.blogspot.com/" width="400" height="200"></iframe>
</div>

Example

Thursday, March 10, 2011

CSS Text Shadow

Regular text shadow:

p { text-shadow: 1px 1px 1px #000; } 

Multiple shadows:

p { text-shadow: 1px 1px 1px #000, 3px 3px 5px blue; }


The first two values specify the length of the shadow offset. The first value specifies the horizontal distance and the second specifies the vertical distance of the shadow. The third value specifies the blur radius and the last value describes the color of the shadow:
1. value = The X-coordinate
2. value = The Y-coordinate
3. value = The blur radius
4. value = The color of the shadow
Using positive numbers as the first two values ends up with placing the shadow to the right of the text horizontally (first value) and placing the shadow below the text vertically (second value).
The third value, the blur radius, is an optional value which can be specified but don’t have to. It’s the amount of pixels the text is stretched which causes a blur effect. If you don’t use the third value it is treated as if you specified a blur radius of zero.
Also, remember you can use RGBA values for the color, for example, a 40% transparency of white:

p { text-shadow: 0px 2px 2px rgba(255, 255, 255, 0.4); }

Examples


 p    
    { 
    text-shadow: 1px 1px 10px #000; 
    font-size:100px;
    color:#fff;
    }


 h1   
    {
    text-shadow: 1px 1px 1px yellow, 3px 3px 1px #000;
    font-size:100px;
    color:#fff;
    }


 h3 
    {
    text-shadow: 0.2em 0.5em 0.1em #600,
    -0.3em 0.1em 0.1em #060,
    0.4em -0.3em 0.1em #006;
    font-size:100px;
    }


h4 {
    text-shadow: -1px 0 black, 0 1px black,
     1px 0 black, 0 -1px black;
     font-size:100px;
     color:#fff;
    } 


/*This one is Internet Exlorer */
h2 
    {
    height: 5em;
    font-size:100px;
    color:#009900;
    filter: Shadow(Color=#666666,Direction=125, Strength=10);
}