Archive for the 'SAP' Category

Personal news update Nov/06

Wednesday, November 1st, 2006

So what I've been up to recently? Having a bit of a break, I guess. First, I'm not currently writing a book, after the last one for which I completed my chapter back in June. That's some free time (There is a very exciting book project on the horizon though, we'll see). Then, I'm not working so much on our new house. Now (August) that my family is back from Bulgaria, and the two little princesses are running around, it's next to impossible to do any construction work, however small.

I changed my job not so long ago, I'm working for SAP now, here in good old Old Montreal. Meeting smart people every day and learning new things, SAP has quite a bit going on and there's always something to learn. Take the proprietary ABAP programing language for one.

As always a PHP junkie, I looked into what's possible in terms of integration of PHP and SAP. Turns out it's possible and it's fun. There is this open-source SAPRFC PHP extension, that allows you to use PHP to connect to an SAP system and do stuff. Out of this interest a few things happened:

  • I published an article at the International PHP Magazine about a tool (or more like a collection of tools), called Scripting In A Box which is developed at SAP. It's one big archive (as in ZIP) which you unpackage to your C:\ drive and you get Apache, MySQL, PHP(+SAPRFC), Perl, Ruby/ROR, Python, Eclispse(+PHPEclipse), all pre-configured and running together. So you can start scripting in minutes. This tool actually gave me a chance to try out and love PHPEclipse, something I've missed, being so attached to my TextPad and ignoring any other way to do PHP. Now I can highly recommend PHPEclipse as a PHP IDE.
  • Next, some folks at SAP (Thanks Craig, AndrĂ©!) recognized my PHP experience and asked me to do a little demo of SAP+PHP at SAP's big event, called TechEd in Las Vegas. This was quite an experience! Las Vegas is one different place and the conference itself was pretty big with 5000 people, I think. I had a chance to meet guys from SDN (SAP Developers Network), which is quite a vivid community with something like half a million members. You know what's the everage response time when you post a question on the SDN forums? 7 minutes.
  • Then, I wrote another article for IPM, which described the demo I did at TechEd. (I'll add the source code and some screenshots at the bottom of this post.)
  • I also contributed one new container for the PEAR::Auth package, it allows you to authenticate users against an SAP system in your PHP app.
  • Another contribution to PEAR was the ABAP language definition for the Text_Highlighter package
  • Finally, I did a little ABAP console, but I'll blog about it seperately and will share the code, of course.
  • ... and my first posting on SDN was published today. The next one will be a sort of a cross-post here and on SDN about the ABAP console thingie.

I think that's about it for SAP. Otherwise, as usual, I get easily excited by different things, so I've been doing this and that, here and there, on my own terms, relaxing, without any deadlines preasure.

On the pipeline, I have a bit of stuff to do, again, small little things I enjoy doing, like helping with one article for the PEAR::MDB2 manual, assembling an extra intro chapter for the PEAR book, helping out with Text_Highlighter (I'm this package's official helper since a few days ago), also doing some work for the Image_Text PEAR package, as well as anything else that comes into the radar any given day. Yeah, this is how I understand relaxation, doing whatever you're passionate about, even if this means less sleep at night. Ah, and I have the test for Canadian citizenship tomorrow, so I should be reading as opposed to writing now (I always do this, the busier I am, the more interesting things I "shoehorn")

SAPRFC/PHP demo files

Yeah, the demo app uses YUI and a bit of AJAX and animation to make it a bit sexier.

 

ABAP code syntax highlighting

Tuesday, September 19th, 2006

Just finished and eager to share - I added a new syntax definition to the Text_Highlighter PEAR package (see also here). It's for highlighting code written in the SAP's own ABAP programming language.

A live demo is available at the hiliteme.com site, just pick ABAP from the drop-down of programming languages. Any feedback is appreciated, because it's a brand new thing and may have bugs or incompletenesses (is that a word?). So feel free to highlight your ABAP code and post it to blogs or forums.

The implementation wasn't hard, the Text_Highlighter package is made to be extended and even provides the tools for that. All you need to do is create an XML file that contains keywords and other syntax rules, such as formats of the comments and so on. Then there is a command line tool that takes the XML file and generates a class out of it. The class is later on used when highlighting. Here's the XML file in case you want to improve on it and generate your own ABAP.php class:

 

SAP container for PEAR::Auth

Friday, September 1st, 2006

PEAR::Auth is a package that allows you to abstract the user authentication from the main part of your application and not worry about it. What is good about the package is that it comes with different "containers" that allows you to authenticate users against different storages, I mean you can store users data in a database and use the PEAR::DB or PEAR::MDB2 containers, or you can use flat files, IMAP servers, SOAP and what not. And the package is easily extensible. So I played around with creating an SAP container that allows you to check users against your company's SAP system and for example build a section of your Internet (or Extranet) page that is only accessible for people and partners that exist as users in the SAP system.

In order to connect to an SAP system with PHP you need the SAPRFC PHP extension. Get it here. Then you use the function saprfc_open() (more docs here) to establish a connection. You provide some info about the SAP system as well as your username/password. Once connected, a so-called "SSO ticket" is generated for you. This is just a long string, like a session ID. For consecutive connections you can use this SSO ticket instead of providing username/password every time. BTW, SSO stands for Single Sign-On.

Now, with my little SAP container you can benefit from the PEAR and PEAR::Auth infrastructure to do the logins. The way to do an authentication is simple (example stolen in parts from this PEAR manual entry). You pass the connection options (such as hostname). Then, once the user is authenticated, the container retrieves the SSO session ID and sticks into the Auth session data, so that it's reusable for consecutive connections within the same session. If you need to do more with the SAP system, apart from authenticating users, you can get back the updated connection options and just pass them to saprfc_open(). Here's an example:

<?php
// get Auth lib
require_once "Auth.php";
 
// SAP connection options
$options = array (
    'ASHOST'    => 'hostname'
);
 // create Auth object using the SAP container
$a = new Auth("SAP", $options);
 

$a->start();
 
// check
if ($a->checkAuth()) {

 
    // authorised! You can do the protected stuff here
 
    // For example open a connection to the SAP system
    // using the stored authentication data
    $rfc = saprfc_open($a->getAuthData('sap'));
 
    // show sapinfo if you will
    echo '<pre>';
    print_r(saprfc_attributes($rfc));
    echo '</pre>';

}
?>

And here's the actual Auth_Contaner_SAP class, should be placed in a file called SAP.php in your_pear_dir/Auth/Container/

<?php
require_once 'PEAR.php';
require_once 'Auth/Container.php';
/**
 * Performs authentication against an SAP system
 * using the SAPRFC PHP extension.
 *
 * When the option GETSSO2 is TRUE (default)
 * the Single Sign-On (SSO) ticket is retrieved
 * and stored as an Auth attribute called 'sap'
 * in order to be reused for consecutive connections.
 *
 * @author Stoyan Stefanov <ssttoo@gmail.com>
 * @package Auth
 * @see http://saprfc.sourceforge.net/
 */
class Auth_Container_SAP extends Auth_Container {
    /**
     * @var array Default options
     */
    var $options = array(
        'CLIENT'    => '000',
        'LANG'      => 'EN',
        'GETSSO2'   => true,
    );
 
    /**
     * Class constructor. Checks that required options
     * are present and that the SAPRFC extension is loaded
     *
     * Options that can be passed and their defaults:
     * <pre>
     * array(
     *   'ASHOST' => "",
     *   'SYSNR'    => "",
     *   'CLIENT' => "000",
     *   'GWHOST' =>"",
     *   'GWSERV' =>"",
     *   'MSHOST' =>"",
     *   'R3NAME' =>"",
     *   'GROUP'    =>"",
     *   'LANG'     =>"EN",
     *   'TRACE'    =>"",
     *   'GETSSO2'=> true
     * )
     * </pre>
     *
     * @var array array of options.
     */
    function Auth_Container_SAP($options)
    {
        $saprfc_loaded = PEAR::loadExtension('saprfc');
        if (!$saprfc_loaded) {
            return PEAR::raiseError('Cannot use SAP authentication, '
                    .'SAPRFC extension not loaded!');
        }
        if (empty($options['R3NAME']) && empty($options['ASHOST'])) {
            return PEAR::raiseError('R3NAME or ASHOST required for authentication');
        }
        $this->options = array_merge($this->options, $options);
    }

    /**
     * Performs username and password check
     *
     * @var string Username
     * @var string Password
     * @return boolean TRUE on success (valid user), FALSE otherwise
     */        
    function fetchData($username, $password)
    {
        $connection_options = $this->options;
        $connection_options['USER'] = $username;
        $connection_options['PASSWD'] = $password;
        $rfc = saprfc_open($connection_options);
        if (!$rfc) {
            $message = "Couldn't connect to the SAP system.";
            $error = $this->getError();
            if ($error['message']) {
                $message .= ': ' . $error['message'];
            }
            PEAR::raiseError($message, null, null, null, @$erorr['all']);
            return false;
        } else {
            if (!empty($this->options['GETSSO2'])) {
                if ($ticket = @saprfc_get_ticket($rfc)) {
                    $this->options['MYSAPSSO2'] = $ticket;
                    unset($this->options['GETSSO2']);
                    $this->_auth_obj->setAuthData('sap', $this->options);
                } else {
                    PEAR::raiseError("SSO ticket retrieval failed");
                }
            }
            @saprfc_close($rfc);
            return true;
        }

     }
    /**
     * Retrieves the last error from the SAP connection
     * and returns it as an array.
     *
     * @return array Array of error information
     */
    function getError()
    {

        $error = array();
        $sap_error = saprfc_error();
        if (empty($err)) {
            return $error;
        }
        $err = explode("\n", $sap_error);
        foreach ($err AS $line) {
            $item = split(':', $line);
            $error[strtolower(trim($item[0]))] = trim($item[1]);
        }
        $error['all'] = $sap_error;
        return $error;
    }
}
?>