update syncuuids for Egon
[tine20] / scripts / syncuuids / lib / Sync.php
1 <?php
2 /**
3  * Tine 2.0
4  *
5  * @package     Sync
6  * @author      Philipp Schüle <p.schuele@metaways.de
7  * @license     http://www.gnu.org/licenses/agpl.html AGPL Version 3
8  * @copyright   Copyright (c) 2008-2015 Metaways Infosystems GmbH (http://www.metaways.de)
9  */
10
11 /**
12  * class documentation
13  *
14  * @package     Sync
15  */
16 class Sync 
17 {
18     /**
19      * configuration
20      * 
21      * @var Zend_Config
22      */
23     protected $_config = NULL;
24     
25     /**
26      * logger
27      * 
28      * @var Zend_Log
29      */
30     protected $_logger = NULL;
31     
32     /**
33      * ldap connector
34      * 
35      * @var Zend_Ldap
36      */
37     protected $_ldap = NULL;
38
39    /**
40     * the basic group ldap filter (for example the objectclass)
41     *
42     * default LDAP:  'objectclass=posixgroup'
43     * Samba:         'objectclass=group'
44     *
45     * @var string
46     */
47     protected $_groupBaseFilter = 'objectclass=group';
48     
49    /**
50     * the basic user ldap filter (for example the objectclass)
51     *
52     * default LDAP:  'objectclass=posixaccount'
53     * Samba:         'objectclass=user'
54     *
55     * @var string
56     */
57     protected $_userBaseFilter = 'objectclass=user';
58
59     /**
60      * username property
61      *
62      * default LDAP: 'uid'
63      * Samba:        'samaccountname'
64      *
65      * @var string
66      */
67     protected $_usernameProperty = 'samaccountname';
68
69     /**
70      * uuid property
71      *
72      * default LDAP: 'entryuuid'
73      * Samba:        'objectguid'
74      *
75      * @var string
76      */
77     protected $_uuidProperty = 'objectguid';
78
79     /**
80     * the tine user backend
81     *
82     * @var Tinebase_User_Sql
83     */
84     protected $_tineUserBackend = NULL;
85     
86     /**
87      * the tine group backend
88     *
89     * @var Tinebase_Group_Sql
90     */
91     protected $_tineGroupBackend = NULL;
92     
93     /**
94     * the basic user search scope
95     *
96     * @var integer
97     */
98     protected $_userSearchScope = Zend_Ldap::SEARCH_SCOPE_SUB;
99     
100     /**
101     * the basic group search scope
102     *
103     * @var integer
104     */
105     protected $_groupSearchScope     = Zend_Ldap::SEARCH_SCOPE_SUB;
106     
107     /**
108      * the constructor
109      */
110     public function __construct()
111     {
112         $this->_initSettings();
113         $this->_initConfig();
114         $this->_initLogger();
115         $this->_initLdap();
116         $this->_initTineBackends();
117         
118         $this->_logger->info(__METHOD__ . '::' . __LINE__ . ' init complete');
119     }
120     
121     /**
122      * init php settings
123      */
124     protected function _initSettings()
125     {
126         error_reporting(E_COMPILE_ERROR | E_CORE_ERROR | E_ERROR | E_PARSE);
127         ini_set('display_errors', 1);
128         ini_set('log_errors', 1);
129         set_error_handler('Tinebase_Core::errorHandler', E_ALL);
130
131         if (PHP_VERSION_ID > 50600) {
132             ini_set('default_charset', 'UTF-8');
133         } else {
134             // set default internal encoding
135             if (extension_loaded('iconv')) {
136                 iconv_set_encoding('internal_encoding', "UTF-8");
137             }
138         }
139     }
140     
141     /**
142      * init config
143      */
144     protected function _initConfig()
145     {
146         $configData = include('conf.php');
147         if ($configData === false) {
148             die ('central configuration file config.inc.php not found in includepath: ' . get_include_path());
149         }
150         $this->_config = new Zend_Config($configData);
151         
152         if (! $this->_config->inputfile) {
153             die('need inputfile in config');
154         }
155     }
156
157     /**
158      * init config
159      */
160     protected function _initLogger()
161     {
162         $this->_logger = new Zend_Log();
163         if ($this->_config->logfile) {
164             $writer = new Zend_Log_Writer_Stream($this->_config->logfile);
165         } else {
166             $writer = new Zend_Log_Writer_Null;
167         }
168         $this->_logger->addWriter($writer);
169         
170         if ($this->_config->loglevel) {
171             $filter = new Zend_Log_Filter_Priority($this->_config->loglevel);
172             $this->_logger->addFilter($filter);
173         }
174     }
175     
176     /**
177      * returns config
178      * 
179      * @return Zend_Config
180      */
181     public function getConfig()
182     {
183         return $this->_config;
184     }
185     
186     /**
187      * init ldap
188      */
189     protected function _initLdap()
190     {
191         if (! $this->_config->ldap || ! $this->_config->ldap->baseDn) {
192             throw new Exception('ldap config section or basedn missing');
193         }
194         
195         $this->_ldap = new Zend_Ldap($this->_config->ldap->toArray());
196         $this->_ldap->bind();
197         $this->_logger->info(__METHOD__ . '::' . __LINE__ . ' LDAP initialized');
198     }
199
200     /**
201     * init tine backends
202     */
203     protected function _initTineBackends()
204     {
205         Tinebase_Core::setupConfig();
206         Tinebase_Core::setupDatabaseConnection();
207         
208         $this->_tineUserBackend = new Tinebase_User_Sql();
209         $this->_tineGroupBackend = new Tinebase_Group_Sql();
210     }
211     
212     /**
213      * sync user/group ids in db dump
214      */
215     public function doSync()
216     {
217         $userMapping = $this->_getUserMapping();
218         $groupMapping = $this->_getGroupMapping();
219         
220         if ($this->_config->dryrun) {
221             echo "user mapping:\n" . print_r($userMapping, TRUE);
222             echo "group mapping:\n" . print_r($groupMapping, TRUE);
223         } else {
224             $this->_syncIdsInDump(array_merge($userMapping, $groupMapping));
225             $this->_logger->info(__METHOD__ . '::' . __LINE__ . ' Sync finished.');
226         }
227     }
228     
229     /**
230      * read ldap / get users from tine an create mapping
231      * 
232      * @return array
233      */
234     protected function _getUserMapping()
235     {
236         $this->_logger->info(__METHOD__ . '::' . __LINE__ . ' Fetching user mapping ...');
237         
238         $filter = Zend_Ldap_Filter::andFilter(
239             Zend_Ldap_Filter::string($this->_userBaseFilter)
240         );
241         $mapping = array();
242         $ldapUsers = $this->_ldap->search($filter, $this->_config->ldap->baseDn, $this->_userSearchScope, array('*', '+'));
243         foreach ($ldapUsers as $user) {
244             $username = $user[$this->_usernameProperty][0];
245             $ldapUuid = ($this->_uuidProperty === 'objectguid')
246                 ? Tinebase_Ldap::decodeGuid($user['objectguid'][0])
247                 : $user[$this->_uuidProperty][0];
248
249             try {
250                 $tineUser = $this->_tineUserBackend->getFullUserByLoginName($username);
251                 $this->_logger->debug(__METHOD__ . '::' . __LINE__ . ' User ' . $username . ': ' . $tineUser->getId() . ' -> ' . $ldapUuid);
252                 $mapping[$tineUser->getId()] = $ldapUuid;
253             } catch (Tinebase_Exception_NotFound $tenf) {
254                 $this->_logger->debug(__METHOD__ . '::' . __LINE__ . ' User ' . $username . ' not found.');
255             }
256         }
257         
258         $this->_logger->info(__METHOD__ . '::' . __LINE__ . ' Found ' . count($mapping) . ' users for the mapping.');
259         $this->_logger->debug(__METHOD__ . '::' . __LINE__ . ' ' . print_r($mapping, TRUE));
260         
261         return $mapping;
262     }
263
264     /**
265      * read ldap / get users and groups from tine an create mapping
266      * 
267      * @return array
268      */
269     protected function _getGroupMapping()
270     {
271         $this->_logger->info(__METHOD__ . '::' . __LINE__ . ' Fetching user mapping ...');
272         
273         $filter = Zend_Ldap_Filter::andFilter(
274             Zend_Ldap_Filter::string($this->_groupBaseFilter)
275         );
276         $mapping = array();
277         $groupNameMapping = ($this->_config->groupNameMapping) ? $this->_config->groupNameMapping->toArray() : array();
278         $this->_logger->debug(__METHOD__ . '::' . __LINE__ . ' Group name mapping: ' . print_r($groupNameMapping, TRUE));
279         $ldapGroups = $this->_ldap->search($filter, $this->_config->ldap->baseDn, $this->_groupSearchScope, array('*', '+'));
280         foreach ($ldapGroups as $group) {
281             $groupname = (isset($groupNameMapping[$group['cn'][0]])) ? $groupNameMapping[$group['cn'][0]] : $group['cn'][0];
282             $ldapUuid = ($this->_uuidProperty === 'objectguid')
283                 ? Tinebase_Ldap::decodeGuid($group['objectguid'][0])
284                 : $group[$this->_uuidProperty][0];
285
286             try {
287                 $tineGroup = $this->_tineGroupBackend->getGroupByName($groupname);
288                 $this->_logger->debug(__METHOD__ . '::' . __LINE__ . ' Group ' . $groupname . ' (' .$group['cn'][0] . '): ' . $tineGroup->getId() . ' -> ' . $ldapUuid);
289                 $mapping[$tineGroup->getId()] = $ldapUuid;
290             } catch (Tinebase_Exception_Record_NotDefined $tenf) {
291                 // @todo should be: Tinebase_Exception_NotFound 
292                 $this->_logger->debug(__METHOD__ . '::' . __LINE__ . ' Group ' . $groupname . ' (' .$group['cn'][0] . '): ' . $tenf->getMessage());
293             }
294         }
295         
296         $this->_logger->info(__METHOD__ . '::' . __LINE__ . ' Found ' . count($mapping) . ' groups for the mapping.');
297         $this->_logger->debug(__METHOD__ . '::' . __LINE__ . ' ' . print_r($mapping, TRUE));
298         
299         return $mapping;
300     }
301     
302     /**
303      * syncs the ids in a sql dump file
304      * 
305      * @param array $mapping
306      */
307     protected function _syncIdsInDump($mapping)
308     {
309         // use mapping for str_replace
310         if (! file_exists($this->_config->inputfile)) {
311             die('file does not exist');
312         }
313         $this->_logger->info(__METHOD__ . '::' . __LINE__ . ' Reading input file: ' . $this->_config->inputfile);
314         $input = file_get_contents($this->_config->inputfile);
315         $this->_logger->info(__METHOD__ . '::' . __LINE__ . ' Replacing ids ...');
316         $output = str_replace(array_keys($mapping), array_values($mapping), $input);
317         
318         $filename = ($this->_config->outputfile) ? $this->_config->outputfile : 'synced.sql';
319         $this->_logger->info(__METHOD__ . '::' . __LINE__ . ' Writing to file: ' . $filename);
320         file_put_contents($filename, $output);
321     }
322 }