Trying to connect to MQ using PHP; almost there

2019-06-16 10:05发布

问题:

So I've spent the past few days trying to solve this that seems to have been forgotten since none of the two PECL extensions available (SAM and mqseries) have been updated for a long time. I've tried both and mqseries seems to get me the furthest at this point since SAM refuses to get me a connection, even though MQ works perfectly from the command line. I've successfully created a connection to my QueueManager and it's during the next step (MQOPEN) that I fail miserably:

$mqcno = array(
        'Version' => MQSERIES_MQCNO_VERSION_2,
        'Options' => MQSERIES_MQCNO_STANDARD_BINDING,
        'MQCD' => array('ChannelName' => '[channel]',
        'ConnectionName' => '[ipnumber]([port])',
        'TransportType' => MQSERIES_MQXPT_TCP)
    );

mqseries_connx('MQED', $mqcno, $conn, $comp_code,$reason);
if ($comp_code !== MQSERIES_MQCC_OK) {
    printf("Connx CompCode:%d Reason:%d Text:%s<br>\n", $comp_code, $reason, $reason);
    exit;
}

$mqods = array('ObjectName'=>'MYPUTQUEUE', 'ObjectType'=>MQOT_Q, 'ObjectQMgrName'=>'MYQUEUEMANAGER');
mqseries_open($conn, $mqods, 
          MQSERIES_MQOO_FAIL_IF_QUIESCING | MQSERIES_MQOO_OUTPUT,
          $obj, $comp_code,$reason);

THis results in $reason being populated with 2044, which translates to MQRC_OD_ERROR, or in English: 'On the MQOPEN or MQPUT1 call, the object descriptor MQOD is not valid'.

So the question is, what's wrong with my MQOD?

Update #1: At this point this is not resolved. I rebuilt the project from the ground up to resolve any issues at build time. I am still stuck on MQOPEN returning 2044. The samples still run flawlessly from CLI, so this is definitely tied to the installation of the PECL extension. If there's anyone out there who has successfully installed and are running PHP against MQ in a fairly recent 64-bit PHP5 environment please let me know...

Update #2: MQPUT1 works flawlessly with the problem that I can't receive my response. At this point, it's just MQOPEN that doesn't work. Question is; what is causing MQOPEN to return 2044 when MQPUT1 works, which I understand includes MQOPEN?

回答1:

The MQOD in the cmqch file looks like this:

 /****************************************************************/
 /*  MQOD Structure -- Object Descriptor                         */
 /****************************************************************/


 typedef struct tagMQOD MQOD;
 typedef MQOD  MQPOINTER PMQOD;
 typedef PMQOD MQPOINTER PPMQOD;

 struct tagMQOD {
   MQCHAR4   StrucId;              /* Structure identifier */
   MQLONG    Version;              /* Structure version number */
   MQLONG    ObjectType;           /* Object type */
   MQCHAR48  ObjectName;           /* Object name */
   MQCHAR48  ObjectQMgrName;       /* Object queue manager name */
   MQCHAR48  DynamicQName;         /* Dynamic queue name */
   MQCHAR12  AlternateUserId;      /* Alternate user identifier */
   /* Ver:1 */
   MQLONG    RecsPresent;          /* Number of object records
                                      present */
   MQLONG    KnownDestCount;       /* Number of local queues opened
                                      successfully */
   MQLONG    UnknownDestCount;     /* Number of remote queues opened
                                      successfully */
   MQLONG    InvalidDestCount;     /* Number of queues that failed to
                                      open */
   MQLONG    ObjectRecOffset;      /* Offset of first object record
                                      from start of MQOD */
   MQLONG    ResponseRecOffset;    /* Offset of first response record
                                      from start of MQOD */
   MQPTR     ObjectRecPtr;         /* Address of first object record */
   MQPTR     ResponseRecPtr;       /* Address of first response
                                      record */
   /* Ver:2 */
   MQBYTE40  AlternateSecurityId;  /* Alternate security identifier */
   MQCHAR48  ResolvedQName;        /* Resolved queue name */
   MQCHAR48  ResolvedQMgrName;     /* Resolved queue manager name */
   /* Ver:3 */
   MQCHARV   ObjectString;         /* Object long name */
   MQCHARV   SelectionString;      /* Message Selector */
   MQCHARV   ResObjectString;      /* Resolved long object name*/
   MQLONG    ResolvedType;         /* Alias queue resolved object type */
   /* Ver:4 */
 };

 #define MQOD_DEFAULT {MQOD_STRUC_ID_ARRAY},\
                      MQOD_VERSION_1,\
                      MQOT_Q,\
                      {""},\
                      {""},\
                      {"AMQ.*"},\
                      {""},\
                      0,\
                      0,\
                      0,\
                      0,\
                      0,\
                      0,\
                      NULL,\
                      NULL,\
                      {MQSID_NONE_ARRAY},\
                      {""},\
                      {""},\
                      {MQCHARV_DEFAULT},\
                      {MQCHARV_DEFAULT},\
                      {MQCHARV_DEFAULT},\
                      MQOT_NONE

I'm wondering if the module fills in the defaults and is letting you override then with the hash. If so, is 'DeviceName' really the right key? I would think it would match the WMQ field name or constant.

Update: Per the example at the link provided, the hash key does indeed match the field name from the cmqc.h.

Update #2 respond to comment: Object types as defined in cmqc.h are:

 /* Object Types */
 #define MQOT_NONE       0
 #define MQOT_Q          1
 #define MQOT_NAMELIST   2
 #define MQOT_PROCESS    3
 #define MQOT_STORAGE_CLASS 4
 #define MQOT_Q_MGR      5
 #define MQOT_CHANNEL    6
 #define MQOT_AUTH_INFO  7
 #define MQOT_TOPIC      8
 #define MQOT_CF_STRUC   10
 #define MQOT_LISTENER   11
 #define MQOT_SERVICE    12
 #define MQOT_RESERVED_1 999

My understanding of the PHP, Perl and most other similar efforts is that they are a very thin wrapper over the C API. The Perl one simply generates most of the code directly from the cmqc.h and other C include files and therefore all the field names and defaults exactly match those include files. This module appears to have taken a similar approach and I would expect to use the defined names and field defaults where needed.

I'm thinking something like:

$mqods = array(
                 'StrucID'=>'OD  ',
                 'Version'=>1.
                 'ObjectType'=>1,
                 'ObjectName'=>'MYPUTQUEUE', 
                 'ObjectQMgrName'=>'MYQUEUEMANAGER'
                 'DynamicQName'='',
                 'AlternateUserId'='',
                 'RecsPresent'=>0,
                 'KnownDestCount'=>0,
                 'UnknownDestCount'=>0,
                 'InvalidDestCount'=>0,
                 'ObjectRecOffset'=>0,
                 'ResponseRecOffset'=>0,
                 'ObjectRecPtr'=>NULL,
                 'ResponseRecPtr'=>NULL
);

Update #3 respond to additional comments:

The Q Mgr will accept any version of the MQOD but will fall back to that level of functionality. If you use v1 you can test out that it works. If you want to use later versions of the MQOD then you will need to add the additional fields to the hash.

The 2009 is "Connection Broken." Essentially the QMgr didn't like something and terminated your connection. Usually the meaningful error messages for that return code are in /var/mqm/qmgrs/<qmgrname>/errors/AMQEER01.LOG.