<?php
/**
 * IMPORTANT NOTE
 * The code of this system is closed and a private proprietary of Flex Solutions.
 * A written authorization/license from Flex Solutions is required before using or modifying this code.
 * Email: sales@flexsolution.biz, Phone: +962795342585, Website: http://www.flexsolutions.biz
 */
 

// We will disable the warning in order to avoid warning messages in case the search method return an empty result
error_reporting(~E_WARNING);

/*
 *  This class will implement the basic LDAP methods required by this application, these methods are
 *  1- Connect to the LDAP server
 *  2- Bind a user to the LDAP server
 *  3- Search the ldap directory
 */

class LDAP
    {
    /* Class Attribute */

    // The ldap connnection
    public static $ldap_conn;
    // The first ldap server (for search)
    public static $first_ldap_server;
    // The redundant ldap server (for search)
    public static $second_ldap_server;
    // The authentication ldap server
    public static $authentication_ldap_server;
    // The ldap server's port number
    public static $ldap_port;
    // The base DN
    public static $base_dn;

    /*
     * This method will try to establish a connection to the ldap server
     *  The Outputs:
     *      The output of this method is eihter true or false
     *          True: The connection is established successfully.
     *          Flase: The connection cannot be established.
     */
    static function connect($server_type = "search")
    {
        // Get the connection settings from the Settings array (i.e. from the database)
        $settings_array = Setting::getSettingsArray();
        self::$first_ldap_server = isset($settings_array["first_ldap_server"]) ? $settings_array["first_ldap_server"] : "";
        self::$second_ldap_server = isset($settings_array["second_ldap_server"]) ? $settings_array["second_ldap_server"] : "";
        self::$ldap_port = isset($settings_array["ldap_port"]) ? $settings_array["ldap_port"] : "";
        self::$base_dn = isset($settings_array["base_dn"]) ? $settings_array["base_dn"] : "";
        self::$authentication_ldap_server = isset($settings_array["authentication_ldap_server"]) ? $settings_array["authentication_ldap_server"] : "";
        
        // Connect to the first ldap server
        self::$ldap_conn = ldap_connect(self::$first_ldap_server, self::$ldap_port);

        // Check if the connection was successfully established, if not then try to connect to the second server
        if (!self::$ldap_conn)
        {
            // Connect to the second server (i.e. the redundant server)
            if ($second_ldap_server)
            {
                self::$ldap_conn = ldap_connect(self::$second_ldap_server, self::$ldap_port);
            }
        }

        // Override the connection in case it will be used for the authentication
        if($server_type == "authentication"){
            self::$ldap_conn = ldap_connect(self::$authentication_ldap_server, self::$ldap_port);
        }

        if (self::$ldap_conn)
        {
            // The connection is established successfully.
            return true;
        }
        else
        {
            // The connection cannot be established.
            return false;
        }
    }

    /*
     * This method will try to bind a credentials to the ldap server
     *  The Inputs:
     *      $username: The username that is needed to be binded
     *      $password: The password that is needed to be binded in addition to the username
     *  The Outputs:
     *      The output of this method is eihter true or false
     *          True: The binding done.
     *          Flase: The binding failed.
     */

    static function bind( $username = "", $password = "" )
    {
        $server_type = "search";
        
        // Check if the username and password are passed (=> connect for authentication not search), i.e. we need to connect to the authentication server
        if ($username != "" && $password != "")
        {
            $server_type = "authentication";
        }

        // The connection should be established first
        if (self::connect($server_type))
        {
            // Check if the passed credentials represent an anonymous user
            if ($username == "" && $password == "")
            {
                // bind to the ldap server anonymously
                $ldapbind = ldap_bind(self::$ldap_conn);
            }
            else
            {
                // bind to the ldap server normally
                // NOTE: for the active directory binding the username should be the email of the user (e.g. admin@exchange.slb.com but without the exchange => the email should be admin@slb.com)
                if(strpos($username, "exchange.") !== false){
                    $username = str_replace("exchange.", "", $username);
                }

                $ldapbind = ldap_bind(self::$ldap_conn, $username, $password);
            }

            // Verify binding
            if (!$ldapbind)
            {
                // The binding done successfully.
                return false;
            }
            else
            {
                // The binding done failed.
                return true;
            }
        }
    }

    /*
     * This method will search for a user by his alias, if found it will set his email (to be returned)
     *  The Inputs:
     *      $alias: The alias of the user to be used in the search criteria
     *  The Outputs:
     *      &$email: The email of the user, it is an output parameter, it will be set if the user found.
     *      return value: The return value of this method is the error message, in case the search failed.
     */

    static function getUserEmailByAlias( $alias, &$email )
    {
        try
        {
            // First, we will try to bind to the server anonymously (not that the bind will establish a connection)
            if (self::bind())
            {
                // The rows returned by the search method
                $rows = "";
                $search_filter = "(alias=$alias)";

                // Perform the search, note that we will limit the search be 1 result since the alias is unique
                $results = ldap_search(self::$ldap_conn, self::$base_dn, $search_filter, array("mail"), 0, 1);

                // Check if the search failed
                if (!$results)
                {
                    $email = "";
                    return yii::t('default', 'This username is not exist in the LDAP directory.');
                }
                else
                {
                    // Get the rows from using the returned result
                    $rows = ldap_get_entries(self::$ldap_conn, $results);

                    // check if there is no rows with the returned result
                    if (!$rows || !isset($rows[0]))
                    {
                        $email = "";
                        return yii::t('default', 'This username is not exist in the LDAP directory.');
                    }
                    else
                    {
                        // There search returned rows, so we will get the first one
                        $email = isset($rows[0]["mail"]) ? $rows[0]["mail"][0] : "-"; // we used "-" in case the email not set
                        return "";
                    }
                }
            }
            else // The bind failed
            {
                $email = "";
                return yii::t('default', 'Cannot connect to the LDAP server, please contact the system administrator.');
            }
        }
        catch (Exception $exc)
        {
            $email = "";
            return yii::t('default', 'Cannot connect to the LDAP server, please contact the system administrator.');
        }
    }

    /*
     * This method will search for a user by his alias, if found it will set gridDataProvider (to be returned)
     *  The Inputs:
     *      $alias: The alias of the user to be used in the search criteria
     *  The Outputs:
     *      &$gridDataProvider: The email of the user, it is an output parameter, it will be set if the user found.
     *      return value: The return value of this method is the error message, in case the search failed.
     */

    static function getUsers( $person_info, &$gridDataProvider )
    {
        try
        {
            // First, we will try to bind to the server anonymously (not that the bind will establish a connection)
            if (self::bind())
            {
                // The rows returned by the search method
                $gridDataProvider = null;
                $search_filter = "(|(cn=*$person_info*)(alias=*$person_info*)(employeeNumber=*$person_info*))";

                // Perform the search, note that we will limit the search be 1 result since the alias is unique
                $results = ldap_search(self::$ldap_conn, self::$base_dn, $search_filter, array("cn", "alias", "employeenumber", "employeetype", "mobile", "mail", "manager"), 0, 100);

                // Check if the search failed
                if (!$results)
                {
                    $gridDataProvider = null;
                    return yii::t('default', 'There is no result matching the requesting criteria');
                }
                else
                {
                    // Get the rows from using the returned result
                    $rows = ldap_get_entries(self::$ldap_conn, $results);

                    // check if there is no rows with the returned result
                    if (!$rows || !isset($rows[0]))
                    {
                        $gridDataProvider = null;
                        return yii::t('default', 'There is no result matching the requesting criteria');
                    }
                    else
                    {
                        // There search returned rows, so we willencapsulation it in arrayDataProvider object 
                        $all_person_LDAP=array();
                        for ($i = 0; $i < $rows["count"]; $i++)
                        {
                            $cn = isset($rows[$i]["cn"]) ? $rows[$i]["cn"][0] : "-";
                            $alias = isset($rows[$i]["alias"]) ? $rows[$i]["alias"][0] : "-";
                            $employeenumber = isset($rows[$i]["employeenumber"]) ? $rows[$i]["employeenumber"][0] : "-";
                            $employeetype = isset($rows[$i]["employeetype"]) ? $rows[$i]["employeetype"][0] : "-";
                            $mobile = isset($rows[$i]["mobile"]) ? $rows[$i]["mobile"][0] : "-";
                            $mail = isset($rows[$i]["mail"]) ? $rows[$i]["mail"][0] : "-";
                            $manager = isset($rows[$i]["manager"]) ? $rows[$i]["manager"][0] : "-";
                            $person_LDAP=array('id'=>$cn,'alias'=>$alias,'employeenumber'=>$employeenumber,'employeetype'=>$employeetype,'mobile'=>$mobile,'mail'=>$mail,'manager'=>$manager);
                            array_push($all_person_LDAP, $person_LDAP);
                        }
                        $gridDataProvider = new CArrayDataProvider($all_person_LDAP);
                        return "";
                    }
                }
            }
            else // The bind failed
            {
                $gridDataProvider = null;
                return yii::t('default', 'Cannot connect to the LDAP server, please contact the system administrator.');
            }
        }
        catch (Exception $exc)
        {
            $gridDataProvider = null;
            return yii::t('default', 'Cannot connect to the LDAP server, please contact the system administrator.');
        }
    }

    /*
     * This method will search for a user by his alias, if found it will set Person (to be returned)
     *  The Inputs:
     *      $alias: The alias of the user to be used in the search criteria
     *  The Outputs:
     *      &$Person: The LDAP Person, it is an output parameter, it will be set if the user found.
     *      return value: The return value of this method is the error message, in case the search failed.
     */

    static function getPersonByAlias( $alias, &$Person )
    {
        try
        {
            // First, we will try to bind to the server anonymously (not that the bind will establish a connection)
            if (self::bind())
            {
                // The rows returned by the search method
                $Person = null;
                $search_filter = "(alias=$alias)";

                // Perform the search, note that we will limit the search be 1 result since the alias is unique
                $results = ldap_search(self::$ldap_conn, self::$base_dn, $search_filter, array("cn", "alias", "employeenumber", "employeetype", "mobile", "mail", "manager","applicationmifareno"), 0, 100);

                // Check if the search failed
                if (!$results)
                {
                    $Person = null;
                    return yii::t('default', 'There is no result matching the requesting criteria');
                }
                else
                {
                    // Get the rows from using the returned result
                    $rows = ldap_get_entries(self::$ldap_conn, $results);

                    // check if there is no rows with the returned result
                    if (!$rows || !isset($rows[0]))
                    {
                        $Person = null;
                        return yii::t('default', 'There is no result matching the requesting criteria');
                    }
                    else
                    {
                        // There search returned rows, so we willencapsulation it in arrayDataProvider object
                            $cn = isset($rows[0]["cn"]) ? $rows[0]["cn"][0] : "-";
                            $alias = isset($rows[0]["alias"]) ? $rows[0]["alias"][0] : "-";
                            $employeenumber = isset($rows[0]["employeenumber"]) ? $rows[0]["employeenumber"][0] : "-";
                            $employeetype = isset($rows[0]["employeetype"]) ? $rows[0]["employeetype"][0] : "-";
                            $mobile = isset($rows[0]["mobile"]) ? $rows[0]["mobile"][0] : "-";
                            $mail = isset($rows[0]["mail"]) ? $rows[0]["mail"][0] : "-";
                            $manager = isset($rows[0]["manager"]) ? $rows[0]["manager"][0] : "-";
                            $badge_number = isset($rows[0]["applicationmifareno"]) ? $rows[0]["applicationmifareno"][0] : "-";
                            $Person=array('cn'=>$cn,'alias'=>$alias,'employeenumber'=>$employeenumber,'employeetype'=>$employeetype,'mobile'=>$mobile,'mail'=>$mail,'manager'=>$manager,'badge_number'=>$badge_number);
                            
                        return "";
                    }
                }
            }
            else // The bind failed
            {
                $Person = null;
                return yii::t('default', 'Cannot connect to the LDAP server, please contact the system administrator.');
            }
        }
        catch (Exception $exc)
        {
            $Person = null;
            return yii::t('default', 'Cannot connect to the LDAP server, please contact the system administrator.');
        }
    }


    /*
     * This method will search for a user by his cn, if found it will set Person (to be returned)
     *  The Inputs:
     *      $cn: The cn of the user to be used in the search criteria
     *  The Outputs:
     *      &$Person: The LDAP Person, it is an output parameter, it will be set if the user found.
     *      return value: The return value of this method is the error message, in case the search failed.
     */

    static function getPersonByCn( $cn, &$Person )
    {
        try
        {
            // First, we will try to bind to the server anonymously (not that the bind will establish a connection)
            if (self::bind())
            {
                // The rows returned by the search method
                $Person = null;
                $search_filter = "(cn=$cn)";

                // Perform the search, note that we will limit the search be 1 result since the alias is unique
                $results = ldap_search(self::$ldap_conn, self::$base_dn, $search_filter, array("cn", "alias", "employeenumber", "employeetype", "mobile", "mail", "manager","applicationmifareno"), 0, 100);

                // Check if the search failed
                if (!$results)
                {
                    $Person = null;
                    return yii::t('default', 'There is no result matching the requesting criteria');
                }
                else
                {
                    // Get the rows from using the returned result
                    $rows = ldap_get_entries(self::$ldap_conn, $results);

                    // check if there is no rows with the returned result
                    if (!$rows || !isset($rows[0]))
                    {
                        $Person = null;
                        return yii::t('default', 'There is no result matching the requesting criteria');
                    }
                    else
                    {
                        // There search returned rows, so we will encapsulation it in arrayDataProvider object
                            $cn = isset($rows[0]["cn"]) ? $rows[0]["cn"][0] : "-";
                            $alias = isset($rows[0]["alias"]) ? $rows[0]["alias"][0] : "-";
                            $employeenumber = isset($rows[0]["employeenumber"]) ? $rows[0]["employeenumber"][0] : "-";
                            $employeetype = isset($rows[0]["employeetype"]) ? $rows[0]["employeetype"][0] : "-";
                            $mobile = isset($rows[0]["mobile"]) ? $rows[0]["mobile"][0] : "-";
                            $mail = isset($rows[0]["mail"]) ? $rows[0]["mail"][0] : "-";
                            $manager = isset($rows[0]["manager"]) ? $rows[0]["manager"][0] : "-";
                            $badge_number = isset($rows[0]["applicationmifareno"]) ? $rows[0]["applicationmifareno"][0] : "-";
                            $Person=array('cn'=>$cn,'alias'=>$alias,'employeenumber'=>$employeenumber,'employeetype'=>$employeetype,'mobile'=>$mobile,'mail'=>$mail,'manager'=>$manager,'badge_number'=>$badge_number);

                        return "";
                    }
                }
            }
            else // The bind failed
            {
                $Person = null;
                return yii::t('default', 'Cannot connect to the LDAP server, please contact the system administrator.');
            }
        }
        catch (Exception $exc)
        {
            $Person = null;
            return yii::t('default', 'Cannot connect to the LDAP server, please contact the system administrator.');
        }
    }


    /*
     * This method will search for a user by his Number, if found it will set Person (to be returned)
     *  The Inputs:
     *      $number: The employeenumber of the user to be used in the search criteria
     *  The Outputs:
     *      &$Person: The LDAP Person, it is an output parameter, it will be set if the user found.
     *      return value: The return value of this method is the error message, in case the search failed.
     */

    static function getPersonByNumber( $number, &$Person )
    {
        try
        {
            // First, we will try to bind to the server anonymously (not that the bind will establish a connection)
            if (self::bind())
            {
                // The rows returned by the search method
                $Person = null;
                $search_filter = "(employeenumber=$number)";

                // Perform the search, note that we will limit the search be 1 result since the number is unique
                $results = ldap_search(self::$ldap_conn, self::$base_dn, $search_filter, array("cn", "alias", "employeenumber", "employeetype", "mobile", "mail", "manager","applicationmifareno"), 0, 100);

                // Check if the search failed
                if (!$results)
                {
                    $Person = null;
                    return yii::t('default', 'This Employee Number {n} is not exist in the LDAP directory.',$number);
                }
                else
                {
                    // Get the rows from using the returned result
                    $rows = ldap_get_entries(self::$ldap_conn, $results);

                     // check if there is no rows with the returned result
                    if (!$rows || !isset($rows[0]))
                    {
                        $Person = null;
                        return yii::t('default', 'This Employee Number {n} is not exist in the LDAP directory.',$number);
                    }
                    else
                    {
                        // There search returned rows, so we willencapsulation it in arrayDataProvider object
                            $cn = isset($rows[0]["cn"]) ? $rows[0]["cn"][0] : "-";
                            $alias = isset($rows[0]["alias"]) ? $rows[0]["alias"][0] : "-";
                            $employeenumber = isset($rows[0]["employeenumber"]) ? $rows[0]["employeenumber"][0] : "-";
                            $employeetype = isset($rows[0]["employeetype"]) ? $rows[0]["employeetype"][0] : "-";
                            $mobile = isset($rows[0]["mobile"]) ? $rows[0]["mobile"][0] : "-";
                            $mail = isset($rows[0]["mail"]) ? $rows[0]["mail"][0] : "-";
                            $manager = isset($rows[0]["manager"]) ? $rows[0]["manager"][0] : "-";
                            $badge_number = isset($rows[0]["applicationmifareno"]) ? $rows[0]["applicationmifareno"][0] : "-";
                            $Person=array('cn'=>$cn,'alias'=>$alias,'employeenumber'=>$employeenumber,'employeetype'=>$employeetype,'mobile'=>$mobile,'mail'=>$mail,'manager'=>$manager,'badge_number'=>$badge_number);

                        return "";
                    }
                }
            }
            else // The bind failed
            {
                $Person = null;
                return yii::t('default', 'Cannot connect to the LDAP server, please contact the system administrator.');
            }
        }
        catch (Exception $exc)
        {
            $Person = null;
            return yii::t('default', 'Cannot connect to the LDAP server, please contact the system administrator.');
        }
    }

    }

