Conexion PHP y SAP


#1

Hola buen dia comunidad quiero ver si alguno de ustedes tendra algun tipo de experiencia con conectar PHP con SAP, aparentemente la conexion es lo mas facil pero vaya que va a dado un verdadero dolor de cabeza, les comento:
Descargue las librerias y los DLL llamados saprfc-1.4.1.

El dll librfc32.dll lo coloque en C:\Windows\System32 ademas en mi carpeta del AppServ/php5/ext coloque el archivo php_saprfc_530.dll y posteriormente en mi archivo php.ini actualice lo actualice con la linea extension=php_saprfc_530.dll.

Reinicie mi servidor y nada no jala la libreria me manda el siguiente error:

Fatal error: Call to undefined function saprfc_open() in C:\AppServ\www\bnon\prueba.php line 31

Mis caracteristicas de mi servidor son las siguientes:

The AppServ Open Project - 8.1.0 for Windows
Now you running on PHP 5.6.18
Apache Web Server Version 2.4.18
PHP Script Language Version 5.6.18 & 7.0.3
MySQL Database Version 5.7.10
phpMyAdmin Database Manager Version 4.5.4.1

Alguien sabra como le puedo hacer para que mi servidor detecte la libreria.

De antemano muchas gracias, y si en el transcurso logro algo, sin duda alguna lo compartire con la comunidad en un tutorial, vaya que el tema es interesante.

Saludos.


#2

A lo mejor es tonta la pregunta, ¿pero registraste las librerías?


#3

Si ya la registre en el archivo php.ini, o en otro lado la tengo que registrar :smiley:


#4

Tendrias que registrarlas en Windows, para que las reconozca.

Registrar un OCX o DLL de 32 bits en un sistema de 32 bits
Este es el método más extendido pero claro solamente funciona con sistemas operativos de 32 bits

1º- Tenemos que copiar el archivo de la librería en la ruta C:\WINDOWS\System32\

2º- Abrimos la consola de Windows (CMD) como administrador (botón derecho, ejecutar como administrador) y escribimos:

cd C:\WINDOWS\System32
3º- Una vez copiado para registrar la librería:

regsvr32.exe C:\WINDOWS\System32\NOMBRE_ARCHIVO.OCX
Y listo ya está la librería registrada en el sistema.

Registrar un OCX o DLL de 32 bits o 64 bits en un sistema de 64 bits
Es un poco diferente del modo de registrarlo en 32 bits, aunque sólo son las carpetas las que cambian (no válido para sistemas operativos de 32 bits)

1º- Tenemos que copiar el archivo de la librería en la ruta C:\WINDOWS\SysWOW64\

2º- Abrimos la consola de Windows (CMD) como administrador (botón derecho, ejecutar como administrador) y escribimos:

cd C:\WINDOWS\SysWOW64
3º- Una vez copiado para registrar la librería:

regsvr32.exe C:\WINDOWS\SysWOW64\NOMBRE_ARCHIVO.OCX
Y listo ya está la librería registrada en el sistema.

ht_p://www.mancera.org/2014/07/27/registrar-un-archivo-ocx-o-dll-en-windows-7-8-8-1-x86-y-x64/


#5

Listo ese paso lo habia omitido por completo ya registre la libreria y me salio un mensaje de que habia sido registrada exitosamente.

Reinicio mi servidor apache hasta inclusive la maquina y nada :frowning: , en que estaré fallando


#6

Yo de Php muy poco, pero … leíste esto?


¿Capaz ahí salga como conectan?


#7

Saludos a tod@s en el foro!

Amigo @Alvan1 te recomiendo que en lugar de utilizar la libreria php-saprfc, desarrolles un webservice en java utilizando SAP Java Connector 3.0 (JCo3) para la interface con R/3. Este conector JCo3 es provisto y recomendado por la mismisima SAP AG. Este esquema de conectividad que te planteo esta mas que probado, yo particularmente lo he implementado en n aplicativos que estan en productivo actualmente.

En su momento, hace 2 años aproximadamente, se trato de utilizar el conector php-saprfc-1.4.1 en un proyecto y fue desechado casi de inmediato por los problemas de configuracion e inestabilidad de conexión que presentaba, investigamos mas a fondo y nos dimos cuenta que la ultima actualizacion de la libreria habia sido en el año 2011, una libreria con 3 años sin actualizaciones es practicamente un proyecto que se dejo abandonado.

Ahora que @SidV coloco el link en git de la libreria es que me doy cuenta que al parecer retomaron el proyecto. Me voy a tomar como tarea probarla nuevamente a ver que tal.

Prueba la solución que te propuse, te garantizo que funciona bien. Ademas por tratarse de un webservice, vas a crear una solución mas abierta, basada en estandares y reutilizable desde cualquier plataforma.

Hasta te puedes ganar un punto extra por su implementación :thumbsup:


#8

Hola @Alvan1 yo realice la conexión de PHP con SAP, te comento lo que necesitas es lo siguiente:
Nota: toma encuenta si tu server es a 32 o 64

  1. El archivo Librfc

  2. php_saprfc_php5.6_ts.dll en tu caso por la version de tu PHP.

  3. Abrir el archivo php.ini (que se encuentra en c:\xampp\php\php.ini)y agregar el dll dentro del archivo donde se encuentran las “extension= …” ejemplo:
    extension=php_saprfc_php5.6_ts.dll

  4. Debes de crear una funcion RFC en sap, con tus tablas o estructuras correspondientes.

  5. Crear una “Funcion en PHP” donde hagas la conexión a SAP (tomando en cuenta el envio de parametros a tu función y elementos entrantes a la misma).

  6. El archivo que generes PHP se apoya de “otro” PHP el cual contiene librerias para la conexión.

En mi caso, lo implementé en una INTRANET usando XAMPP, cualquier duda o comentario hazlo saber o comunicate conmigo.

Saludos y suerte.


#9

Este sería el código del archivo PHP donde llamarias a la funcion RFC de SAP …en mi caso:

<html>
<body>
<h1>CONEXIÓN SAP_PHP</h1>
<?PHP

    // aqui en esta parte incluyes el archivo donde tendras las librerias que pondré más aabajo
    require_once("saprfc.php");
 
    // Create saprfc-instance
    $sap = new saprfc(array(
            "logindata"=>array(
            "ASHOST"=>"10.10.10.10"		// application server
            ,"SYSNR"=>"Numero de sistema"	/ system number
            ,"CLIENT"=>"Cliente"			// client
            ,"USER"=>"USUARIO DE ACCESO A SAP"			// user
            ,"PASSWD"=>"Password"		// password
            )
            ,"show_errors"=>false			// let class printout errors
            ,"debug"=>false)) ; 				// detailed debugging information
 
    // Call-Function
    $result=$sap->callFunction("NOMBRE_DE_TU_FUNCION",
            array(	array("IMPORT","EL_NOMBRE_DEL_IMPORT_DE_TU_FUNCION","*"),
            array("TABLE","TABLE_DE_TU_FUNCION",array())
            ));
 
    // Si se realizo el llamado a la funcion correctamente
    if ($sap->getStatus() == SAPRFC_OK) 
    {
        // Entonces imprimes tus resultados....
        ?><table>
            <tr>
            <td>Nombre</td>
            <td>Numero De Usuario</td>
            </tr>

     <?PHP
 
        foreach ($result["USER_DISPLAY_TAB"] as $user) 
        	{
            echo "<tr>
            	  <td>", $user["SAPNAM"],"</td><td>",$user["USRNO"],"</td> //Elementos o Campos de tu estructura o tabla
            	  </tr>";
        	}
 
        ?></table><?PHP
    } 
		    else 
		    	{
		        // Si no se realizo la conexión a la funcion RFC
		        $sap->printStatus();
		        // Imprimes el mensaje de error
		        // 		$sap->getStatusText() or $sap->getStatusTextLong()
		    	}
 
    // Logoff/Cerrar SAP RFC
    $sap->logoff();
?>
</body>
</html>

Y este seria tu archivo saprfc.php donde contendrías las librerias…y lo incluirás en el codigo anterior que te pase…

<?PHP


// For easy checking of BAPI-type values
if (!defined("SAPRFC_OK")) define("SAPRFC_OK",0);
if (!defined("SAPRFC_ERROR")) define("SAPRFC_ERROR",1);
if (!defined("SAPRFC_APPL_ERROR")) define ("SAPRFC_APPL_ERROR",2);


class saprfc {

	var $logindata;
	var $rfc_conn;
	var $func_id;
	var $show_status_flag;
	var $check_bapi_errors;
	var $status;
	var $status_infos;
	var $debug;
	var $call_function_result;

	function saprfc($config=array()) {
		$this->rfc_conn=false;
		$this->func_id=false;
		$this->show_status_flag=isset($config["show_errors"]) ? $config["show_errors"] : true;
		$this->check_bapi_errors=isset($config["check_bapi_errors"]) ? $config["check_bapi_errors"] : false;
		$this->status="";
		$this->status_infos="";
		$this->debug=isset($config["debug"]) ? $config["debug"] : false;
		$this->logindata=isset($config["logindata"])?$config["logindata"]:array();
		$this->call_function_result=false; // Result of the last executed sapaccess-call_function()
	}
	
	function setLoginData($logindata) {
		$this->logindata=$logindata;
	}

	// TODO: currently only login with logindata allowed
	// that means you have to set logindata for the class on creation
	// maybe we can use setcookie ("SAPRFC_LOGON", urlencode(serialize($this->logindata)),time()+7200);	
	function login() {
	   	if (!$this->rfc_conn)
	   	{
		   	$this->rfc_conn=@saprfc_open($this->logindata);
			if (!$this->rfc_conn) {
				return $this->setStatus(SAPRFC_ERROR,"saprfc::login()\nOpen RFC connection with saprfc_open() failed with error:\n".@saprfc_error());
			}
		}
		return SAPRFC_OK;
	}

	// Close RFC_Connection	
	function logoff() {
	   	if ($this->rfc_conn)
	   	{
			@saprfc_close($this->rfc_conn);
		}
	}

	// set Status and optionally show Errors
	function setStatus($status,$status_infos) {
		$this->status=$status;
		$this->status_infos=$status_infos;
		if ($this->show_status_flag &&
			$this->status!=SAPRFC_OK ) {
			$this->printStatus();
		}
		return $this->status;
	}		
	
	// Checks if last Call succeded
	function getStatus() {
		return $this->status;
	}
	
	// Returns actual Status/Error
	function getStatusText() {
		$statustext="";
		switch ($this->status) {
			case SAPRFC_OK:
				$statustext=$this->status_infos;
				break;
			case SAPRFC_APPL_ERROR:
				$statustext=$this->status_infos["TYPE"]." ".$this->status_infos["ID"]."-".$this->status_infos["NUMBER"].": ".$this->status_infos["MESSAGE"];
				break;
			case SAPRFC_ERROR:
				$statustext=$this->status_infos;
				break;
		}
		return $statustext;
	}

	// Returns actual Status/Error
	function getStatusTextLong() {
		$statustext="";
		switch ($this->status) {
			case SAPRFC_OK:
				$statustext.="<br><font size=4 color=green><pre>";
				$statustext.="No errors detected.";
				$statustext.="</font><br><font size=3 color=green><pre>";
				$statustext.="<br><b>".$this->getStatusText()."</b>";
				$statustext.="</pre></font>";
				break;
			case SAPRFC_APPL_ERROR:
				$statustext.="<br><font size=4 color=red><pre>";
				$statustext.="Application-Errors found during BAPI-Calls:";
				$statustext.="</font><br><font size=3 color=red><pre>";
				$statustext.="<br><b>".$this->getStatusText()."</b>";
				$statustext.="</pre></font>";
				break;
			case SAPRFC_ERROR:
				$statustext.="<br><font size=4 color=red><pre>";
				$statustext.="Errors found during saprfc-Calls:";
				$statustext.="</font><br><font size=3 color=red><pre>";
				$statustext.="<br><b>".$this->getStatusText()."</b>";
				$statustext.="</pre></font>";
				break;
		}
		return $statustext;
	}

	function printStatus() {
		echo $this->getStatusTextLong();
	}		
	
	// Call RFC-Function in SAP		
	function callFunction($func_name="",$parameters) {
		/* typical call:
			$result=$saprfc->call_function("RFC_SYSTEM_INFO",
									array(	array("EXPORT","SYSTEM","MBS")
											array("IMPORT","CODEPAGE")
											array("IMPORT","DBNAME")
											array("TABLE","APPLLIST",array())
									)
								);
		*/
		
		// Initialize Variables
		$result_data=array();
		$this->call_function_result=false;
						
		// Check SAPRFC-Installation
		if (! extension_loaded ("saprfc")) {
			return $this->setStatus(SAPRFC_ERROR,"saprfc::callFunction()\n SAPRFC-Extension.dll not loaded.");
		}
		
		// Validate given data
		if (empty($func_name)) {
			return $this->setStatus(SAPRFC_ERROR,"saprfc::callFunction():\n No Function-Name given");
		}
		
		// Move Parameters to local Arrays
		$func_params_import=array();		
		$func_params_tables=array();
		$func_params_export=array();
		foreach ($parameters as $key => $param) {
			$type=$param[0];
			$name=$param[1];
			$value=isset($param[2])?$param[2]:"";
			switch ($type) {
				case "IMPORT":
					$func_params_import[$name]=$value;
					break;
				case "EXPORT":
					$func_params_export[$name]="";
					break;
				case "TABLE":
					$func_params_tables[$name]=$value;
					if (!is_array($value)) {
						return $this->setStatus(SAPRFC_ERROR,"saprfc::callFunction()\n Wrong Parameter-Value for Table-Parameter ".$name.". We expected an Array.");
					}
					break;
				default:
					return $this->setStatus(SAPRFC_ERROR,"saprfc::callFunction()\n Wrong Parameter-Type '".$type."'. Must be IMPORT, EXPORT or TABLE.");
			}
		}
		
		// Do Login (only done in method login(), if necessary)	
		if ($this->login()==SAPRFC_ERROR) {
			return $this->getStatus();
		}
		
		// Discover Function in SAP
		$this->func_id=@saprfc_function_discover($this->rfc_conn,$func_name);
		if (!$this->func_id) {
			return $this->setStatus(SAPRFC_ERROR,"saprfc::callFunction()\n Function module '".$func_name."' seems not to exist. function saprfc_function_discover() failed.");
		}

		// Set Import-Parameters		
		foreach ($func_params_import as $name => $value) {
			$rc=@saprfc_import($this->func_id,$name,$value);
			if (empty($rc)) {
				return $this->setStatus(SAPRFC_ERROR,"saprfc::callFunction('".$func_name."')\n Import-Parameter=".$name. " could not be set. (Does it exist?)");
			}
		}
		// Set Table-Parameters	(importing-values)
		foreach ($func_params_tables as $name => $value) {
			$rc=@saprfc_table_init($this->func_id,$name);
			if (empty($rc)) {
				return $this->setStatus(SAPRFC_ERROR,"saprfc::callFunction('".$func_name."')\n Table-Parameter=".$name. " could not be set. (Does it exist?)");
			}
			foreach ($value as $key => $data) {
				@saprfc_table_append($this->func_id,$name,$data);
			}
		}

		// Execute Function
		$result = @saprfc_call_and_receive ($this->func_id);
		if ($result != SAPRFC_OK)
		{
			if ($result == SAPRFC_EXCEPTION ) {
				return $this->setStatus(SAPRFC_ERROR,"saprfc::callFunction('".$func_name."')\n saprfc_call_and_receive(): Exception raised: ".@saprfc_exception($this->func_id));
			} else {
				return $this->setStatus(SAPRFC_ERROR,"saprfc::callFunction('".$func_name."')\n saprfc_call_and_receive(): Call error: ".@saprfc_error($this->func_id));
			}
		}
	   
		// Get Exporting-Parameters
		foreach ($func_params_export as $name =>$value) {
			$rc=@saprfc_export($this->func_id,$name);
//			if (empty($rc)) { // llaegner removed (Reason: when export returns the -good- value "0", then empty also evaluates to true (thanks Alexander Gouriev)
			if (!isset($rc)) {
				return $this->setStatus(SAPRFC_ERROR,"saprfc::callFunction('".$func_name."')\n Export-Parameter=".$name. " could not be set (Does it exist?)".@saprfc_error($this->func_id));
			} else {
				$result_data[$name]=$rc;
			}
		}

		// Get Table-Parameters
		foreach ($func_params_tables as $name => $content) {
			// Ausgabe-Tabelle initialisieren
			$result_data[$name]=array(); 
			$rows=@saprfc_table_rows($this->func_id,$name);
			for ($i=1; $i<=$rows; $i++)
			{
				$result_data[$name][$i]=@saprfc_table_read ($this->func_id,$name,$i);
			}
		}

		// Save function-call result for later analysis
		$this->call_function_result=$result_data;
		
		// Echo Debug-Information, if flagged
		if ($this->debug)
			@saprfc_function_debug_info($this->func_id);
			
		// Falls es ein BAPI-Aufruf ist, Fehler raussuchen
		if ($this->check_bapi_errors) {
			$bapi_return=@saprfc_export($this->func_id,"RETURN");
			if (isset($bapi_return) && 
					is_array($bapi_return) && 
					isset($bapi_return["MESSAGE"]) && 
					$bapi_return["NUMBER"] != 0) {
					
				// FINISH FUNCTION-CALL
				$this->setStatus(SAPRFC_APPL_ERROR,$bapi_return);
				return $result_data;	
			}
		}
		// Close Function-Execution and free results removed because it sometimes stops completly executing PHP!!
		//@saprfc_function_free($this->func_id);
		
		// FINISH FUNCTION-CALL
		$this->setStatus(SAPRFC_OK,"call function '".$func_name."' successfull.");
		return $result_data;	
	}
	
}

?>

#11

Si van a compartir muchas lineas de código, me parece mejor que usen https://gist.github.com/
Donde podrían hasta “folkear-se” entre ustedes :slight_smile: y pegan aquí directamente la URL del GIST, y queda compartida en el tema :thumbsup:


Volviendo al tema.
No les sirve esto?


#12

Gracias…haré uso de ello¡¡¡ saludos


#13

Una disculpa de antemano por haberme ausentado de este tópico fue por razones laborales, les comento aun sigo sin poder realizar dicha conexión :frowning: pero el fin me dare la tarea de crear una maquina virtual para ahí montarle lo necesario en SO Linux con estas características kernel 2.6.25.18-0.2-pae i686.

Ya que al parecer todo esta mas orientada a hacerlo dentro de ese sistema. Agradecerles a todos por sus comentarios.

Gracias @marciano por lo que comentas, aquí el tema es que el sistema vive sea creo y ya está implementado en PHP y ahora lo que quieren hacer es darle ese plus con la interconexión a SAP, seria volver a reprogramar todo a JAVA EE y montar los JCO que como bien dices es lo mas idóneo y por WS pues que te digo así lo trabajamos en su momento en su momento en el INFONAVIT pero este cliente es nuevo y se aferró a hacer todo desde PHP y ahora si que al cliente lo que pida, pero de todos modos muchas gracias.

@iespino gracias por tus comentarios en la VM que cree me apegare a usar el XAMPP, nadamas tengo una duda en que S.O. montaste el XAMPP ?

E igualmente @Shadowdancer y @SidV como siempre respondiendo, sus guías me va a ayudar a terminar esta encrucijada que al final tiene que salir si o si

Muchas muchas gracias.
Saludos.


#14

Y has investigado si SAP comparte Web-Services para consumirlos?. Yo no se mucho del tema pero aqui donde laboro lo poco que conozco es que SAP lo único que entrega son archivos de texto, supongo usando ABAP para alimentar otros sistemas…


#15

El sistema operativo donde monte el XAMPP fue Windows Server 2008


#16

@Alvan1 Lograste resolver este problema?


#17

No estimado con la librería nunca se pudo, lo que se hizo puros consumos de wsdl para la extracción de información. Pero pues solo así se pudo


#18

Lo que pasa es que yo lo logré hacer en 2 servidores con windows server 2008, y estoy tratando de implementar en un windows server 2016 y es en el que me da ese error, no se si sea el lenguaje. Ya cambie el SAP Logon, y tampoco. :slight_smile: Alguien del grupo @Abapers sabe sobre el tema?


#19

Buen día, tengo varios semanas tratando de instalar el php_saprfc_php5.6_ts en windows 2008 x64 y no se puede, alguien pudo con esto?, seguí todos los pasos y nada


#20

te sale algún mensaje de error? tienes que buscar el dll correcto para tu versión de apache. que versión tienes?


#21

Version de Apache/2.4.26 (Win32) OpenSSL/1.0.2l PHP/5.6.31