Product Controller doesn't transfer me to template

When i call the product controller from my php code to add a product, the product does get added. However, I am not transferred to the template like it does when I add a product through the browser. Why does it do this? I would like to get some output so I can see if the product was added sucessfully. Right now I cannot tell other than to look myself in a web browser in admin. Does anyone have a helpful tip here?



Here is the code:


function CreateUpdateProduct($product, $FileBytes){
$product_code=$product['product_code'];
$filename = "/media/data/www/webservice/image_upload/$product_code.jpg";
UploadFile($FileBytes,$filename);
// INIT CURL
$ch = curl_init('http://webserv01.gva-twn.com/cscart/admin.php');
// ENABLE HTTP POST
curl_setopt ($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_FOLLOWLOCATION,1);
curl_setopt($ch, CURLOPT_HEADER,0);
curl_setopt ($ch, CURLOPT_COOKIEJAR, 'cookie.txt');
curl_setopt ($ch, CURLOPT_RETURNTRANSFER, 1);

//login to the admin section
//$parameters= array('return_url' => 'admin.php', 'user_login' => 'root', 'password' => 'password', 'dispatch[auth.login]' => 'Sign in');
$parameters='return_url=admin.php&user_login=root&password=cronos889&dispatch[auth.login]=Sign+in';
curl_setopt ($ch, CURLOPT_POSTFIELDS, $parameters);
$returndata1 = curl_exec ($ch);
$h2t =& new html2text($returndata1);
$returndata1 = $h2t->get_text();
$date = new DateTime();
$datef = $date->format( 'mdYHis');
//file_put_contents("returndata1_$datef.txt",$returndata1, FILE_APPEND);
$httpCode1 = curl_getinfo($ch, CURLINFO_HTTP_CODE);
$err1 = $h2t->get_text(curl_error($ch));
$parameters = array('file_product_main_image_icon[0]' => '@'.$filename);
//post the data to new products.php

foreach ($product as $key => $value) {
$parameters['product_data['.$key.']'] = $value;
}
curl_setopt($ch, CURLOPT_URL, 'http://webserv01.gva-twn.com/cscart/admin.php?dispatch=products.add');
curl_setopt ($ch, CURLOPT_POSTFIELDS, $parameters);
$returndata2 = $h2t->get_text(curl_exec ($ch));
//to dump product into a variable use print_r($product, true)
//$post_data = print_r($product, true);
//file_put_contents("returndata2_$datef.txt",$post_data, FILE_APPEND);
$httpCode2 = curl_getinfo($ch, CURLINFO_HTTP_CODE);
$err2 = $h2t->get_text(curl_error($ch)) ;
if ($httpCode1==0) {
return "error from first post $err1";
}
elseif ($httpCode2==0) {
return "error from second post $err2";
}
else {
return $returndata2;
}

}

Please use the “code” tags so indentation is preserved… Too hard to read otherwise.

What exactly are you trying to do? Are you trying to “import” a file without going through the Admin panel? Please give a step-by-step “use case” of what you’e trying to accmplish. No one knows where this function is called, whether it’s called within the cart or on your PC, etc.

Thanks for the tip about the code tag. What I am trying to do is what I see a lot of others trying as well. I am creating a web service to allow external access to the api’s of cscart. Specifically Add/Change/Delete of Products, Categories, Images. Also to be able to read new orders, and update order status including tracking.



The method I chose was to use NuSoap, It works quite well. I have figured out how to pass objects based on products and category so far between my VB.Net Hub that is interfaced with Microsoft Great Plains and the NuSoap PHP page. I have even been able to call the product controller in my code and successfully add a product. I do not, however get any feedback whether it was successful.



If I can get the basic concepts down, I will of course expand the web service to include all the needed functions, and share it with anyone who wants it.



Please let me know if you have any more questions and thanks again,



Scott

Unfortunately the code is just a little to big to fit on here. I have attached it instead. Here is a sample though if the CreateUpdateProduct Function in the script.




function CreateUpdateProduct($product, $FileBytes){
$product_code=$product['product_code'];
$filename = "/media/data/www/webservice/image_upload/$product_code.jpg";
UploadFile($FileBytes,$filename);
// INIT CURL
$ch = curl_init('http://webserv01.gva-twn.com/cscart/admin.php');
// ENABLE HTTP POST
curl_setopt ($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_FOLLOWLOCATION,1);
curl_setopt($ch, CURLOPT_HEADER,0);
curl_setopt ($ch, CURLOPT_COOKIEJAR, 'cookie.txt');
curl_setopt ($ch, CURLOPT_RETURNTRANSFER, 1);

//login to the admin section
//$parameters= array('return_url' => 'admin.php', 'user_login' => 'root', 'password' => 'cronos889', 'dispatch[auth.login]' => 'Sign in');
$parameters='return_url=admin.php&user_login=root&password=cronos889&dispatch[auth.login]=Sign+in';
curl_setopt ($ch, CURLOPT_POSTFIELDS, $parameters);
$returndata1 = curl_exec ($ch);
$h2t =& new html2text($returndata1);
$returndata1 = $h2t->get_text();
$date = new DateTime();
$datef = $date->format( 'mdYHis');
//file_put_contents("returndata1_$datef.txt",$returndata1, FILE_APPEND);
$httpCode1 = curl_getinfo($ch, CURLINFO_HTTP_CODE);
$err1 = $h2t->get_text(curl_error($ch));
$parameters = array('file_product_main_image_icon[0]' => '@'.$filename);
//post the data to new products.php

foreach ($product as $key => $value) {
$parameters['product_data['.$key.']'] = $value;
}
curl_setopt($ch, CURLOPT_URL, 'http://webserv01.gva-twn.com/cscart/admin.php?dispatch=products.add');
curl_setopt ($ch, CURLOPT_POSTFIELDS, $parameters);
$returndata2 = $h2t->get_text(curl_exec ($ch));
//to dump product into a variable use print_r($product, true)
//$post_data = print_r($product, true);
//file_put_contents("returndata2_$datef.txt",$post_data, FILE_APPEND);
$httpCode2 = curl_getinfo($ch, CURLINFO_HTTP_CODE);
$err2 = $h2t->get_text(curl_error($ch)) ;
if ($httpCode1==0) {
return "error from first post $err1";
}
elseif ($httpCode2==0) {
return "error from second post $err2";
}
else {
return $returndata2;
}

}

cscart_integration.zip

For me, I utilize a true login and utilize the CSV import/export format for importing products (which includes images, options, features and all the other goodies) rather than using the fn_update_product() function directly. This gives me the full response of success/failure for each item versus the function returning true/false for each call. I’m assuming you are not returning the function return value to your interface. So how do you know if it was successful or not? Also, there’s many more steps to adding a product than simply creating the product via the fn_update_product() function.



For orders, I register hooks to catch the orders in real time as they are being submitted to the system, evaluate the status and type of transaction and do the appropriate thing for integrating with my backend (I.e. don’t send ‘Open’ orders if there is a processor involved and other logic). I’m assuming that you regularly look at the orders table for new entries and then do the same sort of thing. The paypal type of “handling” requires additional logic so the order isn’t sent until it is actually paid.



Are you then doing all the db calls to find all the related elements or are you then calling fn_get_order_data() and using its results?



Just curious how others are approaching the problems.



I have been providing an integrated solution between my back-end order/inventory management system and cs-cart for quite a while now and I know the problems are not simple and not straight-forward to do it right. I also support the ability to manage multiple stores from a single back-end inventory by creating catalogs from inventory for each store with the ability to calculate fields so you can setup a catalog to (for instance) reduce all prices by 20%. One then sends that catalog. Then after the sale is over, one sends the old catalog to reset everything to what it was or calculate a new one.

What happens if your initial login fails (I.e. after an upgrade and additional security strength has been added)? It appears your code will just continue on since it doesn’t look like you handle a redirect back to the login page if the login fails for any reason.

I am return a string now from the webservice which is intended to have the status (success/failure) along with additional information if I can get it. The problem right now is the controller is transferring to the auth/login_form.tpl instead of a template that can give me that status of my product add/change. I don’t know how to direct it to another template.



In my first integration solution, I was checking for new orders simply by status by directly querying the mysql database remotely. I created a new status to indicate that the order was uploaded to great plains and set the status after I processed it. In my new software I don’t have the function written to read the orders but I was going to try and use orders.manage - fn_get_orders() to keep it consistent and just look for order status P.



I am trying to get everything through the api if possible and avoid database calls, but I am running low on time and I may have to do that for the time being and work on the api method for the long run.



I am satisfied that on the great plains end I have gone from having to scan the database constantly, to using it’s own built-in api’s to push out new product information and order status etc. Great Plains has a huge database and the way customers add extra information is using a product called extender which creates large amounts of unnormalized data that make frequent queries of the entire product catalog (70,000 items) expensive.



So back to the first thing you said, are you automating the csv import/export? I never thought of that. If you are doing that, then I’m assuming you would need to also ftp the images up first so cscart can find them.

[quote name=‘tbirnseth’]What happens if your initial login fails (I.e. after an upgrade and additional security strength has been added)? It appears your code will just continue on since it doesn’t look like you handle a redirect back to the login page if the login fails for any reason.[/quote]



I just wanted to get the basics concepts going, but I will have to check for that as well as problems with product, category, order history add/change/deletes. I am getting output from curl, and I can covert it to plain text and check for key phrases to see if the login went ok or not, or if there are problems with the products, categories, and orders controllers. (If I could only figure out why the products.add sends me back to the auth/login_form.tpl instead of the products/manage.tpl.



If the product gets upgraded or the interface to the logon api is broken, I will have to update my code to recognize both the old and the new if I am providing it to multiple cscart installations which may or may not be on the same version. I can’t think of what else I could do.

[quote]

So back to the first thing you said, are you automating the csv import/export? I never thought of that. If you are doing that, then I’m assuming you would need to also ftp the images up first so cscart can find them.

[/quote]

Yes, the images are assumed to exist and be referencable by the path name specified in the import file.



I choose to use the import/export for the most part simply because this is NOT a real API. I.e. there is no commitment to compatibility from release to release. They are internal functions that can be modified at any time and are outside my control.



So I assume that the “higher level model” (import/export) will be compatible with whatever underlying changes are made. It’s a tad slower but since things are done in a “batch” there is not the traffic of individual product updates…



Have fun.

[quote name=‘tbirnseth’]



For orders, I register hooks to catch the orders in real time as they are being submitted to the system, [/quote]



I’m thinking of using hooks for when I try to add a product to see if it was added successfully.



But I’m not understanding, it appears to me that I can only attach to an existing hook in my addon. For instance there is one in products fn_set_hook(‘update_product’, $product_data, $product_id, $lang_code); that happens after the product is updated. But i do not see a hook in orders except for after one is deleted.

[quote name=‘scottemick’]IBut i do not see a hook in orders except for after one is deleted.[/QUOTE]



There are two that I use (part of checkout, not orders). The first is ‘place_order’ where I check whether there is a payment provider or not (the status is usually ‘O’ (Open) at this point. If no provider (or certain other criteria), I send the order from there. It is assumed that the order sent from here will never make it to order_placement_routines() to be sent from there.



The second is ‘order_placement_routines’ which is where ‘processed’ orders are handled. If an order gets here, then the payment processing completed and you’ll have access to things like transactionIID’s, auth codes, etc.

Thanks, I hadn’t even looked there…so what that tells me unfortunately is you aren’t actually creating any new hooks and I will have to sift through what there are for products and make the best of them.

[quote name=‘scottemick’]Thanks, I hadn’t even looked there…so what that tells me unfortunately is you aren’t actually creating any new hooks and I will have to sift through what there are for products and make the best of them.[/QUOTE]



I chose to utilize what’s there to avoid upgrade conflicts. I support a lot of clients so upgrades are a big deal here. Any conflict that can be avoided should be from my perspective.



But you can add all the hooks you want. Just remember that anything you add has to be maintained. And hooks do change from release to release (usually added parameters).

The solution to the problem for which I created this thread was simply to set a useragent in curl. I already knew that cs-cart based its ouput on useragent, but forgot to include it in my code.



So I added


$useragent="Mozilla/5.0 (Windows; U; Windows NT 6.0; en-US; rv:1.9.2.3) Gecko/20100401 Firefox/3.6.3 (.NET CLR 3.5.30729)";
curl_setopt($ch, CURLOPT_USERAGENT, $useragent);
And now I get the response from the operation (add/update product, category etc).



Now I just need to figure out if I can replace the default template with one of my own to make the output simpler and consistent. I definitely can’t rely on trying to parse a template file that could be anything.

I’ve created my addon and have sucessfully been able to register two code hooks, and have them transfer to my own functions. But when I put the following code in to test, and go to create a product I don’t get any output at all, or any errors in the log. Yet, the product is created ok. Also the template debugger doesn’t show anything. If I comment out all the $view-> statements and re-save the script, then I can add a product just fine.







(I need to get a way to print out the product_id after it is created and also detect that the request is coming from my webservice so it doesn’t cause a problem with the normal admin functions. Maybe a special string in my useragent or something like that.)


```php

func.php


if ( !defined('AREA') ) { die('Access denied'); }

function fn_web_service_integration_update_product($product_data, $product_id, $lang_code) {
$view->assign('product_data', $product_data);
$view->display('addons/web_service_integration/views/product_update_results.tpl');
}
function fn_web_service_integration_update_category($category_data, $category_id, $lang_code) {
$view->assign('product_data', $category_data);
$view->display('addons/web_service_integration/views/category_update_results.tpl');
}

?>

```


$results = fn_web_service_integration_update_product(.....) + fn_web_service_integration_update_category(....);
echo implode("\n", $results);
exit;




Your functions can return an array element for each product or category ID you pass and then just read it from your curl() operation.



I.e.

Product 1234: OK

Category 456: FAIL



Or you may have some things where you want to encapsulate the result via serialize(). I.e.:

echo serialize($result);

exit;



And then on the client side:

$response = curl(…);

return unserialize($response);

I tried to change my $view->assing & view-> just to echo, that doesn’t help. I actually tried that first before. i even put an exit(0) after to try and stop it from running the normal template.



if ( !defined('AREA') ) { die('Access denied'); }

function fn_web_service_integration_update_product($product_data, $product_id, $lang_code) {
echo $product_id."\n";
exit(0);
}
function fn_web_service_integration_update_category($category_data, $category_id, $lang_code) {
echo $category_id."\n";
exit(0);
}

?>






In your example it looks like you are calling the same function that I have the hook set to call. If I am calling it myself, and not the hook, how will I get results for the new product or category.

The echo works when i add a product through the admin section…Just not with my web service…



So I am back on the right track, thanks

My confusion in all of this. I thought you were calling your web serviice with the product/category_id and the data. I thought this was controller code versus a hook.



You should still see the echo being returned through curl. The view would never be called. I don’t use the hooks you are using and don’t have time to investigate. For changes in products, I use the import format. I use the fn_get* functions for retrieving data and generally simply serialize the results and parse the array on the client side.



I would not use ‘exit(0)’ since in PHP, the exit argument sets the value of the header that is sent (default is 200). Hence, I’d just use ‘exit;’ unless you detect a failure then it would be a 500 series code.