Please rate how useful you found this document: 
Average: 4.4 (7 votes)
Contents: [hide]

Overview

ProcessMaker's WSDL Web Services provide a programming interface to remotely control and integrate ProcessMaker with external systems using SOA compliant protocols. WSDL Web Services allow ProcessMaker's functionality to be accessed remotely over the internet using the W3C's Simple Object Access Protocol (SOAP) 1.2 and Web Services Description Language (WSDL) 1.1. Unlike Simple Trigger Web Services which can only be called inside ProcessMaker triggers in PHP, WSDL web services can be called both in triggers and in external applications and scripts.

WSDL web services allow external programs to remotely retrieve lists of users, groups and roles, start and derivate cases and send notifications. These web services can be very useful when creating scripts to automate tasks in your server and creating web pages which create and derive ProcessMaker cases.

Programming WSDL Web Services

ProcessMaker WSDL web services functions can be called by any language which has SOAP and WSDL libraries such as PHP, Java, Python, Perl, Ruby and the .NET languages like VB.NET and C#. Examples are provided using PHP, but they should work with other languages with slight modifications accounting for their particular manner of making function calls and handling objects.

The SOAP library for PHP implements both the SOAP 1.2 and WSDL 1.1 specifications. To use SOAP in a PHP script, PHP should be configured with the option --enable-soap. The ProcessMaker Windows Installer enables this option by default, but it may not be enabled in Linux/UNIX. To verify whether enabled, create the following script:

<?php
   phpinfo();
?>

Save the script to a file called phpinfo.php in your workflow/public_html directory, which is generally found in the following locations:

Linux/UNIX:

/opt/processmaker/engine/public_html

Windows:

ProcessMaker version 1-6.4260 or later in Windows XP/Server 2003:
C:\Program Files\ProcessMaker\processmaker\engine\public_html
ProcessMaker version 1-6.4260 or later in Windows Vista/7/Server 2008:
C:\Users\USERNAME\ProcessMaker\processmaker\engine\public_html
ProcessMaker before version 1-6.4260:
C:\Program Files\ProcessMaker\apps\processmaker\htdocs\workflow\public_html

Then direct your web browser to http:///phpinfo.php to see your PHP configuration. Look for a section labeled "soap" and verify that "Soap Client" is "enabled" for using external web services and "Soap Server" is "enabled" for offering ProcessMaker web services. When done, be sure to delete the file phpinfo.php because it is a security risk.

If unable to use web services, the problem may be that PHP is caching your WSDL calls for up to 24 hours. In this case, disable the WSDL cache in your PHP scipt with the line:

ini_set("soap.wsdl_cache_enabled", "0");

When initially creating scripts which use web services, it is a good idea to display all errors to help debug the script:

ini_set('error_reporting', E_ALL);
ini_set('display_errors', True);

Later when your scripts are used in production, it is a good idea to turn off error reporting for security reasons.

Using External WSDL Web Services

External WSDL web services from other applications can be called from inside a ProcessMaker trigger with the SOAP library. First, find out how to call the web service by examining their WSDL page, which is in XML format.

For instance, if creating a process which has people sending in information from all over the world, a trigger could be created which looks up the IP number and determines the location of the senders. In this case, go to http://www.webservicex.net/geoipservice.asmx?WSDL and find out which functions are available. The XML can be examined to find the available functions, but it is easier to simply use the following script:

<?php
$client = new SoapClient('http://www.webservicex.net/geoipservice.asmx?WSDL');
foreach ($client->__getFunctions() as $func) {
   print "$func <br>\n";
}
?>

Save the script to the file getfunctions.php in your workflow/public_html directory and direct your web browser to http:///getfunctions.php to see a listing of the available functions.

Then add a trigger which creates a SoapClient object and uses it to call web services functions. For instance, if there is a DynaForm where the user can enter an IP address in a field named "IP_ADDRESS", then the following trigger which is called after the DynaForm can look up the country of origin:

 $client = new SoapClient('http://www.webservicex.net/geoipservice.asmx?WSDL');
 $params = array('IPAddress'=> @@IP_ADDRESS);
 $result = $client->__SoapCall('GetGeoIP', array($params));
 @@COUNTRY = $result->GetGeoIPResult->CountryName;

The case variable @@COUNTRY can then be displayed on a subsequent DynaForm with a field named "COUNTRY" or in an output document containing route the case to the next task in the process with @#COUNTRY.

To see more examples using external web services, download the "Web Services" process from the ProcessMaker library.

Testing ProcessMaker's WSDL Web Services

ProcessMaker offers its WSDL web services at the URL http://<IP-ADDRESS>/sys<WORKSPACE>/<LANGUAGE>/classic/services/wsdl2. To find out the location where your installation of ProcessMaker is offering its web services, login to ProcessMaker as a user with the PM_SETUP permissions in her role and go to the ADMIN menu (which was previously the SETUP menu), then select the Web Services tab.

The address for WSDL web services is listed, along with the name of the ProcessMaker workspace and the session ID. A new session ID is created each time a user logins into the web services. To test whether web services is functioning and create a new session ID, click on the [Test] link for Login and enter the name of a ProcessMaker user and his/her password.

Once a new session has been started, all the other available ProcessMaker web services can also be tested by clicking on their [Test] links.

If a web service has an empty dropdown box to select a process, task, group, department, role, etc, then first click on the [Test] link for the corresponding list function to populate the dropdown box. For instance, to use the newCase() function, first test the processList() and taskList() functions, so the dropdown boxes to select the processId and taskId will be prepopulated.

Logging in with ProcessMaker's WSDL web services

The WSDL web services can be called by an external program or by ProcessMaker triggers. First create a SOAP client object. For instance, if accessing ProcessMaker installed at http://myserver.com in the "workflow" workspace, then use:

 $client = new SoapClient('http://myserver.com/sysworkflow/en/green/services/wsdl2');

Web services are handled through the SOAP client object, which can make function calls to ProcessMaker using the __SoapCall() method. It has two parameters:

  1. The name of the ProcessMaker web services function as a string.
  2. An array containing an associative array, which contains the parameters to pass to the web services function. Input each parameter name as a key with its value. (Remember that parameter names are case sensitive.)

To find out what functions to pass through __SoapCall() and its parameter array, see the function list below or examine the XML listing of functions in http://<IP-ADDRESS>/sys<WORKSPACE>/<LANGUAGE>/classic/services/wsdl2

login() Web Service

After instantiating a SOAP client object, then use the login() function to start a web services session in ProcessMaker:

loginResponse login(string userid, string password)

The userid is the name of the user and password is the user's password. Note that the function parameters for web service functions have to be passed as an associative array within an array.

For instance, if the user ID is 'andy' and the password is 'foobar', then login using the following script in PHP:

 $client = new SoapClient('http://myserver.com/sysworkflow/en/green/services/wsdl2');
 $params = array(array('userid'=>'andy', 'password'=>'foobar'));
 $result = $client->__SoapCall('login', $params);

Using Hashed Passwords from the Database

The password can also be an MD5 hash, which is how the passwords are stored in the ProcessMaker database.

The hashed passwords can be found by entering MySQL and examining the field rb_<WORKSPACE>.USERS.USR_PASSWORD in your installation of ProcessMaker. For instance if using the "workflow" workspace (which is the default), enter the following commands in the command line:

C:\> cd "C:\Program Files\ProcessMaker\mysql\bin" (not necessary in Linux/UNIX) C:\Program Files\ProcessMaker\mysql\bin> mysql -u root -p Enter password: ********* mysql> select USR_USERNAME, USR_PASSWORD from rb_workflow.USERS; +--------------+----------------------------------+ | USR_USERNAME | USR_PASSWORD | +--------------+----------------------------------+ | admin | 21232f297a57a5a743894a0e4a801fc3 | | vato | 8185527669f0b54109c7c99488cd08e8 | | amy | 7771fbb20af6ef10827c593daa3aff7b | | patricia | 823fec7a2632ea7b498c1d0d11c11377 | | andy | 10b28c9abf3a62e9dcb63da27a7186d8 | +--------------+----------------------------------+ 5 rows in set (0.00 sec) mysql> quit;

The encrypted passwords need to identify their type of encryption when passed to the login() function. Prepend the string "md5:" to the front of each password, so the password for "andy" in the case above would be "md5:10b28c9abf3a62e9dcb63da27a7186d8". For example:

 $client = new SoapClient('http://myserver.com/sysworkflow/en/green/services/wsdl2');
 $params = array(array('userid'=>'andy', 'password'=>'md5:10b28c9abf3a62e9dcb63da27a7186d8'));
 $result = $client->__SoapCall('login', $params);

If the passwords of the ProcessMaker users are already known, then PHP's md5() function can be used to create the MD5 hash for their passwords. For instance, if the user ID is 'andy' and the password is 'foobar':

 $client = new SoapClient('http://myserver.com/sysworkflow/en/green/services/wsdl2');
 $pass = 'md5:' . md5('foobar');
 $params = array(array('userid'=>'andy', 'password'=>$pass));
 $result = $client->__SoapCall('login', $params);

Looking up Hashed Password

If passwords might change, it is a good idea to have the script lookup the encrypted MD5 password directly from the MySQL database right before calling the login() web service. If using web services inside a ProcessMaker trigger, then the password for a user can be looked up with the executeQuery() function. For instance, the following code would look up the password for the user "andy":

 $client = new SoapClient('http://myserver.com/sysworkflow/en/green/services/wsdl2');
 $user = "andy";
 $result = executeQuery("SELECT USR_PASSWORD FROM USERS WHERE USR_USERNAME='$user'", 'rbac');
 $pass = "md5:" . $result[1]['USR_PASSWORD'];
 $params = array(array('userid'=>$user, 'password'=>$pass));
 $result = $client->__SoapCall('login', $params);

If using web services from an external script, then use the MySQL functions provided by your programming language to look up the password. For example, if programming in PHP, use the mysql_query()function. The MD5 password for the user "andy" is queried on a MySQL server at 192.168.1.100, running on port 3306, which is the default port for MySQL.

 $conn = mysql_connect('192.168.1.100:3306', 'root', 'XXXXXXX') or
              die("Error connecting to MySQL database.\n");
 mysql_select_db('rb_workflow');
 $user = "andy";
 $result = mysql_query("SELECT USR_PASSWORD FROM USERS WHERE USR_USERNAME='$user'") or
              die("Error: Unable to query the USER table.\n");
 $record = mysql_fetch_array($result, MYSQL_ASSOC);
 if (!$record)
      die("Error: Unable to find password for '$user' in the USER table.\n");
 $client = new SoapClient('http://myserver.com/sysworkflow/en/green/services/wsdl2');
 $pass = $record['USR_PASSWORD'];
 $params = array(array('userid'=>$user, 'password'=>$pass));
 $result = $client->__SoapCall('login', $params);

loginResponse object

The login() function returns a loginResponse object, which contains the following data members:

  • integer status_code: Zero if a successful login or a non-zero error number if unsuccessful.
  • string message: If a successful login, the session ID. If unsuccessful login, an error message.
  • string version: The version number of ProcessMaker's web services, which is currently "2.0". This number can be checked to verify that the web services haven't changed when upgrading ProcessMaker.
  • string timestamp: The datetime when the session began.

It is a good idea to check whether a login was successful by checking the status_code of the loginResponse object:

 if ($result->status_code == 0)
    $sessionId = $result->message;
 else
    print "Unable to connect to ProcessMaker.\nError Number: $result->status_code\n" .
          "Error Message: $result->message\n";

Once logged in, use web services to remotely control ProcessMaker.

LDAP and Active Directory Users

If logging in as a user who was imported from LDAP or Active Directory, then MD5 passwords can NOT be used. Imported users can only login using using their real passwords (except if the Authentication Source for those users is switched from LDAP or AD to MySQL).

If needing to use LDAP or Active Directory users in your scripts whose passwords might change, it is recommended to create a dummy user whose password will not change to do all your web services work. If just needing to send in variables and upload Input Documents to the case, then make the dummy user a Process Supervisor and give him/her rights to update specific DynaForms and Input Documents. If needing the dummy user to be able start cases, then assign the dummy user to the initial task(s) in the process.

If needing to route cases, then add the dummy user to the list of ad hoc users for tasks. Then, reassign the case to the dummy user and then route on the case. If needing ProcessMaker to show that a real user worked on the case, then write a trigger to set the real user in the database after the task has been closed. For example, create the following trigger in ProcessMaker:

$caseId = @@APPLICATION;
//case variables set with sendVariables() web service:
$lastIndex = @@lastIndex;
$realUserId = @@realUserId;
executeQuery("UPDATE APP_DELEGATION SET USR_UID='$realUserId' WHERE APP_UID='$caseId' AND DEL_INDEX=$lastIndex");

In the web services script, first route the case to the next task in the process with routeCase(), then send in the index number for the previous task and the user unique ID for the real user with sendVariables() and then call executeTrigger() to fire the above trigger to change the user in the database. Remember to only change the user in this way for closed tasks in the case.

Web Services Response Objects

The ProcessMaker Web Services functions generally return two types of response objects, either a pmResponse object or an object containing an object containing an array of objects.

1. The ProcessMaker web services functions which do not return lists return a pmResponse object. It has the following structure:

object pmResponse ( [integer status_code] [string message] [string time_stamp] )

Where:

  • integer status_code: If the function was executed successfully this parameter is 0, otherwise it is a non-zero error number.
  • string message: The returned function message. If an error, then the error message.
  • string time_stamp: The date and time when the function was performed.

It is recommended to always check the status_code to verify that a web services function executed correctly.

2. Web services functions which return lists such as userList() and processList() will return an object containing an object which contains an array of objects. Here is the structure of the processListResponse object returned by processList():

object processListResponse ( object processes ( [0]array ( object processListStruct ( [string guid] [string name] ) ) [1]array ( object processListStruct ( [string guid] [string name] ) ) ... ) )

Where:

  • string guid: Process ID.
  • string name: Process name.

All the web services which return lists use the same basic object structure, although the names of the objects change. The innermost objects always contain the guid and name member variables, so the data can be accessed in the basically the same way for all the web services functions.

For each function, check the provided example to find out the names of the objects and see how to access their data. It is also recommended to use PHP's var_dump() function to investigate the structure of web services objects.

When there is an error obtaining a list, the object returned has a slightly different structure. It contains the same objects, but does not contain an array:

object processListResponse ( object processes ( object processListStruct ( [string guid] [string name] ) ) )

Where:

  • string guid: The error number.
  • string name: The error message.

When using a web services list function, it is recommended to use PHP's is_array() function to check the return object to verify whether it contains an array. If not containing an array, an error has occurred.

Web Services Error Numbers

After calling a web services function, it is a good idea to check its return object, to verify that the function executed correctly. The guid contains the error number and the name contains the error message, but these member variables have to be accessed differently depending on the type of return object. To see how to check for the error number, see the provided examples for the different web services functions.

Error NumberFunctionStatus Message
0allCommand executed successfully
1loginUser does not have access to system
2many functionsInsufficient privileges to execute this function
3login
assignUserToGroup
User not registered in the system
4loginWrong password
5loginuser is inactive
6createUserInvalid role
7createUserUser ID: $userId already exists!
8assignUserToGroupUser exists in the group
9assignUserToGroupGroup not registered in the system
10newCaseArray of variables is empty
11newCaseInvalid process $processId
12newCaseNo starting task defined
13newCaseMultiple starting tasks
14newCaseTask invalid or the user is not assigned to the task
15derivateCaseThe task is defined for Manual assignment
16getCaseInfoCase $caseNumber doesn't exist
17routeCase
executeTrigger
This case is assigned to another user
18routeCase
executeTrigger
sendVariables
This delegation is already closed or does not exist
19routeCase
executeTrigger
This case is in status $caseType
20routeCasePlease specify the delegation index
21routeCaseCan not route a case with Manual Assignment using webservices
22routeCaseTask does not have a routing rule; check process definition
23sendVariablesThe variables parameter length is zero
24sendVariablesThe variables parameter is not a array
25createUserUser ID is required
26createUserPassword is required
27createUserFirstname is required
28sendMessagetemplate file doesn't exist
29sendMessageproblems sending the email
30reassignCaseTarget and Origin user are the same
31reassignCaseInvalid origin user
32reassignCaseThis case is not open.
33reassignCaseInvalid Case Delegation index for this user
34reassignCaseThe target user does not have rights to execute the task
35reassignCaseThe target user destination is invalid
36reassignCaseThe case could not be reassigned.
100systemInformationA system error message.
100importProcessFromLibraryThe process is already in the System and the value for $importOption is not specified.
or
Error the url $downloadUrl is invalid or the process in $newfilename is invalid
or
A system error message.

Web Services Security

Remember that login passwords are sent as plain text inside SOAP packets, so any packet sniffer watching the traffic can grab passwords. For this reason, it is recommended to store and execute your web services script on the same machine as the ProcessMaker server, so the packets aren't passing over a public network. If planning on passing SOAP packets over a public network, use an SSL or TLS connection to encrypt the traffic.

Remember that using an MD5 password is little protection. MD5 hashes can be cracked (and passwords which are common words in dictionaries are especially easy to crack with password dictionary). More importantly, anyone watching the internet traffic can grab the password hashes and use those hashes directly in a script to login.

Also remember to protect your passwords if your web services script is stored in a publicly accessible place. If your script is executable from the internet, your script should NOT contain passwords either in plain text form or a MD5 hash. Either use a database query in the script to lookup the password or store the passwords in a separate file which is not publicly readable.

For example, create separate file which is not publicly accessible named credentials.php:

<?php
$username = 'janedoe';
$password = 'p@55w0rd';
?>

Then, import the credentials.php file into your publicly accessible script:

<?php
require_once('credentials.php');
$client = new SoapClient('http://myserver.com/sysworkflow/en/green/services/wsdl2');
$params = array(array('userid'=>$username, 'password'=>$password));
$result = $client->__SoapCall('login', $params);
...

WSDL Web Services Functions

userList()

userList() returns a list of the users. For privileges to see the list, the logged-in user must have the PM_USERS permission in his/her role.

userListResponse userList(string sessionId)

Parameters:

  • string sessionId: The session ID, which was obtained during login.

Return value:

The userListResponse object with the following structure:

object userListResponse ( object users ( [0]array ( object userListStruct ( [string guid] [string name] ) ) ... ) )

Where:

  • string guid: The user ID.
  • string name: The user name.

Example:

 $params = array(array('sessionId'=>$sessionId));
 $result = $client->__SoapCall('userList', $params);
 $usersArray = $result->users;
 if (is_array($usersArray))
      foreach ($usersArray as $user)
           print "User name: $user->name, User ID: $user->guid \n";
 else
      print "Error: $usersArray->name \n";

groupList()

groupList() returns a list of the groups. For privileges to see the list, the logged-in user must have the PM_USERS permission in his/her role.

groupListResponse groupList(string sessionId)

Parameters:

  • string sessionId: The session ID, which was obtained during login.

Return value:

The groupListResponse object with the following structure:

object groupListResponse ( object groups ( [0]array ( object groupListStruct ( [string guid] [string name] ) ) ... ) )

Where:

  • string guid: The group ID.
  • string name: The group name.

Example:

 $params = array(array('sessionId'=>$sessionId));
 $result = $client->__SoapCall('groupList', $params);
 $groupsArray = $result->groups;
 if (is_array($groupsArray))
      foreach ($groupsArray as $group)
           print "Group name: $group->name, Group ID: $group->guid \n";
 else
      print "Error: $groupsArray->guid $groupsArray->name \n";

departmentList()

departmentList() returns a list of the departments. For privileges to see the list, the logged-in user must have the PM_USERS permission in his/her role. This function is available from version 1.2-3862Beta on.

departmentListResponse departmentList(string sessionId)

Parameters:

  • string sessionId: The session ID, which was obtained during login.

Return value:

The departmentListResponse object with the following structure:

object departmentListResponse ( object departments ( [0]array ( object departmentListStruct ( [string guid] [string name] [string parentUID] ) ) ... ) )

Where:

  • string guid: The department unique ID.
  • string name: The department name.
  • string parentUID: The unique ID for the parent department. If a top-level department, then will be an empty string.

Example:

 $params = array(array('sessionId'=>$sessionId));
 $result = $client->__SoapCall('departmentList', $params);
 $deptsArray = $result->departments;
 if (is_array($deptsArray))
      foreach ($deptsArray as $dept)
           print "Department name: $dept->name, ID: $dept->guid, Parent: $dept->parentUID \n";
 else
      print "Error: $deptsArray->guid $deptsArray->name \n";

roleList()

roleList() returns a list of the roles. For privileges to see the list, the logged-in user must have the PM_USERS permission in his/her role.

roleListResponse roleList(string sessionId)

Parameters:

  • string sessionId: The session ID, which was obtained during login.

Return value:

The roleListResponse object with the following structure:

object roleListResponse ( object roles ( [0]array ( object roleListStruct ( [string guid] [string name] ) ) ... ) )

Where:

  • string guid: The role ID.
  • string name: The role name.

Example:

 $params = array(array('sessionId'=>$sessionId));
 $result = $client->__SoapCall('roleList', $params);
 $rolesArray = $result->roles;
 if (is_array($rolesArray))
      foreach ($rolesArray as $role)
           print "Role name: $role->name, Role ID: $role->guid \n";
 else
      print "Error: $rolesArray->name \n";

createUser()

createUser() creates a new user. For privileges to create a user, the logged-in user must have the PM_USERS permission in his/her role.

pmResponse createUser(string sessionId, string userId, string firstname, string lastname, string email, string role, string password)

Parameters:

  • string sessionId: The session ID, which was obtained during login.
  • string userId: The username for the new user. (The unique ID for the user will be automatically generated.)
  • string firstname: The user's first name.
  • string lastname: The user's last name.
  • string email: The user's email address.
  • string role: The user's role, such as 'PROCESSMAKER_ADMIN', 'PROCESSMAKER_MANAGER' or 'PROCESSMAKER_OPERATOR'. Possible values can be looked up with the roleList() function.
  • string password: The user's password, such as 'Be@gle2'. (It will be automatically converted into an MD5 hash when inserted in the database.)

Parameters userId, firstname and role are required and may not be empty strings.

Return value:

From version 1.2-2740 on, createUser() returns a createUserResponse object with the following structure:

object createUserResponse ( [integer status_code] [string message] [string userUID] [string timestamp] )

If successful, the message will contain the firstname, lastname and username of the new user, otherwise it will contain the error message.

Before version 1.2-2740, createUser() returned a pmResponse object. If the function executed successfully, the message contained the new user's role.

Example:

 $params = array(array('sessionId'=>$sessionId, 'userId' => 'howdy4',
    'firstname'=>'Howdy', 'lastname'=>'Foobar', 'email'=>'howdy@example.com',
    'role'=>'PROCESSMAKER_ADMIN', 'password'=>'HowDy123'));
 $result = $client->__SoapCall('createUser', $params);
 if ($result->status_code == 0)
    print "$result->message\nUser UID: $result->userUID";  
 else
    print "Unable to create user.\nError Number: $result->status_code\n" .
          "Error Message: $result->message\n";

createGroup()

createGroup() creates a new group. For privileges to create a group, the logged-in user must have the PM_USERS permission in his/her role. Available from version 1.2-3862Beta on.

createGroupResponse createGroup(string sessionId, string name)

Parameters:

  • string sessionId: The session ID (which was obtained at login).
  • string name: The name of the new group.

Return value:

A createGroupResponse object with the following structure:

object createGroupResponse ( [integer status_code] [string message] [string groupUID] [string timestamp] )

If successful, the message will contain the text "Group X created successfully", otherwise it will contain the error message.

Example:

 $params = array(array('sessionId'=>$sessionId, 'name' => 'Independent Contractors'));
 $result = $client->__SoapCall('createGroup', $params);
 if ($result->status_code == 0)
    print "$result->message\nGroup UID: $result->groupUID";  
 else
    print "Unable to create group.\nError Number: $result->status_code\n" .
          "Error Message: $result->message\n";

createDepartment()

createDepartment() creates a new department. For privileges to create a department, the logged-in user must have the PM_USERS permission in his/her role. Available from version 1.2-3862Beta on.

createDepartmentResponse createDepartment(string sessionId, string name, string parentUID)

Parameters:

  • string sessionId: The session ID, which was obtained during login.
  • string name: The name of the new department.
  • string parentUID: The unique ID of the parent department, which can be obtained with departmentList(). To make a top-level department, set to '' (an empty string).

Return value:

A createDepartmentResponse object with the following structure:

object createDepartmentResponse ( [integer status_code] [string message] [string departmentUID] [string timestamp] )

If successful, the message will contain the text "Department X created successfully", otherwise it will contain the error message.

Example:

 $params = array(array('sessionId'=>$sessionId, 'name' => 'Human Resources', 'parentUID' => ''));
 $result = $client->__SoapCall('createDepartment', $params);
 if ($result->status_code == 0)
    print "$result->message\nDepartment UID: $result->departmentUID";  
 else
    print "Unable to create department.\nError Number: $result->status_code\n" .
          "Error Message: $result->message\n";

assignUserToGroup()

assignUserToGroup() assigns a user to a group. For privileges to assign a user, the logged-in user must have the PM_USERS permission in his/her role.

pmResponse assignUserToGroup(string sessionId, string userId, string groupId)

Parameters:

  • string sessionId: The session ID, which was obtained during login.
  • string userId: The ID of the user, which can be found with the userList() function.
  • string groupId: The ID of the group, which can be found with the groupList() function.

Return value:

A pmResponse object.

assignUserToDepartment()

assignUserToDepartment() assigns a user to a department. For privileges to assign a user, the logged-in user must have the PM_USERS permission in his/her role.

pmResponse assignUserToDepartment(string sessionId, string userId, string departmentId, string manager)

Parameters:

  • string sessionId: The session ID, which was obtained during login.
  • string userId: The ID of the user, which can be found with the userList() function.
  • string departmentId: The ID of the group, which can be found with the departmentList() function.
  • string manager: The ID of the department's manager, which can be found with the userList() function.

Return value:

A pmResponse object.

processList()

processList() returns a list of the processes. For privileges to see the list, the logged-in user must have the PM_FACTORY permission in his/her role.

processListResponse processList(string sessionId)

Parameters:

  • string sessionId: The session ID, which was obtained during login.

Return value:

The processListResponse object with the following structure:

object processListResponse ( object processes ( [0]array ( object processListStruct ( [string guid] [string name] ) ) ... ) )

Where:

  • string guid: The process ID.
  • string name: The process name.

Example:

 $params = array(array('sessionId'=>$sessionId));
 $result = $client->__SoapCall('processList', $params);
 $processesArray = $result->processes;
 
 if ($processesArray != (object) NULL)
 {
    if (is_array($processesArray))
    {
        foreach ($processesArray as $process)
            print "Process name: $process->name, Process ID: $process->guid \n";
    }
    else
    {
        print "Process name: $processesArray->name, Process ID: $processesArray->guid \n";
    }
 }
 else
    print "Error: $processesArray->name \n";

taskList()

taskList() returns a list of the tasks to which the logged-in user has privileges.

taskListResponse taskList(string sessionId)

Parameters:

  • string sessionId: The session ID, which was obtained during login.

Return value:

The taskListResponse object with the following structure:

object taskListResponse ( object tasks ( [0]array ( object tasksListStruct ( [string guid] [string name] ) ) ... ) )

If the user has no assigned tasks, then taskList() returns an empty stdClass, which is equivalent to (object) NULL. To avoid errors, check whether the return object equals (object) NULL.

Example:

 $params = array(array('sessionId'=>$sessionId));
 $result = $client->__SoapCall('taskList', $params);
 $tasksArray = $result->tasks;
 if ($tasksArray != (object) NULL)
      foreach ($tasksArray as $task)
           print "Task name: $task->name, Task ID: $task->guid \n";
 else
      print "There are zero tasks assigned to this user. \n";

taskCase()

taskCase() returns the current task for a given case. Note that the logged-in user must have privileges to access the task.

taskCaseResponse taskCase(string sessionId, string caseId)

Parameters:

  • string sessionId: The session ID, which was obtained during login.
  • string caseId: The case ID. The caseList() function can be used to find the ID number for cases.

Return value:

A taskCaseResponse object with the structure:

object taskCaseResponse ( object taskCases ( object taskCaseStruct ( [string guid] [string name] ) ) )

Where:

  • string guid: The ID of the current task.
  • string name: The name of the current task.

If there is no current task or the user doesn't have privileges to access the current task, an empty stdClass will be returned, which is equivalent to (object) NULL. To avoid errors check whether the returned taskCaseResponse is equal to (object) NULL.

Example:

 $params = array(array('sessionId'=>$sessionId, 'caseId'=>$caseId));
 $result = $client->__SoapCall('taskCase', $params);
 if ($result != (object) NULL)
      print "Task name: {$result->taskCases->name}, Task ID: {$result->taskCases->guid} \n";
 else
      print "No task or unable to access task. \n";

caseList()

caseList() returns a list of the cases for the logged-in user.

caseListResponse caseList(string sessionId)

Parameters:

  • string sessionId: The session ID, which was obtained during login.

Return value:

The caseListResponse object with the following structure:

object caseListResponse ( object cases ( [0]array ( object caseListStruct ( [string guid] [string name] [string status] [string delIndex] ) ) ... ) )

Where:

  • string guid: The case unique ID.
  • string name: The case name.
  • string status: The status of the case. Possible values include 'TO_DO', 'DRAFT', 'COMPLETED', 'PAUSED' and 'CANCELED'.
  • int delIndex: The delegation index, which is a positive integer to identify the current task of the case. The first task is 1, the second task is 2, etc.

If the user has no cases, then caseList() returns an empty stdClass, which is equivalent to (object) NULL. To avoid errors, check whether whether the return object equals (object) NULL.

Example:

 $params = array(array('sessionId'=>$sessionId));
 $result = $client->__SoapCall('caseList', $params);
 $casesArray = $result->cases;
 if ($casesArray != (object) NULL)
      foreach ($casesArray as $case)
           print "Case name: $case->name, Case ID: $case->guid, Status: $case->status \n";
 else
      print "There are zero cases. \n";

unassignedCaseList()

unassignedCaseList() returns a list of the unassigned cases which the logged-in user has rights to be assigned to. Available from version 2.0.36 on.

unassignedCaseListResponse unassignedCaseList(string sessionId)

Parameters:

  • string sessionId: The session ID, which was obtained during login.

Return value:

The unassignedCaseListResponse object with the following structure:

object unassignedCaseListResponse ( object cases ( [0]array ( object unassignedCaseListStruct ( [string guid] [string name] [string delIndex] ) ) ... ) )

Where:

  • string guid: The case unique ID.
  • string name: The case title.
  • int delIndex: The delegation index, which is a positive integer to identify the current task of the case. The first task is 1, the second task is 2, etc.

If the user has no unassigned cases, then unassignedCaseList() returns an empty stdClass, which is equivalent to (object) NULL. To avoid errors, check whether whether the return object equals(object) NULL.

Example:

 $params = array(array('sessionId'=>$sessionId));
 $result = $client->__SoapCall('unassignedCaseList', $params);
 $casesArray = $result->cases;
 if ($casesArray != (object) NULL) {
    foreach ($casesArray as $case) {
       print "Case name: $case->name, Case ID: $case->guid \n";
    }
 }
 else  
    print "There are zero unassigned cases.\n";

getCaseInfo()

getCaseInfo() returns information about a given case (as long as the logged in user has privileges to access the case).

getCaseInfoResponse getCaseInfo(string sessionId, string caseId, string delIndex)

Parameters:

  • string sessionId: The session ID, which was obtained during login.
  • string caseId: The case ID, which can be obtained with the caseList() function.
  • string delIndex: The delegation index, which is a positive integer to identify the current task of the case. The first task is 1, the second task is 2, etc. This number can be obtained with the caseList()function.

Return value:

If using version 1.2-2740 or later, then getCaseInfo() returns a getCaseInfoResponse object with the following structure:

object getCaseInfoResponse ( [integer status_code] [string message] [string caseId] [string caseNumber] [string caseName] [string caseStatus] [string caseParalell] [string caseCreatorUser] [string caseCreatorUserName] [string processId] [string processName] [string createDate] [object currentUsers] ( [0]array ( object getCaseInfoStruct ( [string userId] [string userName] [string taskId] [string taskName] [integer delIndex] [integer delThread] [string delThreadStatus] ) ) ... ) )

Before version 1.2-2740, getCaseInfo() returns a getCaseInfoResponse object with fewer elements:

object getCaseInfoResponse ( [integer status_code] [string message] [string caseId] [string caseNumber] [string caseStatus] [string caseParalell] [string caseCurrentUser] [string timestamp] )

If the case does not exist, the delIndex isn't found in the case, or an error occurred, getCaseInfo() before version 1-2.2740 did NOT return a getCaseInfoResponse. Instead, it returned a pmResponseobject with a non-zero error number in the status_code and the error message in the message.

Example:

 $params = array(array('sessionId'=>$sessionId, 'caseId'=>'9636840824a76fab5df5714036136565',
     'delIndex'=>'3'));
 $result = $client->__SoapCall('getCaseInfo', $params);
 if ($result->status_code == 0)
      print "Case ID: $result->caseId, Current UserID: $result->caseCurrentUser \n";
 else
      print "Error: $result->message \n";

newCase()

newCase() begins a new case under the name of the logged-in user.

newCaseResponse newCase(string sessionId, string processId, string taskId, array variables)

Parameters:

  • string sessionId: The ID of the session, which is obtained during login.
  • string processId: The ID of the process where the case should start, which can be obtained with processList().
  • string taskId: The ID of the task where the case should start. This will generally be the first task in a process, which can be obtained with taskList().
  • array variables: An array of variableStruct objects which contain information to start the case. This array has the following format:
[0]array ( object variableStruct ( [string name] [string value] ) ) ...

Return value:

A newCaseResponse object, with the structure:

newCaseResponse ( [integer status_code] [string message] [string caseId] [string caseNumber] [string timestamp] )

If an error occurred, status_code will contain a non-zero error number and the message will hold the error message.

Example:

 # Script to create a new case for the "Credit Card Application" process,
# which is available for download at http://library.processmaker.com
class variableStruct {
   public $name;
   public $value;
 }
 $name = new variableStruct();
 $vars = array('APPLICANT_NAME'=>'John', 'APPLICANT_LAST'=>'Doe',
     'APPLICANT_ID'=>'123456', 'APPLICANT_EMAIL'=>'johndoe@example.com',
     '$APPLICANT_EMPLOYER'=>'Example Corp, Inc.');
 $aVars = array();
 foreach ($vars as $key => $val)
 {
      $obj = new variableStruct();
      $obj->name = $key;
      $obj->value = $val;
      $aVars[] = $obj;   
 }
 
 # Use the functions processList() and taskList() to look up the IDs for the
# process and its first task.
$params = array(array('sessionId'=>$sessionId, 'processId'=>'447CEAF7BE6AEB',
     'taskId'=>'347CEB10B72D11', 'variables'=>$aVars));
 $result = $client->__SoapCall('newCase', $params);
 if ($result->status_code == 0)
      print "New case ID: $result->caseId, Case No: $result->caseNumber \n";
 else
      print "Error creating case: $result->message \n";

Note: The status of the new case will be set to "DRAFT", not "TO_DO" after being created. To get around this problem, create a trigger with the following code:

$caseId = @@APPLICATION;
$index = @%INDEX;
executeQuery("UPDATE APPLICATION SET APP_STATUS='TO_DO' WHERE APP_UID='$caseId' AND APP_STATUS='DRAFT'");

Then call executeTrigger() to fire the above trigger after creating the case with newCase().

newCaseImpersonate()

newCaseImpersonate() creates a new case impersonating a user who has the proper privileges to create new cases. Use this function to allow any user to initiate new cases. Note that the new case's status will be set to "DRAFT", not "TO_DO". See the above workaround.

pmResponse newCaseImpersonate(string sessionId, string processId, string taskId, string userId, array variables)

Parameters:

  • string sessionId: The session ID, which was obtained during login.
  • string processId: The unique ID of the process where the case should start, which can be obtained with processList().
  • string taskId: The unique ID of the starting task in the process, which can be obtained with taskList().
  • string userId: The unique ID of the user who initiates the case, which can be obtained with userList().
  • array variables: An array of variableStruct objects which contain data to start the case. This array has the following format:
array ( object variableStruct ( [string name] [string value] ), ... )

Return value:

A pmResponse object.

reassignCase()

reassignCase() reassigns a case to a different user. Note that the logged-in user needs to have the PM_REASSIGNCASE permission in his/her role in order to be able to reassign the case.

pmResponse reassignCase(string sessionId, string caseId, string delIndex, string userIdSource, string userIdTarget)

Parameters:

  • string sessionId: The session ID, which was obtained during login.
  • string caseId: The case ID, which can be obtained with the caseList() function.
  • string delIndex: The delegation index number of the case, which can be obtained with the caseList() function.
  • string userIdSource: The user who is currently assigned the case, which can be obtained with the caseList() function.
  • string userIdTarget: The target user who will be newly assigned to the case, which can be obtained with userList(). The case can only be reassigned to a user who is one of the assigned users or ad hoc users to the current task in the case.

Return value:

A pmResponse object.

routeCase()

routeCase(), which was named derivateCase() before version 1.2-2740, routes a case (i.e., moves the case to the next task in the process according to the routing rules).

In version 1.2-2740 and later:

routeCaseResponse routeCase(string sessionId, string caseId, string delIndex)

Before version 1.2-2740:

pmResponse derivateCase(string sessionId, string caseId, string delIndex)


Parameters:

  • string sessionId: The session ID, which was obtained during login.
  • string caseId: The case ID (which can be obtained with the caseList() function).
  • string delIndex: The delegation index number for the case (which can be obtained with the caseList() function or by examining the field wf_<WORKSPACE>.APP_DELEGATION.DEL_INDEX).


Return value:

From version 1.2-2740 on, routeCase() returns a routeCaseResponse object with the following structure:

object routeCaseResponse ( [integer status_code] [string message] [string timestamp] object routing ( [0] array ( object routeListStruct ( [string userId] [string userName] [string taskId] [string taskName] [integer delIndex] [integer delThread] [string delThreadStatus] ) ) ... ) )

If routeCase() returns error number 22 ("Task does not have a routing rule, check process definition"), the routing rule which follows the current task probably contains a condition with a case variable which has not been defined. If a case variable was defined by a DynaForm and the DynaForm was never displayed, then the case variable won't be created. In this case, you will have to use thesendVariables() function to send the case variable to the case so it can be used in the routing rule.

If routeCase() returns error number 18 ("This delegation is already closed or does not exist"), either the case ID is wrong (or the user doesn't have privileges to route the case) or using a delegation index from a previous task which has already been completed. Remember that a new delegation index is assigned every time a case is routed to another task. Use caseList() to find the current delIndex for the case before calling routeCase().

Prior to version 1.2-2470, derivateCase() returned a pmResponse object. If an unsuccessful routing, the message will list the error message, which is useful for debugging problems in routing. If a successful routing, the message will list the next task and in parenthesis the user(s) or group(s) to which the task is assigned, plus any triggers which were executing during the routing:

<NEXT_TASK_NAME>(<WHO_ASSIGNED_TO_NEXT_TASK>)
<WHEN_TRIGGER EXECUTED> ----------
<TRIGGER_CODE>

Example:

 #Use caseList() to get the caseId and delIndex.
$params = array(array('sessionId'=>$sessionId,
     'caseId'=>'3291015624a7c9d85b71b21074133813', 'delIndex'=>'1'));
 $result = $client->__SoapCall('routeCase', $params);
 if ($result->status_code == 0)
      print "Case derived: $result->message \n";
 else
      print "Error deriving case: $result->message \n";

getVariables()

getVariables() returns variables from a given case. The variables can be system variables and/or case variables.

variableListResponse getVariables(string sessionId, string caseId, array variables)

Parameters:

  • string sessionId: The session ID, which is obtained during the login.
  • string caseId: The ID of the case, which provides the variable values. This ID can be obtained with caseList().
  • array variables: An array of variableStruct objects, which hold the names of the variables which will be returned. The array has the following structure:
array ( [0] ( object variableStruct ( [string name] ) ) [1] ( object variableStruct ( [string name] ) ) ... )

Return value:

A variableListResponse object, with the structure:

object variableListResponse ( [integer status_code] [string message] [string timestamp] object variables ( array ( [0] ( object variableListStruct ( [string name] [string value] ) ) [1] ( object variableListStruct ( [string name] [string value] ) ) ... ) ) )

If the variables don't exist or it an error occurred, the object variables will be an empty stdClass, which is equal to (object)NULL. To avoid errors, check that variables does not equal (object)NULL.

Note 1: All value's will be returned as strings, so they may need to be converted to other variable types, such as int, float, boolean, etc. If passing complex data types, such as objects or arrays, then fire a trigger beforehand to convert them into serialized strings with serialize() or json_encode() before calling the getVariables() web service. See Variable Type Conversion and the example below.

Note 2: Before version 1.2-2740, this function did not work properly due to a bug.

Note 3:Due to this bug, getVariables() cannot retrieve only one variable. It must retrieve at least 2 variables. If needing only one variable, include a second variable in the variables array.

Example:

 class variableStruct {
   public $name;
 }
 
 $p = new variableStruct();
 $p->name = 'clientName';     //a case variable
 $s = new variableStruct();
 $s->name = 'SYS_LANG';       //a system variable
 $variables = array($p, $s);
 $params = array(array('sessionId'=>$sessionId, 'caseId'=>'3188781734a71c99e356809057266790',
     'variables'=>$variables));
 $result = $client->__SoapCall('getVariables', $params);
 if ($result->status_code == 0 && $result->variables != (object) NULL)
 {
      $variablesArray = $result->variables;
      foreach ($variablesArray as $variable)
           print "Variable name: $variable->name, Value: $variable->value \n";
 }

It is possible to dynamically construct the array of $variables, based upon an array. The following code would do the same as the example above:

 class variableStruct {
     public $name;
 }
 $vars = array('clientName', 'SYS_LANG');  
 $variables = array();
 foreach ($vars as $var)
 {
    $obj = new variableStruct();
    $obj->name = $var;
    $variables[] = $obj;         
 }
 $params = array(array('sessionId'=>$sessionId, 'caseId'=>'3188781734a71c99e356809057266790',
     'variables'=>$variables));
 $result = $client->__SoapCall('getVariables', $params);
 if ($result->status_code == 0 && $result->variables != (object) NULL)
 {
      $variablesArray = $result->variables;
      foreach ($variablesArray as $variable)
           print "Variable name: $variable->name, Value: $variable->value \n";
 }

To get a grid from ProcessMaker, which is stored as an associative array of associative arrays, it first must be converted to a serialized string, so it can returned as a string by getVariables(). Create a trigger in ProcessMaker to convert the string. For example:

 @@MyGridSerialized = serialize(@=MyGrid);

Before calling the getVariables() web service, first call the executeTrigger() to convert the grid to a serialized string. After receiving the string, convert it into an associative array of associative arrays with theunserialize() function.

sendVariables()

sendVariables() sends variables to a case.

pmResponse sendVariables(string sessionId, string caseId, array variables)

Parameters:

  • string sessionId: The session ID, which was obtained during login.
  • string caseId: The case ID (which can be obtained with the caseList() function).
  • array variables: An array of variableListStruct objects that contains the variable names and their values to be sent. This array has the following format:
array ( [0] ( object variableListStruct ( [string name] [string value] ) ) [1] ( object variableListStruct ( [string name] [string value] ) ) ... )

Return value:

A pmResponse object. If successful, the message will indicate how many variables have been received; otherwise, it will contain an error message.

Example:

 class variableListStruct {
     public $name;
     public $value;
 }
 
 $position = new variableListStruct();
 $position->name = "position";
 $position->value = "manager";
 
 $salary = new variableListStruct();
 $salary->name = "salary";
 $salary->value = 3896.78;
 
 $startdate = new variableListStruct();
 $startdate->name = "startdate";
 $startdate->value = "2009-08-20";
 
 $variables = array($position, $salary, $startdate);
 $params = array(array('sessionId'=>$sessionId, 'caseId'=>$caseId, 'variables'=>$variables));
 $result = $client->__SoapCall('sendVariables', $params);
 if ($result->status_code != 0)
     print "Error: $result->message \n";

It is possible to dynamically construct the array of $variables, based upon an associative array. The following code would do the same as the example above:

 class variableListStruct {
     public $name;
     public $value;
 }
 $vars = array('position'=>'manager', 'salary'=>3896.78, 'startdate'=>'2009-08-20');  
 $variables = array();
 foreach ($vars as $key => $val)
 {
    $obj = new variableListStruct();
    $obj->name = $key;
    $obj->value = $val;
    $variables[] = $obj;         
 }
 $params = array(array('sessionId'=>$sessionId, 'caseId'=>$caseId, 'variables'=>$variables));
 $result = $client->__SoapCall('sendVariables', $params);
 if ($result->status_code != 0)
     print "Error: $result->message \n";

Variable Type Conversion

All variable values are send as strings. In most cases, ProcessMaker will gracefully convert these string values to one of the other basic PHP data types (int, float or boolean) when needed in the process. If this doesn't occur, it may be necessary to use executeTrigger() to fire a trigger afterwards which will convert the data. For example, it might be necessary to execute this trigger after sending the "salary" variable:

 @=salary = (float)@@salary; //explicit conversion

or:

 @=salary = @#salary; //convert with ProcessMaker case variable data typing

Complex data types
If sending a complex data type such as an array or an object, it is best to pass the variable as a serialized string, then use executeTrigger() to fire a trigger which will unserialize the object and assign it to a case variable.

For example, if sending this $employees associative array of associative arrays (which is how grids are stored in ProcessMaker):

 $employees = array(
    '1' => array("position"=>"manager",      "salary"=>4000.00, "startdate"=>"2009-08-20"),
    '2' => array("position"=>"receptionist", "salary"=>2000.00, "startdate"=>"2007-12-01"),
    '3' => array("position"=>"grunt",        "salary"=>2500.00, "startdate"=>"2005-03-18")
 );

First, create the following Trigger in the process which will convert a serialized string into an associative array of associative arrays:

 @=EmployeesGrid = unserialize(@@EmployeesGrid);

Then, create the web service script which uses PHP's serialize() function when passing the $employees array to the case with sendVariables(). After sending the grid data to the case, then use executeTrigger() to call the trigger which will unserialize @@EmployeesGrid and convert it into an associative array of associative arrays:

 $employees = array(
    '1' => array("position"=>"manager",      "salary"=>4000.00, "startdate"=>"2009-08-20"),
    '2' => array("position"=>"receptionist", "salary"=>2000.00, "startdate"=>"2007-12-01"),
    '3' => array("position"=>"grunt",        "salary"=>2500.00, "startdate"=>"2005-03-18")
 );
 class variableStruct {
     public $name;
     public $value;
 }
 $v = new variableStruct();
 $v->name = "EmployeesGrid";
 $v->value = serialize($employees);
 
 $variables = array($v);
 $params = array(array('sessionId'=>$sessionId, 'caseId'=>$caseId, 'variables'=>$v));
 $result = $client->__SoapCall('sendVariables', $params);
 if ($result->status_code != 0)
     print "Error: $result->message \n";
 #look up the caseId and delIndex with caseList() and the triggerIndex with triggerList():
$params = array(array('sessionId'=>$sessionId, 'caseId'=>'$caseId',
       'triggerIndex'=>'3126831054a7dd8781e84a7046772575','delIndex'=>'1'));
 $result = $client->__SoapCall('executeTrigger', $params);
 if ($result->status_code != 0)
      print "Error: $result->message \n";

A subsequent DynaForm which has a grid object named "EmployeesGrid" can then display the data in a grid.

Other Programming Languages

If using a different programming language which doesn't support the serialize() function, then encode objects and arrays as JSON strings, before passing them to the sendVariables() web service. See this list of JSON encoders/decoders for different languages. After sending the variables, then call the executeTrigger() web service to decode the object or array in a ProcessMaker trigger withjson_decode().

If sending associative arrays, note that they will be encoded in JSON as objects. To pass a grid (an associative array of associative arrays) to ProcessMaker with JSON, it in necessary to convert the objects to associative arrays in a trigger before trying to display them in a DynaForm grid. For example, this trigger code would decode the JSON string and convert the object to an associative array of associative arrays which can be displayed in a grid:

 $aGrid = (array) json_decode(@@EmployeesGrid);
 @=EmployeesGrid = array();
 foreach ($aGrid as $rowNo=>$row) {
    @=EmployeesGrid[$rowNo] = (array) $row;
 }

triggerList()

triggerList() returns a list of all the available triggers in a workspace. (Available from version 1.2-2740 on.)

triggerListResponse triggerList(string sessionId)

Parameters:

  • string sessionId: The session ID (which was obtained at login).

Return value:

A triggerListResponse object, with the following structure:

[0] array ( object triggerListStruct ( [string guid] [string name] [string processId] ) ) ...

executeTrigger()

executeTrigger() executes a ProcessMaker trigger. Note that triggers which are tied to case routing will executing automatically, so this function does not need to be called when deriving cases.

pmResponse executeTrigger(string sessionId, string caseId, string triggerIndex, string delIndex)

Parameters:

  • string sessionId: The session ID, which was obtained during login.
  • string caseId: The case ID, which is can be found with caseList().
  • string triggerIndex: The ID of the trigger to execute, which can be found with triggerList().
  • string delIndex: The delegation index number of the case, which can be found with caseList().

Return value:

A pmResponse object. If successful, the message will contain "executed: <TRIGGER_CODE>".

The triggerIndex can be looked up with the triggerList() function if using version 1.2-2740 or later. For prior versions, the triggerIndex will have to be looked up in the wf_<WORKSPACE>.CONTENT table in MySQL:

C:\Program Files\ProcessMaker\mysql\bin> mysql -u root -p Enter password: ******** mysql> select con_value, con_id from wf_workflow.content where (con_category = 'TRI_TITLE'); +----------------------------+----------------------------------+ | con_value | con_id | +----------------------------+----------------------------------+ | updateAddinHistory | 10768559548a5cc2e0fbe52053131576 | | setRepFinalDec | 11249313348d67d3d7862a3048595231 | | getIssueDate | 11696570848a596568ee996042105082 | | setStatusOnHold | 16522080448a5f47eed5b21029801136 | | ws3 | 17763769948e29e195dff45029465358 | | ws2 | 21947161648e29de1ba6239054599761 | | getDateAddIn | 23391845548a5cc9a238ee9056072477 | | GET DATE | 247CEBDB202DE0 | | UpdateBugComments | 25994873048a8e0b157bd28002964410 | | getCaseNumber | 28138323548a5e9c5acbb13018874573 | | Hello World | 306900500490b24cc8fdd71038114427 | ...

Once the trigger ID is known, the code for a particular trigger can also be looked up in the wf_<WORKSPACE>.TRIGGERS table:

mysql> select tri_uid, tri_webbot from wf_workflow.triggers where tri_uid = '306900500490b24cc8fdd71038114427'; +----------------------------------+------------------------------------+ | tri_uid | tri_webbot | +----------------------------------+------------------------------------+ | 306900500490b24cc8fdd71038114427 | @@HELLO='Hello World of '.@@name; | +----------------------------------+------------------------------------+

Example:

 #look up the caseId and delIndex with the caseList() web service and the triggerIndex in MySQL
$params = array(array('sessionId'=>$sessionId, 'caseId'=>'9782409664a7c94433d0920003544388',
       'triggerIndex'=>'3126831054a7dd8781e84a7046772575','delIndex'=>'1'));
 $result = $client->__SoapCall('executeTrigger', $params);
 if ($result->status_code != 0)
      print "Error: $result->message \n";

sendMessage()

sendMessage() sends an email with the provided data. Note that ProcessMaker must be properly configured to send email for this option to work.

pmResponse sendMessage(string sessionId, string caseId, string from, string to, string cc, string bcc, string subject, string template)

Parameters:

  • string sessionId: The session ID, which was obtained during login.
  • string caseId: The case ID, which can be found with caseList().
  • string from: The email address of the sender.
  • string to: A list of email addresses (separated by commas) to receive the email.
  • string cc: A list of email addresses (separated by commas) to receive carbon copies of the email.
  • string bcc: A list of email addresses (separated by commas) to receive blind carbon copies of the email.
  • string subject: The subject line of the email.
  • string template: The file containing the body of the email. The file should be placed in the shared/sites/<WORKSPACE>/mailTemplates/<PROCESS_ID> directory. See HTML Notification Templates for more information on how to make an HTML template file containing variables.

Return value:

A pmResponse object. If unable to locate the template file for the email, the error message in the pmResponse will indicate the path where ProcessMaker is searching for the file. Check this error message to find where to save the email template file.

Note: This function does not work in recent versions due to this bug.

Example:

 $params = array(array("sessionId"=>$sessionId, "caseId"=>"3188781734a71c99e356809057266790",
     "from"=>"support@colosa.com", "to"=>"joe@example.com, jane@example.com", "cc"=>"", "bcc"=>"",
     "subject"=>"Contact Information", "template"=>"mail-body.txt"));
 $result = $client->__SoapCall('sendMessage', $params);
 if ($result->status_code != 0)
     print "Email error: $result->message \n";

systemInformation()

systemInformation() returns information about the WAMP/LAMP stack, the workspace database, the IP number and version of ProcessMaker, and the IP number and version of web browser of the user. (Available from version 1.2-2740 on.)

systemInformationResponse systemInformation(string sessionId)

Parameters:

  • string sessionId: The session ID (which was obtained at login).

Return value:

A systemInformationResponse object with the following structure:

object systemInformationResponse ( [integer status_code] [string message] [string timestamp] [string version] [string operatingSystem] [string webServer] [string serverName] [string serverIp] [string phpVersion] [string databaseVersion] [string databaseServerIp] [string databaseName] [string availableDatabases] [string userBrowser] [string userIp] }

importProcessFromLibrary()

importProcessFromLibrary() downloads and imports a process from the ProcessMaker library. Available from version 1.2-2741 and later.

importProcessFromLibraryResponse importProcessFromLibrary(string sessionId, string processId, string version, string importOption, string usernameLibrary, string passwordLibrary)

Parameters:

  • string sessionId: The session ID (which was obtained at login).
  • string processId:
  • string version:
  • string importOption:
  • string usernameLibrary: The username to obtain access to the ProcessMaker library.
  • string passwordLibrary: The password to obtain access to the ProcessMaker library.

Return value:

An importProcessFromLibraryResponse object with the following structure:

object importProcessFromLibraryResponse ( [integer status_code] [string message] [string processId] [string processTitle] [string category] [string version] )

inputDocumentList()

inputDocumentList() returns a list of the uploaded documents for a given case. Available from version 1.2-3104 and later.

inputDocumentListResponse inputDocumentList(string sessionId, string caseId)

Parameters:

  • string sessionId: The session ID, which was obtained during login.
  • string caseId: The case unique ID, which can be obtained with the caseList() web service.

Return value:

The inputDocumentListResponse object with the following structure:

object inputDocumentListResponse ( object cases ( [0]array ( object caseListStruct ( [string guid] [string filename] [string docId] [integer version] [string createDate] [string createBy] [string type] [integer index] [string link] ) ... ) )

Where:

  • string guid: The uploaded document unique ID (appDocUid). Every time a new document is uploaded, a UID is assigned.
  • string filename: The uploaded document name.
  • string docId: Corresponds to input document object unique ID, which is assigned during the process design.
  • integer version: The uploaded document version.
  • string createDate: The date and time when the document was created.
  • string createdBy: The user name, who uploaded the document.
  • string type: The type of the document.
  • integer index: Indicates in which order along the process, the document is uploaded. The first input document along the process has index=1, the second index=2, etc.
  • string link: Returns a relative link to download the document: cases/cases_ShowDocument?a=<DOCUMENT-UID>&v=<VERSION>
The relative link can be used in a link field in a DynaForm. If using in an email or Output Document, then create an absolute address by concatenating "http://<IP-ADDRESS>/sys<WORKSPACE>/<LANG>/<SKIN>/" and the relative link.

Example:

 $params = array(array('sessionId'=>$sessionId, 'caseId'=>$caseId));
 $result = $client->__SoapCall('InputDocumentList', $params);
 $inputDocumentListArray = $result->documents;
 if ($inputDocumentListArray != (object) NULL)
 {
    if (is_array($inputDocumentListArray))
    {
       foreach ($inputDocumentListArray as $iDocList)
       {
           print "InputDocument Name:    $iDocList->filename
                  InputDocument ID:      $iDocList->guid
                  InputDocument Doc ID:  $iDocList->docId  
                  InputDocument Version: $iDocList->version
                  InputDocument Created: $iDocList->createDate \n"
;
       }
    }
    else
    {
       print "InputDocument name:    $inputDocumentListArray->filename
              InputDocument ID:      $inputDocumentListArray->guid
              InputDocument Doc ID:  $inputDocumentListArray->docId
              InputDocument Version: $inputDocumentListArray->version  
              InputDocument Created: $inputDocumentListArray->createDate \n"
;
    }
 }
 else
    print "Error: $inputDocumentListArray->filename \n";

inputDocumentProcessList()

inputDocumentProcessList() returns a list of the input documents for a given process. Available from version 1.2-3104 and later.

inputDocumentProcessListResponse inputDocumentProcessList(string sessionId, string processId)

Parameters:

  • string sessionId: The session ID, which was obtained during login.
  • string processId: The process unique ID, which can be obtained with the webservice processList().

Return value:

The inputDocumentProcessListResponse object with the following structure:

object inputDocumentProcessList ( object cases ( [0]array ( object inputDocumentProcessListStruct ( [string guid] [string name] [string description] ) ) ... ) )

Where:

  • string inputDocUid: The Input Document unique ID.
  • string name: The Input Document title.
  • string description: The Input Document description.

Example:

 $params = array(array('sessionId'=>$sessionId, 'processId'=>$processId));
 $result = $client->__SoapCall('inputDocumentProcessList', $params);
 $inputDocumentListArray = $result->documents;
 if ($inputDocumentListArray != (object) NULL)
 {
    if (is_array($inputDocumentListArray))
    {
       foreach ($inputDocumentListArray as $iDocList)
           print "Document Name:        $iDocList->name \n
                 "
Document ID:          $iDocList->guid \n
                 "Document Description: $iDocList->description \n\n";
    }
    else
    {
       print "Document Name:        $inputDocumentListArray->name \n" .
             "Document ID:          $inputDocumentListArray->guid \n" .
             "Document Description: $inputDocumentListArray->description \n";
    }
 }
 else
    print "Error: $inputDocumentListArray->filename \n";

outputDocumentList()

outputDocumentList() returns a list of the output documents for a given case. Available from version 1.2-3104 and later.

outputDocumentListResponse outputDocumentList(string sessionId, string caseId)

Parameters:

  • string sessionId: The session ID, which was obtained during login.
  • string caseId: The case unique ID, which can be obtained with caseList().

Return value:

The outputDocumentListResponse object with the following structure:

object outputDocumentListResponse ( object cases ( [0]array ( object caseListStruct ( [string guid] [string filename] [string docId] [integer version] [string createDate] [string createBy] [string type] [integer index] [string link] ) ) ... ) )

Where:

  • string guid: The generated document unique ID (appDocUid). Every time a new document is uploaded, a UID is assigned.
  • string filename: The generated document name.
  • string docId: Corresponds to output document object unique ID, which is assigned during the process design.
  • integer version: The generated document version.
  • string createDate: The date and time when the document was created.
  • string createBy: The username of the user who generated the document.
  • string type: The type of the document.
  • integer index: Indicates in which order along the process, the document is generated. The first output document along the process has index=1, the second index=2, etc.
  • string link: Returns a relative link to download the document: cases/cases_ShowDocument?a=<DOCUMENT-UID>&v=<VERSION>
The relative link can be used in a link field in a DynaForm. If using the link in an email or Output Document, then create an absolute address by concatenating "http://<IP-ADDRESS>/sys<WORKSPACE>/<LANG>/<SKIN>/" and the relative link.

Example:

 $params = array(array('sessionId'=>$sessionId, 'caseId'=>$caseId));
 $result = $client->__SoapCall('outputDocumentList', $params);
 $outputDocumentListArray = $result->documents;
 if ($outputDocumentListArray != (object) NULL)
 {
    if (is_array($outputDocumentListArray))
    {
       foreach ($outputDocumentListArray as $iDocList)
           print "Document Name:    $iDocList->filename
                  Document ID:      $iDocList->guid
                  Document DocID:   $iDocList->docId
                  Document Version: $iDocList->version
                  Document Created: $iDocList->createDate \n"
;
    }
    else
    {
       print "Document Name:    $outputDocumentListArray->filename
              Document ID:      $outputDocumentListArray->guid  
              Document DocID:   $outputDocumentListArray->docId
              Document Version: $outputDocumentListArray->version  
              Document Created: $outputDocumentListArray->createDate \n"
;
    }
 }
 else
    print "Error: $outputDocumentListArray->filename \n";

removeDocument()

removeDocument() removes an uploaded or generated document from a case. Available from version 1.2-3104 and later.

removeDocumentResponse removeDocument(string sessionId, string appDocUid)

Parameters:

Return value:
A pmResponse object. If successful, the message will contain the appDocUid.

Example:

 $params = array(array('sessionId'=>$sessionId, 'appDocUid'=>$appDocUid));
 $result = $client->__SoapCall('removeDocument', $params);

Uploading and Downloading Files

The SOAP and WSDL protocols were not designed for passing files over the internet, so ProcessMaker WSDL web services can not be used to directly upload and download files such as Input Documents, Output Documents and Attached Files. Instead, ProcessMaker WSDL web services can be used to obtain the necessary information, so that other internet protocols can be used to upload and download files to/from a ProcessMaker server.

Uploading Files

In ProcessMaker version 1.2-2372 and later, files can be uploaded to cases at the address:

http://<IP-ADDRESS>/sys<WORKSPACE>/<LANG>/<SKIN>/services/upload

For example, if uploading files to a ProcessMaker server installed at the IP address 192.168.1.100 and using the default "workflow" workspace, the "en" (English) language, and the "green" skin, then use the URL:

http://192.168.1.100/sysworkflow/en/green/services/upload

In order to upload a file to a particular case, parameters need to be passed as POST variables which specify the case UID, the user UID, etc. To set the POST variables and upload the files, it is recommended to use the cURL library which has bindings for most programming languages such as PHP, Java, Perl, Python, Ruby, .NET, etc.

upload POST variables

services/upload accepts the following POST variables:

  • ATTACH_FILE: The name of the file to be uploaded. If not in the same directory, then include the full path. If using cURL to upload the file, then add an @ (ampersand) in front of the filename, so cURL will upload the contents of the file, rather than the filename. For example, '@/home/user/id-photo.png' or '@C:\Documents and Settings\user\My Documents\id-photo.png'. PHP version 5.5 and later has added security restrictions to prevent code injection attacks, so use a CURLFile object instead of the ampersand. See the code examples below.
  • APPLICATION: The unique ID of the case to which the file will be attached. The case UID can be obtained by calling the caseList() web service, by using the @@APPLICATION system variable, or by examining the wf_<WORKSPACE>.APPLICATION.APP_UID field in the database.
  • INDEX: The delegation index number of the case to which the file will be attached. The INDEX is a positive integer which can be obtained by calling the caseList() web service, by using the @@INDEXsystem variable, or by examining the wf_<WORKSPACE>.APPLICATIONS.APP_INDEX field in the database.
  • USR_UID: The unique ID for the user who will upload the file to the case. The user ID can be obtained with the userList() or caseList() web services, from the @@USER_LOGGED system variable, or by examining the wf_<WORKSPACE>.USERS.USR_UID field in the database. This user should have at least one of the following privileges, in order to be able to upload the file:
1. Is the user currently assigned to work on the case.
2. Has the PM_FOLDERS_ADD_FILE permission in his/her role.
3. Is a Process Supervisor who has been assigned rights to the specified Input Document.
  • DOC_UID: The unique ID for the Input Document definition, which can be obtained by using InputDocumentProcessList() web service, by opening the list of Input Documents for a process and clicking on its UID link, or by examining the wf_<WORKSPACE>.INPUT_DOCUMENT.INP_DOC_UID field in the database. If uploading an attached file to a case, then set the DOC_UID to '-1'.
  • APP_DOC_TYPE: Indicate the type of file to be uploaded, which can be 'INPUT' for an Input Document or 'ATTACHED' for a file attached to a case.
  • APP_DOC_UID: Optional parameter to specify the unique ID for an existing Input Document file for a case. This parameter is used to overwrite an existing Input Document file for a case or add another version of an existing document if Input Document versioning is enabled (which is an option available in ProcessMaker 1.2-3306Beta and later). The APP_UID_UID can be found with theInputDocumentList() web service or by examining the wf_<WORKSPACE>.APP_DOCUMENT.APP_DOC_UID field in the database. If the APP_DOC_UID parameter is an empty string or unset, then a new file will be added to the Input Document. Remember that Input Documents are boxes which can hold multiple files.
  • TITLE: Optional. A title to identify the uploaded file.
  • COMMENT: Optional. A comment to provide additional information about the uploaded file.

Using PHP's cURL library to upload

These code examples show how to upload a file to a ProcessMaker case using PHP's cURL library. If using a different programming language, the steps will be similar, although the functions and their parameters might be slightly different.

First, create an associative array with the above POST variables names as the array keys:

$params = array(
    'ATTACH_FILE'  => (phpversion() >= "5.5") ? new CurlFile('myfile.ext') : '@myfile.ext',
    'APPLICATION'  => 'XXXXXXXXXXXXXXXXXXXXXXXXXXXXXX',
    'INDEX'        => X,
    'USR_UID'      => 'XXXXXXXXXXXXXXXXXXXXXXXXXXXXXX',
    'DOC_UID'      => 'XXXXXXXXXXXXX',
    'APP_DOC_TYPE' => 'INPUT|ATTACHED',
    'TITLE'        => 'Title for myfile.ext',
    'COMMENT'      => 'Comment for myfile.ext'
);

Then, initiate a cURL session with curl_init() and save its handle to a variable, so it can be later referenced in the script. If the script has already outputted something, for example with print() or echo(), it is a good idea to first flush its output buffers with ob_flush(), so they don't corrupt the headers:

 ob_flush();
 $ch = curl_init();

Next, use curl_setopt() with the CURLOPT_URL option, to set the address where the file will be uploaded:

curl_setopt($ch, CURLOPT_URL, 'http://<IP-ADDRESS>/sys<WORKSPACE>/en/classic/services/upload');

Activate the CURLOPT_RETURNTRANSFER option, so services/upload will return a message, reporting a successful upload or reporting any errors in the upload:

 curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);

Activate the CURLOPT_POST option in order to set POST variables, then use the CURLOPT_POSTFIELDS option to set those POST variables to the values in the associative array:

curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_POSTFIELDS, $params);

If using a secure connection with SSL or TLS, activate the CURLOPT_SSL_VERIFYHOST and CURLOPT_SSL_VERIFYPEER options:

curl_setopt ($ch, CURLOPT_SSL_VERIFYHOST, 1);
curl_setopt ($ch, CURLOPT_SSL_VERIFYPEER, 1);

Once all the cURL options are set, execute the file upload with curl_exec() and save the return message to a variable, so it can be checked:

 $response = curl_exec($ch);

Finally, use curl_close() to close the cURL session, free up system resources, and delete the session handle:

 curl_close($ch);

Uploading Input Documents

To upload an Input Document to a case, set the DOC_UID parameter to the Unique ID for the Input Document definition and set the APP_DOC_TYPE to 'INPUT'.

For example, if uploading the file /home/user/identification.png as an Input Document to a server located at 192.168.1.100, using the "workflow" workspace:

$path = '/home/user/identification.png';
$params = array (
    'ATTACH_FILE'  => (phpversion() >= "5.5") ? new CurlFile($path) : '@' . $path,
    'APPLICATION'  => '5628388134d10f1db768027020151425',
    'INDEX'        => 1,
    'USR_UID'      => '00000000000000000000000000000001',
    'DOC_UID'      => '547CEBEE61202A',
    'APP_DOC_TYPE' => 'INPUT',
    'TITLE'        => "Identification for John Doe",
    'COMMENT'      => "Scanned ID document"
);
 ob_flush();
 $ch = curl_init();
 curl_setopt($ch, CURLOPT_URL, 'http://192.168.1.100/sysworkflow/en/green/services/upload');
 // curl_setopt($ch, CURLOPT_VERBOSE, 1);  //Uncomment to debug
 curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
 curl_setopt($ch, CURLOPT_POST, 1);
 curl_setopt($ch, CURLOPT_POSTFIELDS, $params);
 // curl_setopt ($ch, CURLOPT_SSL_VERIFYHOST, 1); //Uncomment for SSL
 // curl_setopt ($ch, CURLOPT_SSL_VERIFYPEER, 1); //Uncomment for SSL
 $response = curl_exec($ch);
 curl_close($ch);
 print "<html><body><pre>$response</pre></body></html>";

Uploading Attached Files

To upload an attached file to a case, set APP_DOC_TYPE to 'ATTACHED' and DOC_UID to '-1'.

For example, to upload the file /home/user/identification.png to a case:

$path = '/home/user/identification.png';
$params = array (
    'ATTACH_FILE'  => (phpversion() >= "5.5") ? new CurlFile($path) : '@' . $path,
    'APPLICATION'  => '5628388134d10f1db768027020151425',
    'INDEX'        => 1,
    'USR_UID'      => '00000000000000000000000000000001',
    'DOC_UID'      => '-1',
    'APP_DOC_TYPE' => 'ATTACHED',
    'TITLE'        => "Identification for John Doe",
    'COMMENT'      => "Scanned ID document"
 );
 ob_flush();
 $ch = curl_init();
 curl_setopt($ch, CURLOPT_URL, 'http://192.168.1.100/sysworkflow/en/green/services/upload');
 // curl_setopt($ch, CURLOPT_VERBOSE, 1);  //Uncomment to debug
 curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
 curl_setopt($ch, CURLOPT_POST, 1);
 curl_setopt($ch, CURLOPT_POSTFIELDS, $params);
 // curl_setopt ($ch, CURLOPT_SSL_VERIFYHOST, 1); //Uncomment for SSL
 // curl_setopt ($ch, CURLOPT_SSL_VERIFYPEER, 1); //Uncomment for SSL
 $response = curl_exec($ch);
 curl_close($ch);
 print "<html><body><pre>$response</pre></body></html>";

Overwriting files or adding new versions

If overwriting an existing attached file or Input Document file (or if adding a new version to an existing Input Document file if versioning is enabled), set the APP_DOC_UID to the unique ID for the existing file.

For example, to overwrite the input document in the previous example, first lookup the APP_UID_UID with the InputDocumentList() web service or by examining thewf_<WORKSPACE>.APP_DOCUMENT.APP_DOC_UID field in the database:

$path = /home/user/id2.png';
$params = array (
    '
ATTACH_FILE'  => (phpversion() >= "5.5") ? new CurlFile($path) : '@' . $path,
    '
APPLICATION'  => '5628388134d10f1db768027020151425',
    '
INDEX'        => 1,
    '
USR_UID'      => '00000000000000000000000000000001',
    '
DOC_UID'      => '547CEBEE61202A',
    '
APP_DOC_TYPE' => 'INPUT',
    '
APP_DOC_UID'  => '12345689abdcef123456789abdcef',
    '
TITLE'        => "Identification for John Doe",
    '
COMMENT'      => "Scanned ID document"
);
ob_flush();
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, '
http://192.168.1.100/sysworkflow/en/green/services/upload');
// curl_setopt($ch, CURLOPT_VERBOSE, 1);  //Uncomment to debug
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_POSTFIELDS, $params);
// curl_setopt ($ch, CURLOPT_SSL_VERIFYHOST, 1); //Uncomment for SSL
// curl_setopt ($ch, CURLOPT_SSL_VERIFYPEER, 1); //Uncomment for SSL
$response = curl_exec($ch);
curl_close($ch);
print "<html><body><pre>$response</pre></body></html>";

Downloading Files

To download an attached file, Input Document file or Output Document File, first use the InputDocumentList() or OutputDocumentList() web services to get a download link for the file. (Alternatively, do a search in the wf_<WORKSPACE>.APP_DOCUMENT.APP_DOC_UID field in the database and manually construct the link from the file's unique ID.)

If the php.ini configuration file contains the setting "allow_url_fopen = On", then functions like file_get_contents() can be used to get the contents of a remote file at a URL. For example:

 # First use login() and caseList() to get the $sessionId and $caseId
$params = array(array('sessionId'=>$sessionId, 'caseId'=>$caseId));
 $result = $client->__SoapCall('outputDocumentList', $params);
 $files = $result->documents;
 if ($result->documents != (object) NULL)
 {
   if (is_array($result->documents))
      $url = $result->documents[0]->link;
   else
      $url = $result->documents->link;
 
   $contents = file_get_contents("http://example.com/sysworkflow/en/green/$url");
 }

Unfortunately, the file_get_contents() function is not very reliable, especially for files larger than 64KB which may experience buffer overflows or slow internet connections which might exceed Apache's keepalive timeout setting (which is 15 seconds by default). To avoid these problems, use cURL to download the files:

 $c = curl_init();
 curl_setopt($c, CURLOPT_RETURNTRANSFER, 1);
 curl_setopt($c, CURLOPT_URL, 'http://example.com/sysworkflow/en/green/$url');
 $contents = curl_exec($c);
 curl_close($c);

PHP's readfile() function can be used to download a ProcessMaker file and display it inside a web browser, but it is important to first set the headers correctly. For example:

 $url = 'http://example.com/sysworkflow/en/green/$url';
 $fsize = filesize($url);
 $path_parts = pathinfo($url);
 $ext = strtolower($path_parts["extension"]);
   
 // Determine Content Type
 switch ($ext) {
    case "pdf": $ctype="application/pdf"; break;
    case "exe": $ctype="application/octet-stream"; break;
    case "zip": $ctype="application/zip"; break;
    case "tar":
    case "tgz":
    case "tbz": $ctype="application/x-tar"; break;
    case "gz" : $ctype= stripos($url, '.tar.gz') === false ? "application/x-gzip" : "application/x-tar"; break;
    case "doc": $ctype="application/msword"; break;
    case "xls": $ctype="application/vnd.ms-excel"; break;
    case "ppt": $ctype="application/vnd.ms-powerpoint"; break;
    case "odt": $ctype="application/vnd.oasis.opendocument.text"; break;
    case "ods": $ctype="application/vnd.oasis.opendocument.spreadsheet"; break;
    case "odp": $ctype="application/vnd.oasis.opendocument.presentation"; break;
    case "gif": $ctype="image/gif"; break;
    case "png": $ctype="image/png"; break;
    case "jpeg":
    case "jpg": $ctype="image/jpg"; break;
    default: $ctype="application/force-download";
 }
 
 header("Pragma: public"); // required
 header("Expires: 0");
 header("Cache-Control: must-revalidate, post-check=0, pre-check=0");
 header("Cache-Control: private",false); // required for certain browsers
 header("Content-Type: $ctype");
 header("Content-Disposition: attachment; filename=\"".basename($url)."\";" );
 header("Content-Transfer-Encoding: binary");
 header("Content-Length: ".$fsize);
 ob_clean();
 flush();
 readfile($url);

Examples

Create User

This example shows how to create a new user with the first name of "Foo", the last name of "Bar" and the username of "foobar":

<?php
 ini_set("soap.wsdl_cache_enabled", "0");
 ini_set('error_reporting', E_ALL);
 ini_set('display_errors', True);
   
 print "<html><body><pre>";
   
 $client = new SoapClient('http://localhost/sysworkflow/en/green/services/wsdl2');
 $pass = 'md5:' . md5('admin');
 $params = array(array('userid'=>'admin', 'password'=>$pass));
 $result = $client->__SoapCall('login', $params);
 
 if ($result->status_code == 0)
    $sessionId = $result->message;
 else
    print "Unable to connect to ProcessMaker.\nError Number: $result->status_code\n" .
         "Error Message: $result->message\n";
 
 $params = array(array('sessionId'=>$sessionId, 'userId' => 'foobar',
    'firstname'=>'Foo', 'lastname'=>'Bar', 'email'=>'foobar@example.com',
    'role'=>'PROCESSMAKER_ADMIN', 'password'=>'foob@r123'));
 $result = $client->__SoapCall('createUser', $params);
 
 if ($result->status_code == 0)
    print "$result->message\nUser UID: $result->userUID";  
 else
    print "Unable to create user.\nError Number: $result->status_code\n" .
         "Error Message: $result->message\n";
 
 print "</pre></body></html>";
?>

Import a List of Users

The above script works to create a single user. If thinking about importing a large list of users, it is probably better to maintain your users in LDAP or Active Directory and import them using as anAuthentication Source.

If your organization doesn't plan to user LDAP or Active Directory, then the following script can be used to import users into ProcessMaker. First, create a list of users and export them as a comma separated value (CSV) file.

For example:

userId;firstname;lastname;email;role;password;DUE_DATE;COUNTRY;CITY;LOCATION;ADDRESS;PHONE;ZIP_CODE;DEPARTMENT;POSITION;REPORTS_TO;REPLACED_BY jbossy;John Q.;Bossy;jbossy@example.com;PROCESSMAKER_MANAGER;2015-01-31;US;Florida;Boca Raton;404 W. Elm St.;987-654-3210;46135;;CEO;;janevp mcounter;Mary;Counter;mcounter@example.com;PROCESSMAKER_OPERATOR;2015-12-01;US;Indiana;Greencastle;714 E. Oak Ave;123-456-7890;52201;Accounting;Chief Accountant;jbossy;bobbilling ...

The first line indicates the names of the fields in the CSV file and will be ignored when parsing the file. Each line thereafter contains fields of information about a user to import into Processmaker. The first six fields, userId;firstname;lastname;email;role;password, will be used as the parameters for the createUser() function. The rest of the fields will be inserted directly into the wf_<WORKSPACE>.USERS table.

The script first opens the CVS file and imports this information into an array. Then it looks through each element in the array, calling the createUser() function. After all the users are created in ProcessMaker and they all have records in the wf_<WORKSPACE>.USERS table, then the script will loop through the array a second time, and write the remaining information directly to the wf_<WORKSPACE>.USERS table using PHP's mysql functions. Before writing to the table, the unique IDs for departments and users will have to be looked up, so they can be inserted into the USR_DEPARTMENT, USR_REPORTS_TO and USR_REPLACED_BY fields.

<?php
 ini_set("soap.wsdl_cache_enabled", "0");
 ini_set('error_reporting', E_ALL);
 ini_set('display_errors', True);
 
 #Generic function to lookup information in a ProcessMaker database
function queryDB($varToFind, $query, $fieldToReturn, $errorMsg)
 {
    if (empty($varToFind))
       return '';
 
    $result = mysql_query($query) or
       die("Error: Unable to query database.\n\tQuery:\n\t$query\n");
    $record = mysql_fetch_array($result, MYSQL_ASSOC);
 
    if (!$record)
       die("Error: $errorMsg\n");
 
    return $record["$fieldToReturn"];
 }
 
 # Check if CSV file of users was passed as a parameter to this script
if (argc < 2)
    exit("Error: Must specify a CSV file of users to import.");
 
 # Open the CSV file as an array for each line
$aUsers = file($argv[1]);
 if ($aUsers === false or !is_array($aUsers) or count($aUser) < 2)
    exit("Error: file \"{$argv[1]}\" does not exist or has no content.");
 
 #Remove the first element of the array, which are the column headers:
$aUsers = array_slice($aUsers, 1);
 $aUsersInFields = array();
 
 #Loop through the array and for each user break the line into its individual fields.
#Make sure that there are 17 fields of information for each user; otherwise stop and correct CSV file.
for ($cnt = 0; $len = len($aUsers); $cnt < $len; $cnt++)
 {
   $aUsersInFields[$cnt]= explode(';', $aUsers[$cnt]);
   $fieldCnt = len($aUsersInFields[$cnt]);
   if ($fieldCnt != 17)
      exit("Error in line " . $cnt + 2 . ": Should be 17 fields, but $fieldCnt fields found." .
         "\nCheck:\n{$aUsers[$cnt]}");
 }
   
 #Login to web services
$client = new SoapClient('http://localhost/sysworkflow/en/green/services/wsdl2');
 $pass = 'md5:' . md5('admin');
 $params = array(array('userid'=>'admin', 'password'=>$pass));
 $result = $client->__SoapCall('login', $params);
 
 if ($result->status_code == 0)
    $sessionId = $result->message;
 else
     exit("Unable to connect to ProcessMaker.\nError Number: $result->status_code\n" .
         "Error Message: $result->message\n");
 
 #loop through array of users and create new users with web services
foreach ($aUsersInFields as $user)
 {
    $userId    = trim($user[0]);
    $firstname = trim($user[1]);
    $lastname  = trim($user[2]);
    $email     = trim($user[3]);
    $role      = trim($user[4]);
    $password  = trim($user[5]);    
    $params = array(array('sessionId'=>$sessionId, 'userId' => $userId,
       'firstname'=>$firstname, 'lastname'=>$lastname, 'email'=>$email,
       'role'=>$role, 'password'=>$password));
    $result = $client->__SoapCall('createUser', $params);
 
    if ($result->status_code == 0)
       print "$result->message\nUser UID: $result->userUID";  
    else
       exit("Unable to create user \"$firstname $lastname\" ($userId).\n" .
          "Error Number: $result->status_code\nError Message: $result->message\n");        
 }
 
 #connect to the wf_workflow database used by ProcessMaker
$conn = mysql_connect('localhost:3306', 'root', 'P@ssW0rd') or
    die("Error connecting to mysql.\n");
 mysql_select_db('wf_workflow');
 
 #After all the users are created, loop through and look up unique IDs.
#Then use PHP's mysql functions to insert the values in the USERS table.
foreach($aUsersInFields as $user)
 {
    $userId         = trim($user[0]);
    $dueDate        = empty($user[6]) ? date('Y-m-d', strtotime('+2 year') : trim($user[6]) ;
    $countryName    = trim($user[7]);
    $cityName       = trim($user[8]);  #USERS.USR_CITY field is really the region or state
   $locationName   = trim($user[9]);
    $address        = trim($user[10]);
    $phone          = trim($user[11]);
    $zipCode        = trim($user[12]); #postal code
   $departmentName = trim($user[13]);
    $position       = trim($user[14]);
    $reportsToName  = trim($user[15]);
    $replacedByName = trim($user[16]);
   
    #find the unique ID for the department
   $departmentId = queryDB($departmentName, "SELECT CON_ID FROM CONTENT WHERE
       CON_CATEGORY='DEPO_TITLE' AND CON_VALUE='$departmentName'"
, 'CON_ID',
       "Unable to find department '$departmentName' in the CONTENT table.");
 
    #find the UID for the $reportsToName user in the USERS table
   $reportsToId = queryDB($reportsToName,
       "SELECT USR_UID FROM USERS WHERE USR_USERNAME='$reportsToName'", 'USR_UID',
       "Unable to find the Reports_To user '$reportsToName' in the USERS table.");
 
    #find the UID for the $replacedByName user in the USERS table
   $replacedById = queryDB($replacedByName,
       "SELECT USR_UID FROM USERS WHERE USR_USERNAME='$replacedByName'", 'USR_UID',
       "Unable to find the Replaced_By user '$replacedByName' in the USERS table.");
 
    #find the ID for the $countryName in the ISO_COUNTRY table
   $countryId = queryDB($countryName,
       "SELECT IC_UID FROM ISO_COUNTRY WHERE IC_NAME='$countryName'", 'IC_UID',
       "Unable to find the country '$countryName' in the ISO_COUNTRY table.");
 
    #find the ID for the $cityName in the ISO_SUBDIVISION table
   $cityId = queryDB($cityName, "SELECT IS_UID FROM ISO_SUBDIVISION
       WHERE IC_UID='$countryId' AND IS_NAME='$cityName'"
, 'IS_UID',
       "Unable to find the city '$cityName' in the ISO_SUBDIVISION table.");
 
    #find the ID for the $locationName in the ISO_LOCATION table
   $locationId = queryDB($locationName, "SELECT IL_UID FROM ISO_LOCATION
       WHERE IC_UID='$countryId' AND IS_UID='$cityId' AND IL_NAME='$locationName'"
,
       'IL_UID', "Unable to find the location '$locationName' in the ISO_LOCATION table.");
   
    #write the data to the user's profile in ProcessMaker
   $query = "UPDATE USERS SET USR_DUE_DATE='$dueDate', USR_COUNTRY='$countryId', USR_CITY='$cityId',
       USR_LOCATION='$locationId', USR_ADDRESS='$address', USR_PHONE='$phone', USR_ZIP_CODE='$zipCode',
       USR_DEPARTMENT='$departmentId', USR_POSITION='$position', USR_REPORTS_TO='$reportsToId',
       USR_REPLACED_BY='$replacedById' WHERE USR_USERNAME='$userId'"
;
    mysql_query($query) or die("Error: UPDATE failed:\n\t$query\n");
 }
               
 print "Inserted " . len($aUsersInFields) . " new users in the USERS table.\n";
 ?>

The above script named "importusers.php" can be called from the command line:

php importusers.php userlist.csv

Approval via Email

Web services can be used to allow managers to approve or disapprove a decision directly from an email. In this example, a manager receives an email with links to either approve or disapprove a purchase request. The links lead to a script which sends a variable to the case named "approved". If the manager clicks on the link to approve the purchase, the case will route to one task. If she clicks to disapprove, the case will route to a different task. The evaluation routing rules for these tasks is @@approved == 'yes' and @@approved == 'no', respectively.

First, create following email template named "ManagerDecision.html" in a external HTML editor:

<html>
<body>
<table border="1">
<caption><i>Purchase Request</i></caption>
<tr><th>Date</th><th>Item</th><th>Cost</th></tr>
<tr><td>@#ReqDate</td><td>@#ReqItem</td><td>$@#ReqCost</th></tr>
</table>

<p>Click to <a href="http://192.168.1.100/response.php?approved=yes&case=@#APPLICATION">approve</a> or
<a href="http://192.168.1.100/response.php?approved=no&case=@#APPLICATION">disapprove</a> this purchase.</p>
</body>
</html>

The email will appear something like:


Purchase Request
DateItemCost
09-12-2009Pioneer Big Screen Projector$2000

Click to approve or disapprove this purchase.



Then, upload the email template to your process. Open the process in ProcessMaker and right click on the process map to select the option Process File Manager from the dropdown menu. Go to the mailTemplates directory and click on the Upload link to upload the email template.

Create a trigger to send this email to the manager at a certain point in the process. Use the userInfo() function to lookup the manager's email address and use the PMFSendMessage() function to send the email message.

Then create the script /opt/processmaker/workflow/public_html/response.php on the ProcessMaker server.

From version 2.5.0 you have to create a dummy plugin and create the following script inside its respective public_html folder

In the case of using either both versions mentioned above, the script can be accessed with a web browser at the address http://192.168.1.100/response.php:

<?php
ini_set("soap.wsdl_cache_enabled", "0");
//ini_set('error_reporting', E_ALL); //uncomment to debug
//ini_set('display_errors', True);  //uncomment to debug
 
$client = new SoapClient('http://192.168.1.100/sysworkflow/en/green/services/wsdl2');
$pass = 'md5:' . md5('admin');
$params = array(array('userid'=>'admin', 'password'=>$pass));
$result = $client->__SoapCall('login', $params);
 
if ($result->status_code == 0)
    $sessionId = $result->message;
else
    die("<html><body><pre> Unable to connect to ProcessMaker.\n" .
        "Error Message: $result->message </pre></body></html>");
 
class variableStruct {
    public $name;
    public $value;
}
 
$var = new variableStruct();
$var->name = "approved";
$var->value = $_GET['approved'];
 
$variables = array($var);
$params = array(array('sessionId'=>$sessionId, 'caseId'=>$_GET['case'], 'variables'=>$variables));
$result = $client->__SoapCall('sendVariables', $params);
if ($result->status_code != 0)
   die("<html><body><pre> Error: $result->message </pre></body></html>";
 
//Use routeCase() to route the case using the case variable @@approved in the evaluation condition
 
?>

Automatic Login

ProcessMaker's web services login() function can be used to login in a user and acquire a session ID in an external script. Using that session ID, the web browser can then be directed to any address inside ProcessMaker, thus bypassing the login screen. To avoid a manual login, pass the session ID as the GET variable "sid" in a ProcessMaker URL:

http://<IP-ADDRESS>:<PORT>/sys<WORKSPACE>/<LANGUAGE>/<SKIN>/<MENU>/<SUBMENU>?sid=<SESSION-ID>

For example, if wanting to go directly to the USERS LIST in ProcessMaker 1.X on a server located at 192.168.1.100, using the default "workflow" workspace, the "en" (English) language and the default "green" skin, with a session ID of "3D2187041194d000bca6b8756033322858":

http://192.168.1.100/sysworkflow/en/green/users/users_List?sid=3D2187041194d000bca6b8756033322858

In the following script, web services login the "admin" user and acquire a session ID. PHP's header() function is then used to redirect the web browser to the Cases List inside ProcessMaker. The session ID is passed as the "sid" GET variable inside the URL:

<?php
ini_set("soap.wsdl_cache_enabled", "0");
//ini_set('error_reporting', E_ALL); //uncomment to debug
//ini_set('display_errors', True);  //uncomment to debug
     
$client = new SoapClient('http://192.168.1.100/sysworkflow/en/classic/services/wsdl2');
$pass = 'md5:' . md5('admin');
$params = array(array('userid'=>'admin', 'password'=>$pass));
$result = $client->__SoapCall('login', $params);
 
if ($result->status_code == 0)
{
    $sessionId = $result->message;
    header("Location: http://192.168.1.100/sysworkflow/en/green/cases/main?sid=$sessionId");
}
else
    die("<html><body><pre> Unable to connect to ProcessMaker.\n" .
        "Error Message: $result->message");
?>

It is important to not print anything with this script before calling the header() function, otherwise it will corrupt the HTTP header, causing error messages like:

Warning: Cannot modify header information - headers already sent by (output started at script-name.php:16) in script-name.php on line 18.

If your script needs to print something before using the header() function to redirect to a different web page, then use the ob_flush() or ob_clean() function to clear out the header's output buffer beforehand.

Note: The "neoclassic" skin and many features are found inside <iframes>. These features can still be directly addressed, but they will appear without the header and menus. To show the content of a particular <iframe> inside the normal parent frame with the header and menu, javascript code needs to be added. For instance, in version 2.0, the users list is now found under the ADMIN menu, so do automatic login to this URL:

http://192.168.1.100/sysworkflow/en/classic/setup/main?sid=3D2187041194d000bca6b8756033322858

Then, execute the following PHP code which will execute JavaScript to redirect the "setup-frame" iframe to the address "../users/users_List":

echo "<script>document.getElementById('setup-frame').src='../users/users_List';</script>";