php7-sapnwrfc - RFC PHP 7 的连接器

php7-sapnwrfc 扩展 php7-sapnwrfc扩展提供了一个接口,使用 SAP NetWeaver RFC 库 通过SAP远程函 数调用(RFC)协议调用ABAP功能模块

使用 php7-sapnwrfc, 请按照 快速开始

注解

此文档不断更新,因此始终对应扩展最新的开发版本。

文档

Introduction

php7-sapnwrfc 扩展封装了 SAP NetWeaver RFC 库 并且使用提供的方法允许 PHP开发者调用开启了远程调用的ABAP模块。

如果您没有使用SAP NW RFC SDK的经验,强烈建议您阅读以下文章的文章:

快速开始

下面是调用启用RFC的ABAP模块 STFC_CHANGING 并打印返回值的简单案例:

<?php

use SAPNWRFC\Connection as SapConnection;
use SAPNWRFC\Exception as SapException;

$config = [
    'ashost' => 'my.sap.system.local',
    'sysnr'  => '00',
    'client' => '123',
    'user'   => 'YOUR USERNAME',
    'passwd' => 'YOUR PASSWORD',
    'trace'  => SapConnection::TRACE_LEVEL_OFF,
];

try {
    $c = new SapConnection($config);

    $f = $c->getFunction('STFC_CHANGING');
    $result = $f->invoke([
        'START_VALUE' => 0,
        'COUNTER' => 1,
    ]);

    var_dump($result);
    /*
    * array(2) {
    *   ["COUNTER"]=>
    *   int(2)
    *   ["RESULT"]=>
    *   int(1)
    *   }
    */
} catch(SapException $ex) {
    echo 'Exception: ' . $ex->getMessage() . PHP_EOL;
}

阅读 usage guide ,了解所提供接口的详细说明。

使用场景

至今不是 SAP NW RFC SDK 中所有的功能都在扩展中实现了。基本上,我们区分两种情况:

  • 客户端: 使用PHP代码调用ABAP程序
  • 服务端: 通过ABAP客户端调用PHP代码

目前,扩展只支持客户端场景,即通过PHP调用ABAP函数模块。

当前不支持服务端场景。

在该扩展中其他功能可能也不能使用。如果有特殊需要,随时在GitHub上 打开问题拉取请求

安装

安装 php7-sapnwrfc 扩展包含两部分.

  • 安装 SAP NW RFC 库
  • 在PHP配置文件中启用扩展

安装 SAP NW RFC 库

您可以在http://service.sap.com/rfc-library上找到有关如何编译, 安装和使用SAP NW RFC库的详细说明。

下载 SAP NW RFC 库

Software Center on the SAP ONE Support Launchpad 中下载 SAP NW RFC library.

搜索 SAP NW RFC SDK 7.20 . 下载适合你平台的版本.

Search for SAP NW RFC SDK 7.20

搜索 SAPCAR 7.20 下载 SAPCAR 工具解压SDK.

Search for SAPCAR 7.20

解压类库到文件夹中. 本指南使用``/usr/sap/nwrfcsdk``(在Linux上)或 C:\nwrfcsdk (在Windows上)作为默认路径。您可以自由选择其他目录。如果这样做,请确保在下面的说明中 替换正确的路径。

配置类库文件路径

您必须将*SAP NW RFC 库* 中的 lib 文件配置在系统类库搜索范围内.

Linux

创建文件 /etc/ld.so.conf.d/nwrfcsdk.conf 内容如下:

/usr/sap/nwrfcsdk/lib

之后运行 ldconfig.

Windows

在命令行中执行 set PATH=%PATH%;C:\nwrfcsdk\lib. 这只是临时修改,在命令行窗口关闭后修 改将丢失.

注解

下面操作因为Windows版本不同而不一样.

永久添加类库到PATH环境变量,按一下步骤:

  1. 打开“开始”菜单,然后输入 environment
  2. 选择 Edit the system environment variables or Edit environment variables for your account, depending on whether you want to set the path for the user or the whole system.
  3. Select the PATH environment variable, click Edit and add the path C:\nwrfcsdk\lib.

启用扩展

php.ini 中增加一行:

# for Linux/Unix
extension=sapnwrfc.so

# for Windows
extension=php_sapnwrfc.dll

你可以通过查看 php -m 输出的内容确认扩展是否被加载。显示中应该包含 sapnwrfc.

使用

本指南介绍了 php7-sapnwrfc 扩展的常用功能。有关可用方法的更详细概述,请参阅 API overview

要立即开始使用,请参阅 快速开始

连接SAP系统

连接SAP系统,我们需要传递两个连接参数创建一个 SAPNWRFC\Connection 实例:

<?php
$parameters = [
    'ashost' => 'my.sap.system.local',
    'sysnr'  => '00',
    'client' => '123',
    'user' => 'DEMO',
    'passwd' => 'XXXX',
    // 如果您需要通过saprouter连接,请取消下行注释
    //'saprouter' => '/H/my.saprouter.local/H/',
];

// 连接
$connection = new SAPNWRFC\Connection($parameters);

// 处理

// 关闭连接
$connection->close();

如果连接尝试失败,则抛出 SAPNWRFC\ConnectionException ,其中包含有关错误的详细信息。

我们还可以使用 sapnwrfc.ini 件来指定连接详细信息。有关详细信息,请参阅 API overview 中的 SAPNWRFC\Connection::setIniPath($path)SAPNWRFC\Connection::reloadIniFile()

有关可用的连接参数,请参阅 sapnwrfc.ini参数概述

在使用完连接后,建议使用 SAPNWRFC\Connection::close() 关闭连接。

连接选项

1.2.0 新版功能: SAPNWRFC\Connection 使用了第二个(可选)参数来指定连接。

<?php

$parameters = [ /* <...> */ ];

$options = [
    'use_function_desc_cache' => false,
];

$connection = new SAPNWRFC\Connection($parameters, $options);

可以使用以下选项:

use_function_desc_cache
如果设置为 false ,则在使用 Connection::getFunction() 查找函数之前,将清除本地函数目标缓存。 如:仍在运行时后端功能模块签名发生更改,此时该功能非常有用。因为如果脚本继续使用旧的(缓存的)函数描述, 则会导致垃圾/缺失值。

注解

将此选项设置为 false 可能会导致性能下降,因为每次调用 Connection::getFunction() 时都必须从后端获取函数描述。

参见

有关清除各个功能模块的高速缓存的方法,请参阅 手动清除功能模块描述缓存

默认值: true

调用远程函数模块

查找功能模块

在我们调用远程功能模块之前,我们必须查找所需的函数模块以返回 SAPNWRFC\RemoteFunction 对象。 这是通过 SAPNWRFC\Connection::getFunction($functionName) 方法完成的。我们只需传递远程功能模块的名称:

<?php

$remoteFunction = $connection->getFunction('RFC_PING');

如果查找成功,则返回 SAPNWRFC\RemoteFunction 类型的对象,该对象可用于调用该函数。

如果函数查找失败,则抛出 SAPNWRFC\FunctionCallException 异常。

调用函数模块

在获取到 SAPNWRFC\RemoteFunction 对象之后,我们可以使用 invoke() 方法调用该函数模块。

要调用函数模块 RFC_PING,我们可以简单地调用不带参数的 invoke()

<?php

$returnValue = $remoteFunction->invoke();

如果函数模块有返回值,则调用 invoke() 将会返回它们。发生任何错误上,将抛出 SAPNWRFC\FunctionCallException 异常。

参数和返回值

实际上,大多数远程功能模块都要求我们传递参数和/或在调用后返回参数。

通过使用 $parameters 数组传递可能需要的参数给函数的 invoke() 方法。键是参数的名称,值是要传递的值。

返回值也是如此。如果远程功能模块有返回值,它们将通过 invoke() 返回一个数组。

注解

ABAP功能模块知道四种不同类型的参数:

  • IMPORT: 由客户端设定
  • EXPORT: 由服务端设定
  • CHANGING: 由客户端设定并且可被服务端修改
  • TABLE: 由客户端设定并且可被服务端修改

调用需要传参的函数模块 STFC_CHANGING 以及向调用者返回参数,我们可以执行以下操作:

<?php

$function = $connection->getFunction('STFC_CHANGING');
$result = $function->invoke([
    'START_VALUE' => 0,
    'COUNTER' => 1,
]);

/*
$result looks like this:

array(2) {
  ["COUNTER"] => int(2)
  ["RESULT"] => int(1)
}
*/

参数和返回值的类型映射到标准PHP类型。

参数类型映射

远程功能模块执行ABAP代码,因此使用ABAB数据类型。此扩展在RFC数据类型和内置PHP数据类型之间进行映射,如下所示:

ABAP type RFC type PHP type Meaning Notes
C CHAR string Text field (alphanumeric characters) right-padded with blanks; see rtrim option
D DATE string Date field (format: YYYYMMDD)  
T TIME string Time field (format: HHMMSS)  
X BYTE string Hexadecimal field use hex2bin() to convert to binary
N NUM string Numeric text field  
STRING STRING string String (dynamic length)  
XSTRING BYTE string Hexadecimal string (dynamic length) use hex2bin() to convert to binary
I INT integer Integer INT1 and INT2 are also mapped to integer
P BCD double Packed number / BCD  
F FLOAT double Floating point number  

此外,还有表格和结构:

  • 结构体映射到关联数组,键是字段名称,值是字段值。
  • 内表是个数组结构
调用函数模块时传递可选参数

使用 RemoteFunction::invoke() 调用函数模块时,可以传递第二个参数,指定函数调用的选项。

<?php

// ...
$options = [
    'rtrim' => true
];

$function->invoke($parameters, $options);

可以使用以下选项:

rtrim

在ABAP中,有两种方法可以存储字符串:固定长度字符串类型 C 或动态长度类型 STRING 。当使用 C 类字符串时, 如果字符串短于预定义的长度,则使用空格右边填充字符串。要使用字符串统一扩展行为,可以使用rtrim选项。如果 设置为true,则在返回之前键入 C 字符串进行右边trim。

默认值: false

激活/取消激活参数

在一个函数模块中 SAP NW RFC library 支持激活和取消激活功能模块的参数。如果函数模块具有许多(可能很大的) 您不感兴趣的返回值时,这将非常有用。

要激活或取消激活参数,我们在远程函数对象上调用方法 SAPNWRFC\RemoteFunction::setParameterActive($parameterName, $isActive)。 我们可以使用 SAPNWRFC\RemoteFunction::isParameterActive($parameterName) 来检查参数是否处于活动状态。

<?php

$function = $connection->getFunction('STFC_STRUCTURE');

$function->setParameterActive('IMPORTSTRUCT', false);
$function->setParameterActive('RFCTABLE', false);

$function->isParameterActive('IMPORTSTRUCT'); // returns false

// 在调用函数模块时我们不需要传递参数,
// 因为我们取消激活所有
$result = $function->invoke([]);

// $result will not contain the 'RFCTABLE' parameter

$function->setParameterActive('RFCTABLE', true);
$function->isParameterActive('IMPORTSTRUCT'); // returns true

// we need to pass the 'RFC_TABLE' parameter now
$result = $function->invoke([
    'RFCTABLE' => [],
]);
手动清除功能模块描述缓存

1.3.0 新版功能.

Connection::getFunction() 的调用使用了本地的函数模块描述缓存来加速查找。通常是希望这么做的,但是当脚本在运行时,在 后端修改函数模块签名可能会导致意外结果(缺少/垃圾返回值等)。

除了在连接级别设置 use_function_desc_cache 选项外,还可以使用该函数
\SAPNWRFC\clearFunctionDescCache($functionName, $repositoryId = null) 清除各个函数模块的缓存。
<?php

\SAPNWRFC\clearFunctionDescCache('STFC_STRUCTURE');
// or using the system ID
\SAPNWRFC\clearFunctionDescCache('STFC_STRUCTURE', 'X01');

警告

手动清除函数描述缓存不会影响现有的 RemoteFunction 对象:

<?php

$oldFn = $connection->getFunction('STFC_STRUCTURE');
\SAPNWRFC\clearFunctionDescCache('STFC_STRUCTURE');
$newFn = $connection->getFunction('STFC_STRUCTURE');

// $oldFn 仍然使用旧的功能描述!
函数模块细节
SAPNWRFC\RemoteFunction 对象定义一个 name 属性,该属性包含它所代表的功能模块的名称。

此外,在对象上定义函数模块的每个参数的属性,该属性可用于获取有关参数的详细信息。

Trace 级别

SAP NW RFC library 允许创建跟踪文件以解决连接和/或函数调用问题。

我们可以在建立连接时通过 trace 参数设置所需的跟踪级别,也可以使用 SAPNWRFC\Connection::setTraceLevel($level) 方法随时更改它。

该扩展为 SAPNWRFC\Connection 类定义了四个跟踪级别(从最小到最详细)的常量: TRACE_LEVEL_OFF, TRACE_LEVEL_BRIEF, TRACE_LEVEL_VERBOSE, TRACE_LEVEL_FULL.

此外,我们可以使用 SAPNWRFC\Connection::setTraceDir($path) 为生成的跟踪文件设置目录。跟踪文件的默认位置是当前工作目录。

获取版本

该扩展提供了 SAPNWRFC\Connection::version()SAPNWRFC\Connection::rfcVersion() 方法,用于获取正在使用的扩展版本和RFC SDK版本。

两种方法都返回一个格式为 MAJOR.MINOR.PATCH 的字符串(例如1.1.3);

异常

如果在任何交互期间发生错误,则会引发异常并显示错误详细信息。目前,有两个异常类:

  • SAPNWRFC\ConnectionException 用于与连接本身有关的任何错误。
  • SAPNWRFC\FunctionCallException 用于源自函数模块调用的错误。

这两个异常类都扩展了基本异常类 SAPNWRFC\Exception ,它为 RuntimeException 提供的标准方法和属性添加了一个 额外的 getErrorInfo() 方法。

getErrorInfo() 返回一个包含详细错误信息的数组,至少包含 code, keymessage.

根据错误类型,在详细信息中以下额外的键可能被使用: abapMsgClass, abapMsgType, abapMsgNumber, abapMsgV1, abapMsgV2, abapMsgV3, abapMsgV4.

API

<?php

/**
 * This is a stub file of the extensions public interface to enable
 * code completion in IDEs.
 */
namespace SAPNWRFC;

die('This file is intended for IDE parsers and should not be included.');

/**
 * Clear the function desc cache for $functionName.
 * 
 * Clears the default repository. If $repositoryId is passed, the cache
 * repository matching $repository is cleard as well.
 * 
 * @since 1.3.0
 * 
 * @param string $functionName Function name.
 * @param string $repositoryId The cache repository to use. Defaults to null.
 *                             If passed, the repository is cleared in addition
 *                             to the default repository.
 * 
 * @return bool True if the call succeeded (this does not necessarily mean
 *              that a cache entry was found).
 * 
 */
function clearFunctionDescCache(string $functionName, string $repositoryId = null): bool {}

class Exception extends \RuntimeException
{
    /**
     * Detailed RFC/ABAP error information.
     *
     * $errorInfo contains at least the "code", "key" and "message" keys from
     * the RFC library.
     * If the error is an ABAP error, the following additional keys are
     * available:
     *    "abapMsgClass", "abapMsgType", "abapMsgNumber", "abapMsgV1",
     *    "abapMsgV2", "abapMsgV3", "abapMsgV4"
     *
     * @var array
     */
    protected $errorInfo;

    /**
     * Getter for the errorInfo property.
     *
     * @returns array|null
     */
    public function getErrorInfo(): array {}
}

class ConnectionException extends Exception {}

class FunctionCallException extends Exception {}

class Connection
{
    const TRACE_LEVEL_OFF = 0;
    const TRACE_LEVEL_BRIEF = 1;
    const TRACE_LEVEL_VERBOSE = 2;
    const TRACE_LEVEL_FULL = 3;

    /**
     * Connect to the system using the given parameters.
     *
     * @param array $parameters Connection parameters (see `sapnwrfc.ini` documentation for supported keys)
     * @param array $options Additional options {
     *      @var bool $use_function_desc_cache Use function desc cache (defaults to `true`)
     * }
     *
     * @throws ConnectionException if the connection fails.
     */
    public function __construct(array $parameters, array $options = []) {}

    /**
     * Get the connection attributes.
     *
     * @return array Array of connection attributes.
     *
     * @throws ConnectionException if the connection attributes could not be
     *                             fetched.
     */
    public function getAttributes(): array {}

    /**
     * @return bool True if ping successful.
     *
     * @throws ConnectionException if the ping failed.
     */
    public function ping(): bool {}

    /**
     * Lookup a RFC function and return a RemoteFunction object.
     *
     * @param string $functionnName Name of the function.
     *
     * @return RemoteFunction A RemoteFunction class for the RFC function.
     *
     * @throws FunctionCallException if the lookup fails or an error is
     *                               returned during parameter parsing.
     */
    public function getFunction(string $functionName): RemoteFunction {}

    /**
     * Close the connection.
     *
     * @return bool True if the connection was closed, false if the connection
     *              is closed already.
     *
     * @throws ConnectionException if the connection could not be closed.
     */
    public function close(): bool {}

    /**
     * Sets the path to the sapnwrfc.ini file.
     *
     * By default, the INI file is searched for in the current directory.
     *
     * @param string $path Path to the sapnwrfc.ini file.
     *
     * @return bool True if path was set.
     *
     * @throws ConnectionException if path could not be set.
     */
    public static function setIniPath(string $path): bool {}

    /**
     * Reload the INI file.
     *
     * Searches for the INI file either in the path set by
     * Connection::setIniFile() or in the current directory.
     *
     * @return bool True if INI file was reloaded.
     *
     * @throws ConnectionException if the INI file could not be reloaded.
     */
    public static function reloadIniFile(): bool {}

    /**
     * Set trace directory.
     *
     * @param string $path Path to trace directory (must exist).
     *
     * @return bool True if path was set.
     *
     * @throws ConnectionException if path could not be set.
     */
    public static function setTraceDir(string $path): bool {}

    /**
     * Set trace level.
     *
     * @param int $level Trace level.
     *
     * @return bool True if level was set.
     *
     * @throws ConnectionException if level could not be set.
     */
    public static function setTraceLevel(int $level): bool {}

    /**
     * Get the extension version.
     *
     * @return string The extension version.
     */
    public static function version(): string {}

    /**
     * Get the RFC SDK version.
     *
     * @return string The RFC SDK version.
     */
    public static function rfcVersion(): string {}
}

class RemoteFunction
{
    /**
     * Invoke the RFC function.
     *
     * @param array $parameters Function parameters.
     * @param array $options Additional invoke options {
     *      @var bool $rtrim Right trim CHAR field values.
     * }
     * @return array Return value from the backend.
     *
     * @throws FunctionCallException if any error occurs during execution.
     */
    public function invoke(array $parameters = [], array $options = []): array {}

    /**
     * Make a parameter active or inactive.
     *
     * @param string $parameterName The parameter to modify.
     * @param bool   $isActive      True to activate the parameter, false to deactivate.
     *
     * @throws FunctionCallException if the parameter status could not be set.
     */
    public function setParameterActive(string $parameterName, bool $isActive) {}

    /**
     * Check if a parameter is active or inactive.
     *
     * @param string $parameterName The parameter to check.
     *
     * @return bool True if parameter is active, false if not.
     */
    public function isParameterActive(string $parameterName): bool {}
}

源码编译

在尝试编译扩展前,确认 SAP NW RFC library 已经安装了。 相关说明,请参阅安装 安装 SAP NW RFC 库

在Linux上编译

$ git clone https://github.com/gkralik/php7-sapnwrfc.git
$ cd php7-sapnwrfc
$ phpize
$ ./configure
$ make
$ sudo make install

默认情况下,构建脚本在以下位置查找 SAP NW RFC library :

/usr/sap/nwrfcsdk
/usr/local/sap/nwrfcsdk
/usr/local/nwrfcsdk
/opt/nwrfcsdk

如果你安装类库文件在另一个路径,用 ./configure 替换 ./configure --with-sapnwrfc=/path/to/rfc-library.

在Windows上编译

我们为Windows用户提供了预编译扩展(请参阅`发布页面 <https://github.com/gkralik/php7-sapnwrfc/releases>`_ ). 如果你没有找到你要的版本或者仍然希望自己编译,按照以下说明操作。

设置编译环境

确认你有一个可用 和这里一样的构建环境

在你配置完环境后,可以尝试自己编译PHP:

$ configure --disable-all --enable-cli
$ nmake
$ nmake snap

如果运行成功,你可以继续。如果不是,双击检查你的编译环境。

编译扩展

确认你没有混淆 x86/x64 ( PHP 和 SAP NW RFC library 平台必须匹配)。

注解

1. 本指南假设您要构建x64版本。 2.我们还假设SDK文件位于 C:nwrfcsdk中

C:\nwrfcsdk\include 中的所有头文件 (*.h) 复制到 C:\php-sdk\phpdev\vc14\x64\deps\include. 将 C:\nwrfcsdk\lib 中所有库文件 (*.lib) 复制到 C:\php-sdk\phpdev\vc14\x64\deps\lib.

下载最新扩展并解压到 C:\php-sdk\phpdev\vc14\x64\php-7.0-src\ext\sapnwrfc

打开VS2015的开发人员命令提示符,然后按照PHP Windows逐步构建页面中的说明执行步骤1-4的命令。 打开 VS2015的开发人员命令窗口 ,然后按照 PHP Windows逐步构建页面 中的说明执行步骤1-4的命令。

必须使用以下命令之一替换配置命令(步骤6)(这具体取决于您要构建的版本):

然后继续步骤7-9。

如果您构建了共享扩展,则扩展文件应位于以下位置之一:

贡献

非常欢迎对项目的贡献(通过报告/修复错误,编写文档,帮助测试)。只需在GitHub上打开一个 打开一个问题一个拉取请求

版权信息

该软件遵循 MIT 协议:

The MIT License (MIT)

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

法律声明

此处提及的SAP和其他SAP产品和服务是SAP SE(或SAP关联公司)在德国和其他国家/地区的商标或注册商标。