Loading model function inside a webservice function - php

I'm working in a codeigniter based project with integrated SOAP webservices, and I fail to load a model function inside a registered webservice function.
I have this 2 functions in SOAP webservice: hello and addcontact.
function hello($name) {
return 'Hello, ' . $name;
}
and
function addcontact($nombre, $apellido, $ciudad) {
$resultado=$this->modelo_turismo->addcontact($nombre, $apellido, $ciudad);
if($resultado){
return "Bienvenido $nombre $apellido. Tu eres de $ciudad.";
}else{
return "No se pudo agregar contacto.";
}
}
Function hello is simple and its working fine when service is consumed by client, unlike function addcontact that is showing this message when trying to be consumed:
Response not of type text/xml: text/html
As you can see, I'm loading a function within model that inserts a contact to database, but im not even returning any database data to echo or print.
As well I've tried some other things trying to load the model, I cant get rid of that message, so I tried this (I know its weird to use a function to insert like this in CodeIgniter but im trying to learn why that message come):
function addcontact($nombre, $apellido, $ciudad) {
$conexion = new mysql ("localhost","root","","turismo");
if ($conexion->connect_errno){
return "Failed to connect to MySQL: " . $conexion->connect_error;
}
$query = "INSERT INTO contactos (nombre, apellido, ciudad) VALUES ('$nombre', '$apellido', '$ciudad')";
$resultado = $conexion->query($query);
if($resultado){
return "Bienvenido $nombre $apellido. Tu eres de $ciudad.";
}else{
return "No se pudo agregar contacto.";
}
}
with that function I get this error again:
Response not of type text/xml: text/html
But if I change the in the connection line 'mysql' to 'mysqli' like this:
$conexion = new mysqli ("localhost","root","","turismo");
I get the expected result when loading client:
Bienvenido John Travolta. Tu eres de California.
I then suspected that the error I was getting loading the model was because in my database config file I had this line:
$db['default']['dbdriver'] = 'mysql';
so I tried to change the driver to 'mysqli' and no good results. I keep getting the same error:
Response not of type text/xml: text/html
BTW, this is the way im registering 'addcontact' function:
$this->nusoap_server->register('addcontact', // method name
array('nombre' => 'xsd:string',
'apellido' => 'xsd:string',
'ciudad' => 'xsd:string'), // input parameters
array('return' => 'xsd:string'), // output parameters
'urn:Turismo_WSDL', // namespace
'urn:Turismo_WSDL#addcontact', // soapaction
'rpc', // style
'encoded', // use
'Agregar reservacion' // documentation
);
and this is the client function, that consumes the function above:
function addcontact() {
$wsdl = site_url('Webservice/wsdl');
$client = new nusoap_client($wsdl, true);
$client-> soap_defencoding='UTF-8';
$client->decode_utf8 = true;
$err = $client->getError();
if ($err) {
echo '<h2>Constructor error</h2><pre>' . $err . '</pre>';
}
$result = $client->call('addcontact', array('nombre' => 'John', 'apellido'=>'Travolta', 'ciudad'=>'California'));
// Check for a fault
if ($client->fault) {
echo '<h2>Fault</h2><pre>';
print_r($result);
echo '</pre>';
} else {
// Check for errors
$err = $client->getError();
if ($err) {
// Display the error
echo '<h2>Error</h2><pre>' . $err . '</pre>';
} else {
// Display the result
echo '<h2>Result</h2><pre>';
print_r($result);
echo '</pre>';
}
}
}
So my question is, what I'm doing wrong? I can do the work with a manual connection like described above, but I want to work with the model as in CodeIgniter.

We can call the codeigniter models using instance variable
$ci =& get_instance();
Class soap
{
private $ci;
// set the CI classes to $CI
function __constuct(){
$this->ci = & get_instance ();
}
function callone(){
$resultado=$this->ci->modelo_turismo->addcontact($nombre, $apellido, $ciudad);
}
}
ci-> will provide the models from CI
Please refer this for more about codeigniter Instance variables
Codeigniter: Get Instance

Related

Laravel error reporting in database

I'm making a request to URL to get data using Goutte. But the server where I'm making request is slow. So sometimes laravel throws error of time out. When this error comes, I have to make entry of this error log in databse with some additional data (i.e, id etc). I have searched on internet. But I found all solutions related to customise error message etc. What I want is when laravel throws error of time out, I have to make entry in database with additional data and then redirect page. If any one knows the solution, it will be appreciated.
Here is my code.
use Goutte\Client;
class WebScrapingController extends Controller {
public function index() {
try {
$this->crawler = $this->client->request('GET', $url . '?' . $data);
}catch(Exception $e){
// Here I want to make entry in database and then redirect to another page
dd(['Connection time out', $i, $e]);
}
}
}
Here is my error message
ConnectException in CurlFactory.php line 186:
cURL error 7: Failed to connect to myurl port 80: Connection timed out (see http://curl.haxx.se/libcurl/c/libcurl-errors.html)
Also getting this error sometimes
RequestException in CurlFactory.php line 187:
cURL error 56: Recv failure: Connection timed out (see http://curl.haxx.se/libcurl/c/libcurl-errors.html)
I'm using laravel 5.3 and this scraper.
Well, this is how I would do it:
use Goutte\Client;
class WebScrapingController extends Controller {
public function index() {
try {
$this->crawler = $this->client->request('GET', $url . '?' . $data);
} catch(\ConnectException $e){
$log = new Log();//define this as a model
$log->setMessage($e->getMessage());
$log->save();
} catch(\RequestException $e){
$log = new Log();//define this as a model
$log->setMessage($e->getMessage());
$log->save();
} finally {
$yourModel = YourNamespace\YourModel::find($url);//or, depends on your model structure and DB
$yourModel = YourNamespace\YourModel::where('url',$url)->first();
}
}
}
You can also move the saving of the log in a private method, I left it like this so you can see that it is possible to treat several exceptions differently, or you could catch as a general exception:
public function index() {
try {
$this->crawler = $this->client->request('GET', $url . '?' . $data);
} catch(\Exception $e){
$log = new Log();//define this as a model
$log->setMessage($e->getMessage());
$log->save();
} finally {
$yourModel = YourNamespace\YourModel::find($url);//or, depends on your model structure and DB
$yourModel = YourNamespace\YourModel::where('url',$url)->first();
}
}
If you want to log in some files you have the Log facade: use Illuminate\Support\Facades\Log;

Simple PHP Soap Server and Client Issue

I have the following codes copied directly from here:
http://www.codeproject.com/Tips/671437/Creating-Web-Service-Using-PHP-Within-Minutes
Server:
<?php
//call library
require_once ('nusoap.php');
//using soap_server to create server object
$server = new soap_server;
//register a function that works on server
$server->register('get_message');
// create the function
function get_message($your_name)
{
if(!$your_name){
return new soap_fault('Client','','Put Your Name!');
}
$result = "Welcome to ".$your_name .". Thanks for Your First Web Service Using PHP with SOAP";
return $result;
}
// create HTTP listener
$server->service($HTTP_RAW_POST_DATA);
exit();
?>
Client:
<?php
require_once ('nusoap.php');
//Give it value at parameter
$param = array( 'your_name' => 'Cool Guy');
//Create object that referer a web services
$client = new soapclient('http://localhost/SOAPServer.php');
//Call a function at server and send parameters too
$response = $client->call('get_message',$param);
//Process result
if($client->fault)
{
echo "FAULT: <p>Code: (".$client->faultcode."</p>";
echo "String: ".$client->faultstring;
}
else
{
echo $response;
}
?>
When I try to access the client page, it shows me the following error:
FAULT: Code: (SOAP-ENV:Client
String: error in msg parsing: xml was empty, didn't parse!
I would only need this simple example working, what could be the problem?

How to connect to two different MySQL DB in the same class

I have this class called dataBase . Looks like this
class dataBase
{
private $conexion;
private $paisConexion;
var $db;
function __construct($db='default')
{
$this->db = $db;
include '../settings/variables.php';
if(isset($bbdd)){
$conexion = mysql_connect($bbdd["server"], $pais[0]['user'], $pais[0]['pass']) or die('No se pudo conectar: '.mysql_error());
// Seleccionamos la base de datos
mysql_select_db($x[0]['database']) or die('No se pudo seleccionar la base de datos');
if($conexion)
{
$paisConexion = mysql_connect($bbdd["server"], $pais[$this->db]['user'], $pais[$this->db]['pass']) or die('No se pudo conectar: '.mysql_error());
mysql_select_db($pais[$this->db]['database']) or die('No se pudo seleccionar la base de datos');
}
}
else{
echo 'El sistema no se pudo conectar a la base de datos.';
exit;
}
}
public function execute($sql)
{
$result = mysql_query($sql) or die("ERROR: Ejecución de consulta: $sql<br>\n");
return $result;
}
}
I am trying to make two connection to two different database using the variable $conexion and $paisConexion .
My question is is it possible to do something like this .
I mean suppose I am creating an object for the class like this
$obj = new dataBase(1);
$res = obj->execute($sql);
So how the the class will decide which of the connection it has to use ? .
I think I am doing this wrong way . If any one has any idea please let me know
Thanks in Advance
It is possible to do something like this, but the approach you have suggested seems very limited to me, so I have taken the liberty to write an alternative using PDO since the mysql_* functions are deprecated. Mysql_* functions official documentation here
By using the PDO class provided by PHP you gain the benefit of parameterized queries and transactions. PDO documentation here
To make it easier for you to add other connections in the future I have written a small class containing the absolutely bare bones. I have left many things such as error handling out for simplicity as this only serves as demonstration.
/*
* DO NOT USE THIS IN PRODUCTION
*/
class DatabaseConnectionManager {
private $connections = [];
public function __construct(array $credentials) {
foreach($credentials as $identifier => $information) {
$this->connections[$identifier] = $this->openConnection(
$information['host'],
$information['database'],
$information['username'],
$information['password']
);
}
}
public function __destruct() {
/* If the object is destroyed before the script closes or is disrupted (fatal errors), we
* destroy all database connections as good practice.
*/
$this->connections = [];
}
public function getConnection($identifier) {
if(!array_key_exists($identifier, $this->connections)) {
throw new LogicException('Unknown database connection: ' . $identifier);
}
return $this->connections[$identifier];
}
private function openConnection($host, $database, $username, $password) {
$dsn = "mysql:host{$host};dbname={$database}";
return new PDO($dsn, $username, $password);
}
}
With this you can supply an array of different database connection information. The usage is like the following.
$credentials = [
'primary' => [
'host' => 'localhost',
'database' => 'number1',
'username' => 'awesome',
'password' => 'secret'
],
];
$connections = new DatabaseConnectionManager($credentials);
To get a connection (PDO object) which can perform different database related task, simply specify a connection identifier with the getConnection() method.
$db = $connections->getConnection('primary');
IMPORTANT
This code is no where near production ready and serve only for demonstration purpose. There is next to no error checking or error handling. If an array with insufficient required parameters is provided you will get an error.
At the same time it is impossible at the current moment to provide options to the PDO object without hard-coding them.
Hope this can help you in the right direction.
You can't create one class for both databases. Unless you pass some parameter that specifies witch connection to use. Also than you must use two different variables for different connections. And don't use deprecated mysql_* functions
class DataBase {
// only private variables accessed by functions
private $localDb, $remoteDb;
// Always use constants instead of magic numbers
const LOCAL = 1, REMOTE = 2
public function _construct() {
$this->localDb= new PDO('mysql:host=localhost;dbname=test', 'username', 'password');
$this->remoteDb= new PDO('mysql:host=remore;dbname=test2', 'username', 'password');
}
// Can't use constants in function header - - - - -v
public function execute($queryString, $params = [], $useDb = 1) {
// static:: will take variable from this class and not from parent class (if extends something)
if ($useDb == static::LOCAL) {
$db = $this->local;
} elseif ($useDb == static::REMOTE) {
$db = $this->remote;
}
$query = $db->prepare($queryString);
// Usage of prepared statement
return $query->execute($params);
}
}
$db = new DataBase();
$db->execute(
'SELECT * FROM table WHERE column = :columnVal', // named placeholders instead of tons of '?'
[':columnVal' => 5], // some parameters
DataBase::LOCAL // Constant from class
);
Save connection to private field and use it in execute:
function __construct($db='default')
{
...
$this->paisConexion = mysql_connect(...
...
}
public function execute($sql)
{
$result = mysql_query($sql, $this->paisConexion);
return $result;
}

SAP and php SOAP COMMIT

I have created a Webservice from a BAPI in SAP to insert some AccountDocuments into SAP. The system in these cases needs a COMMIT-call after a successful insert call. Both of these functions must be called in "one context".
Now I'm facing the problem that I don't know how to do this in php or if there is any way to do this?
I have created the following example, but it doesn't work. The COMMIT function gets executed but it has no impact in SAP. I cannot see the data in the databases, although the first call returns "Data successfully booked". I know that you must confirm this with the COMMIT call in SAP. In SE37 there is a way to put 2 function calls into one Sequence. I'm searching the php-way to do this.
function insertAccntDoc($accntgl, $currAmount, $docHeader, $accntTax)
{
#Define Authentication
$SOAP_AUTH = array( 'login' => SAPUSER,
'password' => SAPPASSWORD);
$WSDL = "url_to_my_wsdl";
#Create Client Object, download and parse WSDL
$client = new SoapClient($WSDL, $SOAP_AUTH);
#Setup input parameters (SAP Likes to Capitalise the parameter names)
$params = array(
'AccountGl' => $accntgl,
'CurrencyAmount' => $currAmount,
'DocumentHeader' => $docHeader,
'AccountTax' => $accntTax
);
#Call Operation (Function). Catch and display any errors
try
{
$result = $client->AcctngDocumentPost($params);
$result = $client->BapiServiceTransactionCommit();
$result->Gebucht = 'Committed';
if(count($result->Return) > 1)
{
$client->BapiServiceTransactionRollback();
$result->Gebucht = 'Rollback';
}
else if($result->Return->item->Type == 'S')
{
try
{
$client->BapiServiceTransactionCommit();
$result->Gebucht = 'Committed';
}
catch(SoapFault $exception)
{
$client->BapiServiceTransactionRollback();
$result->Fehler = "***Caught Exception***<br>".$exception."<br>***END Exception***<br>";
$result->Gebucht = 'Fehler beim Committen';
}
}
}
catch (SoapFault $exception)
{
$client->BapiServiceTransactionRollback();
$result->Fehler = "***Caught Exception***<br>".$exception."<br>***END Exception***<br>";
$result->Gebucht = 'Fehler beim Anlegen';
}
#Output the results
$result->FlexRet = 'insertAccntDoc';
return $result;
}
Thanks!
This link gives details on how to use "stateful" web services. This is required to have a shared session.
http://scn.sap.com/thread/140909

CodeIgniter - how to catch DB errors?

Is there a way to make CI throw an exception when it encounters a DB error instead of displaying a message like:
A Database Error Occurred Error Number: 1054
Unknown column 'foo' in 'where clause' SELECT * FROM (FooBar) WHERE foo = '1'
NOTE: I only want this to happen in one controller. In the other controllers, I'm happy for it to display the DB error messages.
Use error() method:
$this->db->error();
For CodeIgniter 2, you can use the following functions which are now deprecated:
$this->db->_error_message(); (mysql_error equivalent)
$this->db->_error_number(); (mysql_errno equivalent)
Maybe this:
$db_debug = $this->db->db_debug; //save setting
$this->db->db_debug = FALSE; //disable debugging for queries
$result = $this->db->query($sql); //run query
//check for errors, etc
$this->db->db_debug = $db_debug; //restore setting
In Codeigniter 3.0 (CI3), all you have to do is $this->db->error()
If you need to get the last error that has occured, the error() method will return an array containing its code and message
http://www.codeigniter.com/user_guide/database/queries.html#handling-errors
You must turn debug off for database in config/database.php ->
$db['default']['db_debug'] = FALSE;
It is better for your website security.
I know this thread is old, but just in case there's someone else having this issue. This is a trick I used without touching the CI db classes. Leave your debug on and in your error view file, throw an exception.
So in you db config, you have :
$db['default']['db_debug'] = true;
Then in your db error view file, mine is in application/errors/error_db.php replace all content with the following:
<?php
$message = preg_replace('/(<\/?p>)+/', ' ', $message);
throw new Exception("Database error occured with message : {$message}");
?>
Since the view file will be called, the error will always get thrown as an exception, you may later add different views for different environment.
An example that worked for me:
$query = "some buggy sql statement";
$this->db->db_debug = false;
if(!#$this->db->query($query))
{
$error = $this->db->error();
// do something in error case
}else{
// do something in success case
}
...
I have created an simple library for that:
<?php
defined('BASEPATH') OR exit('No direct script access allowed');
class exceptions {
public function checkForError() {
get_instance()->load->database();
$error = get_instance()->db->error();
if ($error['code'])
throw new MySQLException($error);
}
}
abstract class UserException extends Exception {
public abstract function getUserMessage();
}
class MySQLException extends UserException {
private $errorNumber;
private $errorMessage;
public function __construct(array $error) {
$this->errorNumber = "Error Code(" . $error['code'] . ")";
$this->errorMessage = $error['message'];
}
public function getUserMessage() {
return array(
"error" => array (
"code" => $this->errorNumber,
"message" => $this->errorMessage
)
);
}
}
The example query:
function insertId($id){
$data = array(
'id' => $id,
);
$this->db->insert('test', $data);
$this->exceptions->checkForError();
return $this->db->insert_id();
}
And I can catch it this way in my controller:
try {
$this->insertThings->insertId("1");
} catch (UserException $error){
//do whatever you want when there is an mysql error
}
Put this code in a file called MY_Exceptions.php in application/core folder:
<?php
if (!defined('BASEPATH'))
exit('No direct script access allowed');
/**
* Class dealing with errors as exceptions
*/
class MY_Exceptions extends CI_Exceptions
{
/**
* Force exception throwing on erros
*/
public function show_error($heading, $message, $template = 'error_general', $status_code = 500)
{
set_status_header($status_code);
$message = implode(" / ", (!is_array($message)) ? array($message) : $message);
throw new CiError($message);
}
}
/**
* Captured error from Code Igniter
*/
class CiError extends Exception
{
}
It will make all the Code Igniter errors to be treated as Exception (CiError). Then, turn all your database debug on:
$db['default']['db_debug'] = true;
Use it
$this->db->_error_message();
It is better for finding error.After completing your site.
Close the error messages
using it
$db['default']['db_debug'] = FALSE;
You will change it in your config folder's database.php
Disable debugging of errors.
$data_user = $this->getDataUser();
$id_user = $this->getId_user();
$this->db->db_debug = false;
$this->db->where(['id' => $id_user]);
$res = $this->db->update(self::$table, $data_user['user']);
if(!$res)
{
$error = $this->db->error();
return $error;
//return array $error['code'] & $error['message']
}
else
{
return 1;
}
If one uses PDO, additional to all the answers above.
I log my errors silently as below
$q = $this->db->conn_id->prepare($query);
if($q instanceof PDOStatement) {
// go on with bind values and execute
} else {
$dbError = $this->db->error();
$this->Logger_model->logError('Db Error', date('Y-m-d H:i:s'), __METHOD__.' Line '.__LINE__, 'Code: '.$dbError['code'].' - '.'Message: '.$dbError['message']);
}
In sybase_driver.php
/**
* Manejador de Mensajes de Error Sybase
* Autor: Isaí Moreno
* Fecha: 06/Nov/2019
*/
static $CODE_ERROR_SYBASE;
public static function SetCodeErrorSybase($Code) {
if ($Code != 3621) { /*No se toma en cuenta el código de command aborted*/
CI_DB_sybase_driver::$CODE_ERROR_SYBASE = trim(CI_DB_sybase_driver::$CODE_ERROR_SYBASE.' '.$Code);
}
}
public static function GetCodeErrorSybase() {
return CI_DB_sybase_driver::$CODE_ERROR_SYBASE;
}
public static function msg_handler($msgnumber, $severity, $state, $line, $text)
{
log_message('info', 'CI_DB_sybase_driver - CODE ERROR ['.$msgnumber.'] Mensaje - '.$text);
CI_DB_sybase_driver::SetCodeErrorSybase($msgnumber);
}
// ------------------------------------------------------------------------
Add and modify the following methods in the same sybase_driver.php file
/**
* The error message number
*
* #access private
* #return integer
*/
function _error_number()
{
// Are error numbers supported?
return CI_DB_sybase_driver::GetCodeErrorSybase();
}
function _sybase_set_message_handler()
{
// Are error numbers supported?
return sybase_set_message_handler('CI_DB_sybase_driver::msg_handler');
}
Implement in the function of a controller.
public function Eliminar_DUPLA(){
if($this->session->userdata($this->config->item('mycfg_session_object_name'))){
//***/
$Operacion_Borrado_Exitosa=false;
$this->db->trans_begin();
$this->db->_sybase_set_message_handler(); <<<<<------- Activar Manejador de errores de sybase
$Dupla_Eliminada=$this->Mi_Modelo->QUERY_Eliminar_Dupla($PARAMETROS);
if ($Dupla_Eliminada){
$this->db->trans_commit();
MostrarNotificacion("Se eliminó DUPLA exitosamente","OK",true);
$Operacion_Borrado_Exitosa=true;
}else{
$Error = $this->db->_error_number(); <<<<----- Obtengo el código de error de sybase para personilzar mensaje al usuario
$this->db->trans_rollback();
MostrarNotificacion("Ocurrio un error al intentar eliminar Dupla","Error",true);
if ($Error == 547) {
MostrarNotificacion("<strong>Código de error :[".$Error.']. No se puede eliminar documento Padre.</strong>',"Error",true);
} else {
MostrarNotificacion("<strong>Código de Error :[".$Error.']</strong><br>',"Error",true);
}
}
echo "#".Obtener_Contador_Notificaciones();
if ($Operacion_Borrado_Exitosa){
echo "#T";
}else{
echo "#F";
}
}else{
redirect($this->router->default_controller);
}
}
In the log you can check the codes and messages sent by the database server.
INFO - 2019-11-06 19:26:33 -> CI_DB_sybase_driver - CODE ERROR [547] Message - Dependent foreign key constraint violation in a referential integrity constraint. dbname = 'database', table name = 'mitabla', constraint name = 'FK_SR_RELAC_REFERENCE_SR_mitabla'. INFO - 2019-11-06 19:26:33 -> CI_DB_sybase_driver - CODE ERROR [3621] Message - Command has been aborted. ERROR - 2019-11-06 19:26:33 -> Query error: - Invalid query: delete from mitabla where ID = 1019.

Categories