Jump to content


  • Content count

  • Joined

  • Last visited

Posts posted by Ian-San

  1. I have a question about an added parameter for this mod.  I read what Ian said about the necessity for the customer to click through so that the email actually gets sent.  So I pasted this code into my paypal_ipn page.

    $parameters['cbt'] = 'Click to Complete Order!';


    Now when an a customer is on paypal and they hit "pay" or "submit" or whatever that button is, Paypal brings them to a page that says "please wait while you are redirected within 10 seconds" and automatically redirects them to my own checkout_suceess.php page.  I thought this was a great thing, until I got more orders in with no actual OSC order emails.


    Do I need to paste all my paypal_ipn code here?  I did add a few mods to this contrib, for example the parameters to move the shipping info, as well as the tax total mods..


    Thank you.


    Somebody else may know better than me - all this line does is to rename the final "continue" button. I am not aware of any auto-direct so this must be the result of some other setting you have made to your PayPal?

  2. Well, here is what I think, so correct me if I'm wrong.


    I am passing the totals to paypal as an aggregate (not per item).


    It looks like Paypal is basically just accepting what it receives from osCommerce, namely that the SUBTOTAL is X, the SHIPPING RATE is Y, and it looks to ignore what osC claims as the total.


    So, Paypal just adds X+Y and comes up with a total. This total is sometimes one cent off osC's own total, due to some bizarre rounding error.


    Looks to me like the solution would be to fix osC's rounding so that its own total works out to be the sum of the subtotal plus shipping (I'm not messing around with tax yet).


    But you are saying it might be a mismatch between the rounding scheme used on PayPal and that on osC? I don't see how that's the case, though -- the problem is, osC's own total doesn't even match with its own subtotal and shipping!


    I can try the 2 decimal places thing, but I doubt it'll help. The main goal here is to eliminate osC's rounding problem, but in the install.html that came with the paypal-ipn module, it does list that as one of the known issues when using foreign currencies. I wonder what the technical reasons for that could be.


    The PayPal guide seems to suggest that PayPal can only work with two decimal places - I guess it truncates after that.


    On the other hand, osC can work with multiple decimal places. So for a foreign currency, the calculated amount will be in many decimal places but only displayed in the required number. I guess you are unlikely to price in your own currency to multiple decimals.


    I dont think changing the decimal places in admin will have any effect as it is just changing the display not the calculated or stored amount.


    The solution would require a change to osC core code to force everything to be stored and displayed in 2 decimals which wouldnt suite everyone. Alternatively, you could force payment in your home currency so that rounding problems dont exist. Or, as I said above, make the if statement in ipn.php more fuzzy.

  3. Made no difference whatsoever.


    If I understand you correctly, I think the problem is down to a combination of decimal places and rounding - PayPal uses different settings to osC.


    Then, this line fails:


    if ($_POST['mc_gross'] == number_format($total['value'] * $order['currency_value'], $currencies->get_decimal_places($order['currency']))) {


    so the status is not updated correctly to give an indication of a problem. The answer would seem to be to set your osC to exactly the same decimal places and rounding method as PayPal (what is it???) or to make the above line a bit more fuzzy?

  4. Damn, I made that change, and I thought we had the problem licked! But here is the new error message, that comes up when paypal returns me to /catalog/checkout_process.php?

    1064 - You have an error in your SQL syntax. Check the manual that corresponds to your MySQL server version for the right syntax to use near 't it accept the apostrophe?' where orders_id = '31' AND orders_
    update orders_status_history set customer_notified = '1', comments = 'Will it or won't it accept the apostrophe?' where orders_id = '31' AND orders_status_id = '4'
    [TEP STOP]


    The strange thing is that in the admin CPL under orders, I see that in the comments box it says:

    So the escaped apostrophe is being inserted by that tep_db_input command, but for some reason when the buyer returns to checkout_process the apostrophe comes back.  >_<


    For a non-paypal order and payment, the comments are checked by the input box which put in the back-slash. So the database input is not further protected by the tep_db_input.


    However, when these comments go off to PayPal they lose the back-slash.


    There are about 4 places in my store where comments might be inserted into the database in the Paypal IPN modules so the simple solution would be to put the tep_db_input function around all of them as it will do no harm if it is not actually required.

  5. Yeah, tep_db_input doesn't like the square brackets there. Not sure why because I think that's appropriate syntax. This is probably easy to solve but I don't know where to look for a syntax reference.


    And does the tep_db_input function do automatic apostrophe stripping?

    Opps, my mistake. I think it should be:


    'comments' => '[Unfinished / In progress PayPal IPN Order] ' . tep_db_input($order->info['comments']));


    This function changes every ' to \'

  6. Um, just ran into a weird bug today.


    Have IPN pretty much working, but if the customer enters a comment for the order that contains an apostrophe, when they finish payment and click the button to return to the store, I get the following error:

    Obviously, it's the apostrophe causing that error. I've tried it with other comments.

    This seems absurd, that a customer won't be able to type contractions like "won't" or "don't" or "can't" in their comments section. Is there an easy workaround to this, like some sort of wrapper that would strip out apostrophes from the comments?


    The solution should be easy but I havent tested it. Just change:


    'comments' => $order->info['comments']);


    in paypal_ipn.php to:


    'comments' => $order->tep_db_input(info['comments']));

  7. I realize this has been covered before, but I would like someone to spell it out for me if possible. What are the technical or security limitations that require the Paypal IPN module *NOT* to pass the buyer's address info to Paypal?


    When I get the orders, there is no buyer address whatsoever. I know I can check to see that the payer is a verified account, simply by looking at the IPN codes in the orders list through the Admin CPL (in the comments box when the status is changed after a successful IPN).


    However, for Paypal purposes this still doesn't help the seller because the order becomes INELIGIBLE for the Paypal Seller Protection Policy.


    This has been brought up before. I'm not here to point fingers or criticize, I'm just trying to understand why it has to be this way and if there's a way around it.


    I think sparky posted really early in this thread that "this was taken out at the last minute due to the Encrypted Website Payments."  I really don't understand the causal relation between those two statements.


    It would be great to pass the address. I think (from the documentation available on Paypal.com itself) that if a customer tries to buy without a paypal account, they are asked for shipping information etc. and there is a checkbox if this is the same as their credit card billing address. I think this is to make sure the payment is eligible for seller protection.


    Anyway, it would be great to hear from you IPN gurus why this is the way it is, even now (August 2005).



    There is contribution included with this mod that intends to add back in the missing customer details. But my belief is that it is flawed as it using the "billing" address which is not defined function order in class order in the standard build so actually no details are actually passed. Apologies to hostmistress if I am wrong.


    I havent had time to test it yet, but I think it would work, without changing the order class, if "billing" was changed to "customer".


    In short, just paste this in to paypal_ipn.php at the end of the current parameter list:


       $parameters['first_name'] = $order->customer['name'];
      $parameters['address1'] = $order->customer['street_address'];
      $parameters['address2'] = $order->customer['suburb'];
      $parameters['city'] = $order->customer['city'];
      if ($order->customer['country']['iso_code_2']=='US') {
        $order->customer['state'] = tep_get_zone_code($order->customer['country_id'], $order->customer['zone_id'], $order->customer['state']);
      $parameters['state'] = $order->customer['state'];
      $parameters['zip'] = $order->customer['postcode'];
      $parameters['country'] = $order->customer['country']['iso_code_2'];
      $parameters['email'] = $order->customer['email_address'];

  8. I thought the IPN took care of this and recorded orders even if the customer didn't return to the site. What is the point in using IPN module?


    There are two parts to this mod:

    - The first part pre-stores the order, manages the transfer of the customer and order details to PayPal and on customer payment and return will generate your customer emails (and any copies to yourself).

    - The second part will receive the IPN from PayPal in the background, change the order status to completed and update the order history.


    Depending on your store, IPN is not really required anyway in so much as you can just check the emails you get direct from PayPal, go to PayPal and check you actually have the cash and then manually update the order status before sending out the product. The IPN just automates this bit for you and gives you another opportunity to spot fraud.


    In my case, I do not sell physical products anyway so am not so concerned about spotting fraud in real time. However, I use the successful IPN to automatically update the customers account and alert me to specific order status details which allows me to manage my store in a completely hands-off way and deal with fraud in my own time.

  9. Ian - - did you ever get this sorted out? I'm also seeing this problem on one of my customers' sites.






    yes I got it to work and no, I don't know why it doesnt work with the standard set-up. My solution was:


    1) Replace the top two lines of ipn.php with:




    and the bottom with:




    2) Create the following file called ipn_application_top.php in the same place as ipn.php:


    <?php // ipn_application_top.php, v 1.0
    // include server parameters
    // include the list of project database tables
     require(DIR_WS_INCLUDES . 'database_tables.php');
    // include the database functions
     require(DIR_WS_FUNCTIONS . 'database.php');
    // make a connection to the database... now
     tep_db_connect() or die('Unable to connect to database server!');
    // set the application parameters
     $configuration_query = tep_db_query('select configuration_key as cfgKey, configuration_value as cfgValue from ' . TABLE_CONFIGURATION);
     while ($configuration = tep_db_fetch_array($configuration_query)) {
       define($configuration['cfgKey'], $configuration['cfgValue']);
    // Add in specific other functions
     function tep_not_null($value) {
       if (is_array($value)) {
         if (sizeof($value) > 0) {
           return true;
         } else {
           return false;
       } else {
         if (($value != '') && ($value != 'NULL') && (strlen(trim($value)) > 0)) {
           return true;
         } else {
           return false;
    // Return a random value
       function tep_rand($min = null, $max = null) {
         static $seeded;
         if (!isset($seeded)) {
           $seeded = true;
         if (isset($min) && isset($max)) {
           if ($min >= $max) {
             return $min;
           } else {
             return mt_rand($min, $max);
         } else {
           return mt_rand();
    // Wrapper function for round()
     function tep_round($number, $precision) {
       if (strpos($number, '.') && (strlen(substr($number, strpos($number, '.')+1)) > $precision)) {
         $number = substr($number, 0, strpos($number, '.') + 1 + $precision + 1);
         if (substr($number, -1) >= 5) {
           if ($precision > 1) {
             $number = substr($number, 0, -1) + ('0.' . str_repeat(0, $precision-1) . '1');
           } elseif ($precision == 1) {
             $number = substr($number, 0, -1) + 0.1;
           } else {
             $number = substr($number, 0, -1) + 1;
         } else {
           $number = substr($number, 0, -1);
       return $number;
    // include currencies class and create an instance
     require(DIR_WS_CLASSES . 'currencies.php');
     $currencies = new currencies();
    // charset for emails
    define('CHARSET', 'iso-8859-1');
    // include the mail classes
     require(DIR_WS_CLASSES . 'mime.php');
     require(DIR_WS_CLASSES . 'email.php');
    // Send an Email
     function tep_mail($to_name, $to_email_address, $email_subject, $email_text, $from_email_name, $from_email_address) {
       if (SEND_EMAILS != 'true') return false;
       // Instantiate a new mail object
       $message = new email(array('X-Mailer: osCommerce Mailer'));
       // Build the text version
       $text = strip_tags($email_text);
       if (EMAIL_USE_HTML == 'true') {
         $message->add_html($email_text, $text);
       } else {
       // Send message
       $message->send('', $to_email_address, $from_email_name, $from_email_address, $email_subject);



    Note, I use HTML emails and not sure how standard the above Send Email part is. Also, you may want to check on the need for CHARSET - it might be something I added!

  10. I have this happen with the team IPN mod. Database is fine, just no emails sent when users do not return to the site.


    You wont get emails unless the customer actually clicks the final PayPal continue button and returns back to the store as the emails are sent out from the paypal_ipn.php module in the after process not the ipn callback module - ipn.php.


    There is no easy solution to this. You could move the email generation to the process_button section of paypal_ipn.php or alternatively to ipn.php. But both solutions create other problems.


    In the first case, the emails would be sent out even if the payment has not actually been made and in both cases it would be a little complicated to get the full order detail into the email. Or you could generate a temporary email from the process_button section with some bland all purpose words about the order but again it has problems if the customer doesnt complete the purchase.


    In addition, you cannot actually tell which module - ipn.php or paypal_ipn.php will actually be run first as it depends on the speed of the cusomer returning versus the speed of the ipn callback.


    So the simpler option is just to add this to the parameter list in paypal_ipn.php!


     $parameters['cbt'] = 'Click to Complete Order!';


    This will rename the final PayPal button and make it clearer that the customer must return to the store.

  11. Not sure if I put this here or if anyone can help me with this but I'm getting an error   


    We are sorry that we are experiencing temporary difficulties. Please try again later.

    Message 5302   


    This happens after I click on the confirm order button.  I'm right now using the sandbox.  Does anyone know how to fix this or any ideas?

    Sorry if this was not the right area to ask this question.


    It just means that PayPal are in the process of updating software on the server and access is slow or restricted.

  12. This moudule still doesnt work for me but some of you might want to check this potential error:


    Email order confirmation will not show the selected attribute list as $languages_id is not defined in query line 488 / 491.


    In catalog/includes/modules/payment/paypal_ipn.php look for the global statement - line 409


    - immediately following "function before process() {"


    and change to:


    global $customer_id, $order, $sendto, $billto, $payment, $currencies, $cart, $cart_PayPal_IPN_ID, $languages_id;

  13. A lot of people in this post have reported problems with the order status "Preparing [PayPal IPN]" not changing on PayPal notify and so far there has not been a real solution posted.


    I also have that problem.


    However, it is obvious that this contribution does work for many people and so the problem is clearly not with the module itself.


    In addition, I have verified that the module does in fact work perfectly up to the point of notify, everything that should be sent is sent to PayPal, all the emails are received, the basket is cleared, the order history updated and PayPal does indeed send back a notify which is logged by my server.


    I get this code 200 in my server logs which clearly indicates that the notify was uccessfully attempted and Paypal does not attempt to send any repeat notifies:

  - - [09/Jul/2005:19:33:26 +0100] "POST /ext/modules/payment/paypal_ipn/ipn.php HTTP/1.0" 200 189 "-" "-"


    However, the fact remains that the notify still doesnt work!


    Initially, I thought the problem was something to do with session creation, permissions or spider blocking but after changing the ipn.php file to one that would simply add an entry to the page_parse_time.log it still doesnt work.


    Yet, if I manually post the variables to the ipn.php file it works perfectly.


    So, it appears to me that something in the server settings is preventing the posts from what looks to the server as being a spider or robot.


    It is not the htaccess file as far as I can see and I can successfully post forms to my site from other external sites.


    So does anyone have any idea what this might be?


    I am running in safe mode - has anyone successfully used this contribution on shared server running safe mode?


    Has anyone who reported the notify not working actually got it to work?

  14. Hi Ian-san,


    I think I've seen that name somewhere... but I'm not quite sure where. :-)


    Ok, I can delete the language string, but I'll need that later as I will in fact have a multi-language installation.


    However, how does WorldPay/osC retain my osCid for a NONSSL session?  I thought I'd need that to tie my Worldpay SSL session to my osC NONSSL session?  When I tried the alternative (no osCid or language), then when I returned to osC, (from either a cancel or a buy), the 'buyer' is logged out, and no meaningful WorldPay message returned.


    With regards to cookies, I tried this on two separate PCs, and both had the same problem.  I'm now a bit worried that I picked two 'unusual' cookie PCs.





    Taking the second point first: When you first enter your store you will probably see the SID in the url string. For most users / stores this will disappear on the second click in the store as it is replaced by the cookie.


    However, if you do not allow cookies on your browser, you will continue to see the SID in all urls throughout your store.


    The WP mod uses tep_href_link to construct the WP string. If cookies are not allowed, the SID will also be present in this string and passed through to WP at this point.


    The mod also adds the SID with this code:


     tep_draw_hidden_field('MC_oscsid', $oscSid);


    as well, so two SIDs would be present in the string which is what you are experiencing.


    What is probably required is an improvement to replace the:


    $worldpay_callback = explode('http://', $callback_url);



    along the lines of:


            $string_new = str_replace("http://","",$callback_url);
           $file = strtolower(strrchr($string_new,"/"));
           $worldpay_callback = str_replace($file,"",$file_new);


    and later to replace:


    tep_draw_hidden_field('MC_callback', $worldpay_callback[1] . '?language=' . $language_code)




    tep_draw_hidden_field('MC_callback', $worldpay_callback . '?language=' . $language_code)


    or similar ...

  15. Ric


    You are 100% correct with the problem but not, I think, the cause.


    The earlier code:


    $callback_url = tep_href_link(FILENAME_WPCALLBACK);
    $worldpay_callback = explode('http://', $callback_url);


    and this part:





    Should not carry the oscSid into the callback string. The fact that it does, is probably (I am just guessing) due to a problem with cookies on your installation / browser. For most users, the oscSid will not be present in a link at this point.


    The second issue is that if you do change the ? to an & for a user who does not have this problem, you will probably get the reverse error. ie and & where it shouldnt be.


    Until it is resolved, the easiest option is just to delete the whole language part from the string ( . '?language=' . $language_code) if you are not using a multi-language installation.

  16. Sam


    Keep posting - we all live and learn!


    Try removing line 125 of modules/worldpay.php (the oscSid) - be careful, it is the last line of the string so you need to terminate the above line.


    I am certain your problem has something to do with your store attempting to restart a session and finding that it already has an identical one stored.

  17. Sam


    If you have followed the install instructions correctly, your problem will not be with the WP Payment Module, OSC or WorldPay as you know that many others are using this module without problem.


    So the issue must be with your setup or configuration. I would start by checking your settings for Sessions in Admin. Set them all to false and try again.


    Next, do you get any problems with any other payment modules or parts of your store?


    Do you store sessions in MySQL in configure.php?

  18. normally the person who wrote the tool is using the tool, notices the problem and then fixes it with a release or update.

    He did! But I don't use this contribution anymore ... :(


    The problem is an easy fix and I will try to make a new contribution later this week. In the meantime, you may just try to paste in these changes:


    switch ($report) {

    case "1": // By Hours Today

    $visitor_stats_query = tep_db_query("select HOUR(date) as name, count(counter) as value FROM " . TABLE_VISITORS . " where to_days(now()) - to_days(date) < 1 group by HOUR(date)");


    case "3": // By Months this Year

    $visitor_stats_query = tep_db_query("select MONTHNAME(date) as name, count(counter) as value FROM " . TABLE_VISITORS . " where YEAR(now()) - YEAR(date) < 1 group by MONTH(date)");


    case "4": // All by Year

    $visitor_stats_query = tep_db_query("select YEAR(date) as name, count(counter) as value FROM " . TABLE_VISITORS . " group by YEAR(date)");


    case "5": // All by Hours

    $visitor_stats_query = tep_db_query("select HOUR(date) as name, count(counter) as value FROM " . TABLE_VISITORS . " group by HOUR(date)");


    case "6": // All by Day of Month

    $visitor_stats_query = tep_db_query("select DAYOFMONTH(date) as name, count(counter) as value FROM " . TABLE_VISITORS . " group by DAYOFMONTH(date)");


    case "7": // Average Clicks per IP by Days

    $visitor_stats_query = tep_db_query("select DAYOFMONTH(date) as name, avg(counter) as value FROM " . TABLE_VISITORS . " group by DAYOFMONTH(date)");


    case "8": // Total Clicks by Top Countries

    $visitor_stats_query = tep_db_query("select browser_language as name, sum(counter) as value FROM " . TABLE_VISITORS . " group by browser_language");


    case "9": // Total Clicks by Site Language

    $visitor_stats_query = tep_db_query("select language as name, sum(counter) as value FROM " . TABLE_VISITORS . " group by language");


    case "10": // Search Engine Keywords

    $visitor_stats_query = tep_db_query("select referer as name, count(counter) as value FROM " . TABLE_VISITORS . " group by referer");


    case "11": // NYA

    $visitor_stats_query = tep_db_query("select DAYOFMONTH(date) as name, count(counter) as value FROM " . TABLE_VISITORS . " where MONTH(now()) - MONTH(date) < 1 and YEAR(now()) - YEAR(date) < 1 group by DAYOFMONTH(date)");


    case "12": // NYA

    $visitor_stats_query = tep_db_query("select DAYOFMONTH(date) as name, count(counter) as value FROM " . TABLE_VISITORS . " where MONTH(now()) - MONTH(date) < 1 and YEAR(now()) - YEAR(date) < 1 group by DAYOFMONTH(date)");


    default: // By Days this Month

    $visitor_stats_query = tep_db_query("select DAYOFMONTH(date) as name, count(counter) as value FROM " . TABLE_VISITORS . " where MONTH(now()) - MONTH(date) < 1 and YEAR(now()) - YEAR(date) < 1 group by DAYOFMONTH(date)");




    and in application_top:


    // Visitors Start

    $b_lang = getenv('HTTP_ACCEPT_LANGUAGE');

    $referer = getenv('HTTP_REFERER');

    if ($referer == '') {

    $referer = 'direct';


    $uri = getenv('REQUEST_URI');

    if ( function_exists('tep_get_ip_address') ) {

    $b_ip = tep_get_ip_address();

    } else {

    $b_ip = getenv('REMOTE_ADDR');


    if ($b_lang == '') {

    $b_lang = 'robot';


    $b_count = '1';

    $ip_count = tep_db_query("select counter FROM " . TABLE_VISITORS . " where browser_ip = '" . $b_ip . "' AND browser_language = '" . $b_lang . "' AND to_days(now()) - to_days(date) < 1");

    if (!tep_db_num_rows($ip_count)) {

    tep_db_query("insert into " . TABLE_VISITORS . " (date,counter,browser_ip,browser_language,language,referer,uri) values (now(),'".$b_count."','".$b_ip."','".$b_lang."','".$language."','".$referer."','".$uri."')");

    } else {

    $ip_values = tep_db_fetch_array($ip_count);

    $b_count = ($ip_values['counter'] + 1);

    tep_db_query("update " . TABLE_VISITORS . " set counter = '" . $b_count . "', date = now() where browser_ip = '" . $b_ip . "' AND browser_language = '" . $b_lang . "' AND to_days(now()) - to_days(date) < 1");



    // Visitors End


    Plus you will need to define TABLE_VISITORS in database tables:


    define('TABLE_VISITORS', 'visitors');



    I will do a diff on my version and the one contributed and see what changes are required.

  19. My version is non-standard but I think the mod should be as follows:




    if ($response_verified==1) {

    if (strtolower($receiver_email)==strtolower(MODULE_PAYMENT_PAYPALIPN_ID) || strtolower($business)==strtolower(MODULE_PAYMENT_PAYPALIPN_ID)) {

    if ($payment_status=='Completed') {





    $notify_customer_id = $order->customer['id'];


    if ( ($notify_customer_id > '0') && ($response_verified == '1') && ($payment_status == 'Completed') && ($txn_type != 'reversal') ) {

    if (strtolower($receiver_email)==strtolower(MODULE_PAYMENT_PAYPALIPN_ID) || strtolower($business)==strtolower(MODULE_PAYMENT_PAYPALIPN_ID)) {



    and replace:

















    The check on the customer_id is not strictly required but maybe adds another layer of protection.

  20. On the second point, WP recently changed its currency server from http to https - so if you are using the unmodified WP currency update contribution it will not work - the delay is probably due to waiting for it to time out. Someone posted some changes to this mod recently - not sure where.