GitHub Access Token became invalid

It seems like the GitHub access token used for retrieving details about this repository from GitHub became invalid. This might prevent certain types of inspections from being run (in particular, everything related to pull requests).
Please ask an admin of your repository to re-new the access token on this website.
Passed
Pull Request — master (#28)
by
unknown
02:31
created

carddav2fb.php (21 issues)

Upgrade to new PHP Analysis Engine

These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more

1
<?php
2
/**
3
 * CardDAV to FritzBox! XML (automatic upload)
4
 * inspired by http://www.wehavemorefun.de/fritzbox/Hochladen_eines_MySQL-Telefonbuchs
5
 * 
6
 * Requirements: 
7
 *   php5, php5-curl, php5-ftp
8
 * 
9
 * used libraries: 
10
 *  *  vCard-parser <https://github.com/nuovo/vCard-parser> (LICNECE: unknown)
11
 *  *  CardDAV-PHP <https://github.com/graviox/CardDAV-PHP>(LICENCE: AGPLv3)
12
 *  *  fritzbox_api_php <https://github.com/carlos22/fritzbox_api_php> (LICENCE: CC-by-SA 3.0)
13
 * 
14
 * LICENCE (of this file): MIT
15
 * 
16
 * Autors: Karl Glatz (original author)
17
 *         Martin Rost
18
 *         Jens Maus <[email protected]>
19
 *         Johannes Freiburger
20
 *
21
 */
22
error_reporting(E_ALL);
23
setlocale(LC_ALL, 'de_DE.UTF8');
24
25
// Version identifier for CardDAV2FB
26
$carddav2fb_version = '1.11 (2016-05-12)';
27
28
// check for the minimum php version
29
$php_min_version = '5.3.6';
30
if(version_compare(PHP_VERSION, $php_min_version) < 0)
31
{
32
  print 'ERROR: PHP version ' . $php_min_version . ' is required. Found version: ' . PHP_VERSION . PHP_EOL;
33
  exit(1);
34
}
35
36
require_once('lib/CardDAV-PHP/carddav.php');
37
require_once('lib/vCard-parser/vCard.php');
38
require_once('lib/fritzbox_api_php/fritzbox_api.class.php');
39
40
if($argc == 2)
41
  $config_file_name = $argv[1];
42
else
43
  $config_file_name = __DIR__ . '/config.php';
44
45
// default/fallback config options
46
$config['tmp_dir'] = sys_get_temp_dir();
47
$config['fritzbox_ip'] = 'fritz.box';
48
$config['fritzbox_ip_ftp'] = $config['fritzbox_ip'];
49
$config['fritzbox_force_local_login'] = false;
50
$config['phonebook_number'] = '0';
51
$config['phonebook_name'] = 'Telefonbuch';
52
$config['usb_disk'] = '';
53
$config['fritzbox_path'] = 'file:///var/media/ftp/';
54
$config['fullname_format'] = 0; // see config.example.php for options
55
$config['prefix'] = false;
56
$config['suffix'] = false;
57
$config['addnames'] = false;
58
$config['orgname'] = false;
59
$config['build_photos'] = true;
60
$config['quickdial_keyword'] = 'Quickdial:';
61
62
if(is_file($config_file_name))
63
  require($config_file_name);
64
else
65
{
66
  print 'ERROR: No ' . $config_file_name . ' found, please take a look at config.example.php and create a ' . $config_file_name . ' file!' . PHP_EOL;
67
  exit(1);
68
}
69
70
// ---------------------------------------------
71
// MAIN
72
print "carddav2fb.php " . $carddav2fb_version . " - CardDAV to FRITZ!Box phonebook conversion tool" . PHP_EOL;
73
print "Copyright (c) 2012-2016 Karl Glatz, Martin Rost, Jens Maus, Johannes Freiburger" . PHP_EOL . PHP_EOL;
74
75
$client = new CardDAV2FB($config);
76
77
// read vcards from webdav
78
print 'Retrieving VCards from all CardDAV server(s):' . PHP_EOL;
79
$client->get_carddav_entries();
80
print 'Done.' . PHP_EOL;
81
82
flush(); // in case this script runs by php-cgi
83
84
// transform them to a fritzbox compatible xml file
85
print 'Converting VCards to FritzBox XML format:' . PHP_EOL;
86
$client->build_fb_xml();
87
print 'Done.' . PHP_EOL;
88
89
flush(); // in case this script runs by php-cgi
90
91
// upload the XML-file to the FRITZ!Box (CAUTION: this will overwrite all current entries in the phone book!!)
92
print 'Upload data to FRITZ!Box @ ' . $config['fritzbox_ip'] . PHP_EOL;
93
$client->upload_to_fb();
94
print 'Done.' . PHP_EOL;
95
96
flush(); // in case this script runs by php-cgi
97
98
// ---------------------------------------------
99
// Class definition
100
class CardDAV2FB
101
{
102
  protected $entries = array();
103
  protected $fbxml = "";
104
  protected $config = null;
105
  protected $tmpdir = null;
106
107
  public function __construct($config)
108
  {
109
    $this->config = $config;
110
111
    // create a temp directory where we store photos
112
    $this->tmpdir = $this->mktemp($this->config['tmp_dir']);
113
  }
114
115
  public function __destruct()
116
  {
117
    // remote temp directory
118
    $this->rmtemp($this->tmpdir);
119
  }
120
121
  // Source: https://php.net/manual/de/function.tempnam.php#61436
122
  public function mktemp($dir, $prefix = '', $mode = 0700)
123
  {
124
    if(substr($dir, -1) != '/')
125
      $dir .= '/';
126
127
    do
128
    {
129
      $path = $dir . $prefix . mt_rand(0, 9999999);
130
    }
131
    while(!mkdir($path, $mode));
132
133
    return $path;
134
  }
135
136
  public function rmtemp($dir)
137
  {
138
    if(is_dir($dir))
139
    {
140
      $objects = scandir($dir);
141
      foreach($objects as $object)
142
      {
143
        if($object != "." && $object != "..")
144
        {
145
          if(filetype($dir . "/" . $object) == "dir")
146
            rrmdir($dir . "/" . $object); else unlink($dir . "/" . $object);
147
        }
148
      }
149
      reset($objects);
150
      rmdir($dir);
151
    }
152
  }
153
154
  public function is_base64($str)
155
  {
156
    try
157
    {
158
      // Check if there are valid base64 characters
159
      if(!preg_match('/^[a-zA-Z0-9\/\r\n+]*={0,2}$/', $str))
160
        return false;
161
162
      // Decode the string in strict mode and check the results
163
      $decoded = base64_decode($str, true);
164
      if($decoded === false)
165
        return false;
166
167
      // Encode the string again
168
      if(base64_encode($decoded) === $str)
169
        return true;
170
      else
171
        return false;
172
    }
173
    catch(Exception $e)
174
    {
175
      // If exception is caught, then it is not a base64 encoded string
176
      return false;
177
    }
178
  }
179
180
  public function base64_to_jpeg($inputfile, $outputfile)
181
  {
182
    // read data (binary)
183
    $ifp = fopen($inputfile, "rb");
184
    $imageData = fread($ifp, filesize($inputfile));
185
    fclose($ifp);
186
187
    // encode & write data (binary)
188
    $ifp = fopen($outputfile, "wb");
189
    fwrite($ifp, base64_decode($imageData));
190
    fclose($ifp);
191
192
    // return output filename
193
    return($outputfile);
194
  }
195
196
  public function get_carddav_entries()
197
  {
198
    $entries = array();
199
    $snum = 0;
200
201
    if(is_array($this->config['carddav']))
202
    {
203
      foreach($this->config['carddav'] as $conf)
204
      {
205
        print " [" . $snum . "]: " . $conf['url'] . " ";
206
        $carddav = new CardDavPHP\CardDavBackend($conf['url']);
207
        $carddav->setAuth($conf['user'], $conf['pw']);
208
209
        // set the vcard extension in case the user
210
        // defined it in the config
211
        if(isset($conf['extension']))
212
          $carddav->setVcardExtension($conf['extension']);
213
214
        // retrieve data from the CardDAV server now
215
        $xmldata = $carddav->get();
216
217
        // identify if we received UTF-8 encoded data from the
218
        // CardDAV server and if not reencode it since the FRITZ!Box
219
        // requires UTF-8 encoded data
220
        if(iconv('utf-8', 'utf-8//IGNORE', $xmldata) != $xmldata)
221
          $xmldata = utf8_encode($xmldata);
222
223
        // read raw_vcard data from xml response
224
        $raw_vcards = array();
225
        $xmlvcard = new SimpleXMLElement($xmldata);
226
227
        foreach($xmlvcard->element as $vcard_element)
228
        {
229
          $id = $vcard_element->id->__toString();
230
          $value = (string)$vcard_element->vcard->__toString();
231
          $raw_vcards[$id] = $value;
232
        }
233
234
        print " " . count($raw_vcards) . " VCards retrieved." . PHP_EOL;
235
236
        // parse raw_vcards
237
        $quick_dial_arr = array();
238
        foreach($raw_vcards as $v)
239
        {
240
          $vcard_obj = new vCard(false, $v);
241
          $name_arr = null;
242
          if(isset($vcard_obj->n[0]))
0 ignored issues
show
The property n does not exist on object<vCard>. Since you implemented __get, maybe consider adding a @property annotation.

Since your code implements the magic getter _get, this function will be called for any read access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

If the property has read access only, you can use the @property-read annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
243
            $name_arr = $vcard_obj->n[0];
0 ignored issues
show
The property n does not exist on object<vCard>. Since you implemented __get, maybe consider adding a @property annotation.

Since your code implements the magic getter _get, this function will be called for any read access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

If the property has read access only, you can use the @property-read annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
244
          $org_arr = null;
245
          if(isset($vcard_obj->org[0]))
0 ignored issues
show
The property org does not exist on object<vCard>. Since you implemented __get, maybe consider adding a @property annotation.

Since your code implements the magic getter _get, this function will be called for any read access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

If the property has read access only, you can use the @property-read annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
246
            $org_arr = $vcard_obj->org[0];
0 ignored issues
show
The property org does not exist on object<vCard>. Since you implemented __get, maybe consider adding a @property annotation.

Since your code implements the magic getter _get, this function will be called for any read access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

If the property has read access only, you can use the @property-read annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
247
          $addnames = '';
248
          $prefix = '';
249
          $suffix = '';
250
          $orgname = '';
251
252
          // Build name Parts if existing ans switch to true in config
253
          if(isset($name_arr['prefixes']) and $this->config['prefix'])
254
            $prefix = trim($name_arr['prefixes']);
255
256
          if(isset($name_arr['suffixes']) and $this->config['suffix'])
257
            $suffix = trim($name_arr['suffixes']);
258
259
          if(isset($name_arr['additionalnames']) and $this->config['addnames'])
260
            $addnames = trim($name_arr['additionalnames']);
261
262
          if(isset($org_arr['name']) and $this->config['orgname'])
263
            $orgname = trim($org_arr['name']);
264
265
          $firstname = trim($name_arr['firstname']);
266
          $lastname = trim($name_arr['lastname']);
267
268
          // the following section implemented different ways of constructing the
269
          // final phonebook name entry depending on user preferred settings
270
          // selectable in the config file. Possible options are:
271
          //
272
          // $this->config['fullname_format']:
0 ignored issues
show
Unused Code Comprehensibility introduced by
75% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
273
          //
274
          // 0: "Prefix Lastname, Firstname AdditionalNames Suffix (orgname)"
275
          // 1: "Prefix Firstname Lastname AdditionalNames Suffix (orgname)"
276
          // 2: "Prefix Firstname AdditionalNames Lastname Suffix (orgname)"
277
          //
278
          $name = '';
279
          $format = $this->config['fullname_format'];
280
281
          // Prefix
282
          if(!empty($prefix))
283
            $name .= $prefix;
284
285 View Code Duplication
          if($format == 0)
0 ignored issues
show
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
286
          {
287
            // Lastname
288
            if(!empty($name) and !empty($lastname))
289
              $name .= ' ' . $lastname;
290
            else
291
              $name .= $lastname;
292
          }
293
          else
294
          {
295
            // Firstname
296
            if(!empty($name) and !empty($firstname))
297
              $name .= ' ' . $firstname;
298
            else
299
              $name .= $firstname;
300
          }
301
302 View Code Duplication
          if($format == 2)
0 ignored issues
show
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
303
          {
304
            // AdditionalNames
305
            if(!empty($name) and !empty($addnames))
306
              $name .= ' ' . $addnames;
307
            else
308
              $name .= $addnames;
309
          }
310
311 View Code Duplication
          if($format == 0)
0 ignored issues
show
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
312
          {
313
            // Firstname
314
            if(!empty($name) and !empty($firstname))
315
              $name .= ', ' . $firstname;
316
            else
317
              $name .= $firstname;
318
          }
319
          else
320
          {
321
            // Lastname
322
            if(!empty($name) and !empty($lastname))
323
              $name .= ' ' . $lastname;
324
            else
325
              $name .= $lastname;
326
          }
327
328 View Code Duplication
          if($format != 2)
0 ignored issues
show
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
329
          {
330
            // AdditionalNames
331
            if(!empty($name) and !empty($addnames))
332
              $name .= ' ' . $addnames;
333
            else
334
              $name .= $addnames;
335
          }
336
337
          // Suffix
338
          if(!empty($name) and !empty($suffix))
339
            $name .= ' ' . $suffix;
340
          else
341
            $name .= $suffix;
342
343
          // OrgName
344
          if(!empty($name) and !empty($orgname))
345
            $name .= ' (' . $orgname . ')';
346
          else
347
            $name .= $orgname;
348
349
          // make sure to trim whitespaces and double spaces
350
          $name = trim(str_replace('  ', ' ', $name));
351
352
          if(empty($name))
353
          {
354
            print '  WARNING: No fullname, lastname or orgname found!';
355
            $name = 'UNKNOWN';
356
          }
357
358
          // format filename of contact photo; remove special letters
359
          if($vcard_obj->photo)
0 ignored issues
show
The property photo does not exist on object<vCard>. Since you implemented __get, maybe consider adding a @property annotation.

Since your code implements the magic getter _get, this function will be called for any read access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

If the property has read access only, you can use the @property-read annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
360
          {
361
            $photo = str_replace(array(',', '&', ' ', '/', 'ä', 'ö', 'ü', 'Ä', 'Ö', 'Ü', 'ß', 'á', 'à', 'ó', 'ò', 'ú', 'ù', 'í', 'ø'),
362
            array('', '_', '_', '_', 'ae', 'oe', 'ue', 'Ae', 'Oe', 'Ue', 'ss', 'a', 'a', 'o', 'o', 'u', 'u', 'i', 'oe'), $name);
363
          }
364
          else
365
            $photo = '';
366
367
          // phone
368
          $phone_no = array();
369
          if($vcard_obj->categories)
0 ignored issues
show
The property categories does not exist on object<vCard>. Since you implemented __get, maybe consider adding a @property annotation.

Since your code implements the magic getter _get, this function will be called for any read access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

If the property has read access only, you can use the @property-read annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
370
            $categories = $vcard_obj->categories[0];
0 ignored issues
show
The property categories does not exist on object<vCard>. Since you implemented __get, maybe consider adding a @property annotation.

Since your code implements the magic getter _get, this function will be called for any read access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

If the property has read access only, you can use the @property-read annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
371
          else
372
            $categories = array();
373
374
          // check for quickdial entry
375
          if(isset($vcard_obj->note[0]))
0 ignored issues
show
The property note does not exist on object<vCard>. Since you implemented __get, maybe consider adding a @property annotation.

Since your code implements the magic getter _get, this function will be called for any read access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

If the property has read access only, you can use the @property-read annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
376
          {
377
            $note = $vcard_obj->note[0];
0 ignored issues
show
The property note does not exist on object<vCard>. Since you implemented __get, maybe consider adding a @property annotation.

Since your code implements the magic getter _get, this function will be called for any read access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

If the property has read access only, you can use the @property-read annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
378
            $notes = explode($this->config['quickdial_keyword'], $note);
379
            foreach($notes as $linenr => $linecontent)
380
            {
381
              $found = strrpos($linecontent, ":**7");
382
              if($found > 0)
383
              {
384
                $pos_qd_start = strrpos($linecontent, ":**7");
385
                $quick_dial_for_nr = preg_replace("/[^0-9+]/", "", substr($linecontent, 0, $pos_qd_start));
386
                $quick_dial_nr = intval(substr($linecontent, $pos_qd_start + 4, 3));
387
                $quick_dial_arr[$quick_dial_for_nr] = $quick_dial_nr;
388
              }
389
            }
390
          }
391
392
          // e-mail addresses
393
          $email_add = array();
394
          $vip = isset($this->config['group_vip']) && in_array((string)$this->config['group_vip'], $categories);
395
396
          if(array_key_exists('group_filter', $this->config) && is_array($this->config['group_filter']))
397
          {
398
            $add_entry = 0;
399
            foreach($this->config['group_filter'] as $group_filter)
400
            {
401
              if(in_array($group_filter, $categories))
402
              {
403
                $add_entry = 1;
404
                break;
405
              }
406
            }
407
          } 
408
          else
409
            $add_entry = 1;
410
411
          if($add_entry == 1)
412
          {
413
            foreach($vcard_obj->tel as $t)
0 ignored issues
show
The property tel does not exist on object<vCard>. Since you implemented __get, maybe consider adding a @property annotation.

Since your code implements the magic getter _get, this function will be called for any read access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

If the property has read access only, you can use the @property-read annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
414
            {
415
              $prio = 0;
416
              $quickdial = null;
417
              
418
              if(!is_array($t) || empty($t['type']))
419
              {
420
                $type = "mobile";
421
                $phone_number = $t;
422
              }
423
              else
424
              {
425
                $phone_number = $t['value'];
426
                
427
                $phone_number_clean = preg_replace("/[^0-9+]/", "", $phone_number);
428
                foreach($quick_dial_arr as $qd_phone_nr => $value)
429
                {
430
                  if($qd_phone_nr == $phone_number_clean)
431
                  {
432
                    //Set quickdial
433
                    if($value == 1)
434
                      print "\nWARNING: Quickdial value 1 (**701) is not possible but used! \n";
435
                    elseif($value >= 100)
436
                      print "\nWARNING: Quickdial value bigger than 99 (**799) is not possible but used! \n";
437
438
                    $quickdial = $value;
439
                  }
440
                }
441
442
                $typearr_lower = unserialize(strtolower(serialize($t['type'])));
443
444
                // find out priority
445
                if(in_array("pref", $typearr_lower))
446
                  $prio = 1;
447
448
                // set the proper type
449
                if(in_array("cell", $typearr_lower))
450
                  $type = "mobile";
451
                elseif(in_array("home", $typearr_lower))
452
                  $type = "home";
453
                elseif(in_array("fax", $typearr_lower))
454
                  $type = "fax_work";
455
                elseif(in_array("work", $typearr_lower))
456
                  $type = "work";
457
                elseif(in_array("other", $typearr_lower))
458
                  $type = "other";
459
                elseif(in_array("dom", $typearr_lower))
460
                  $type = "other";
461
                else
462
                  continue;
463
              }
464
              $phone_no[] = array("type"=>$type, "prio"=>$prio, "quickdial"=>$quickdial, "value" => $this->_clear_phone_number($phone_number));
465
            }
466
467
            // request email address and type
468
            if($vcard_obj->email)
0 ignored issues
show
The property email does not exist on object<vCard>. Since you implemented __get, maybe consider adding a @property annotation.

Since your code implements the magic getter _get, this function will be called for any read access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

If the property has read access only, you can use the @property-read annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
469
            {
470
              foreach($vcard_obj->email as $e)
0 ignored issues
show
The property email does not exist on object<vCard>. Since you implemented __get, maybe consider adding a @property annotation.

Since your code implements the magic getter _get, this function will be called for any read access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

If the property has read access only, you can use the @property-read annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
471
              {
472
                if(empty($e['type']))
473
                {
474
                  $type_email = "work";
475
                  $email = $e;
476
                }
477
                else
478
                {
479
                  $email = $e['value'];
480
                  $typearr_lower = unserialize(strtolower(serialize($e['type'])));
481
                  if(in_array("work", $typearr_lower))
482
                    $type_email = "work";
483
                  elseif(in_array("home", $typearr_lower))
484
                    $type_email = "home";
485
                  elseif(in_array("other", $typearr_lower))
486
                    $type_email = "other";
487
                  else
488
                    continue;
489
                }
490
491
                // DEBUG: print out the email address on the console
492
                //print $type_email.": ".$email."\n";
0 ignored issues
show
Unused Code Comprehensibility introduced by
60% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
493
494
                $email_add[] = array("type"=>$type_email, "value" => $email);
495
              }
496
            }
497
            $entries[] = array("realName" => $name, "telephony" => $phone_no, "email" => $email_add, "vip" => $vip, "photo" => $photo, "photo_data" => $vcard_obj->photo);
0 ignored issues
show
The property photo does not exist on object<vCard>. Since you implemented __get, maybe consider adding a @property annotation.

Since your code implements the magic getter _get, this function will be called for any read access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

If the property has read access only, you can use the @property-read annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
498
          }
499
        }
500
501
        $snum++;
502
      }
503
    }
504
505
    $this->entries = $entries;
506
  }
507
508
  private function _clear_phone_number($number)
509
  {
510
    return preg_replace("/[^0-9+]/", "", $number);
511
  }
512
513
  public function build_fb_xml()
514
  {
515
    if(empty($this->entries))
516
      throw new Exception('No entries available! Call get_carddav_entries or set $this->entries manually!');
517
518
    // create FB XML in utf-8 format
519
    $root = new SimpleXMLElement('<?xml version="1.0" encoding="UTF-8"?><phonebooks><phonebook></phonebook></phonebooks>');
520
    $pb = $root->phonebook;
521
    $pb->addAttribute("name", $this->config['phonebook_name']);
522
523
    foreach($this->entries as $entry)
524
    {
525
      $contact = $pb->addChild("contact");
526
      $contact->addChild("category", $entry['vip']);
527
      $person = $contact->addChild("person");
528
      $person->addChild("realName", $this->_convert_text($entry['realName']));
529
530
      echo " VCard: '" . utf8_decode($entry['realName']) . "'" . PHP_EOL;
531
532
      // telephone: put the phonenumbers into the fritzbox xml file
533
      $telephony = $contact->addChild("telephony");
534
      $id = 0;
535
      foreach($entry['telephony'] as $tel)
536
      {
537
        $num = $telephony->addChild("number", $tel['value']);
538
        $num->addAttribute("type", $tel['type']);
539
        $num->addAttribute("vanity", "");
540
        $num->addAttribute("prio", $tel['prio']);
541
        $num->addAttribute("id", $id);
542
543
        if(isset($tel['quickdial']))
544
        {
545
          $num->addAttribute("quickdial", $tel['quickdial']);
546
          print "  Added quickdial: " . $tel['quickdial'] . " for: " . $tel['value'] . " (" . $tel['type'] . ")" . PHP_EOL;
547
        }
548
549
        $id++;
550
        print "  Added phone: " . $tel['value'] . " (" . $tel['type'] . ")" . PHP_EOL;
551
      }
552
553
      // output a warning if no telephone number was found
554
      if($id == 0)
555
        print "  WARNING: no phone entry found. VCard will be ignored." . PHP_EOL;
556
557
      // email: put the email addresses into the fritzbox xml file
558
      $email = $contact->addChild("services");
559
      $id = 0;
560
      foreach($entry['email'] as $mail)
561
      {
562
        $mail_adr = $email->addChild("email", $mail['value']);
563
        $mail_adr->addAttribute("classifier", $mail['type']);
564
        $mail_adr->addAttribute("id", $id);
565
        $id++;
566
567
        print "  Added email: " . $mail['value'] . " (" . $mail['type'] . ")" . PHP_EOL;
568
      }
569
570
      // check for a photo being part of the VCard
571
      if(($entry['photo']) and ($entry['photo_data']) and (is_array($entry['photo_data'])) and ($entry['photo_data'][0]))
572
      {
573
        // check if 'photo_data'[0] is an array as well because then
574
        // we have to extract ['value'] and friends.
575
        if(is_array($entry['photo_data'][0]) and (array_key_exists('value', $entry['photo_data'][0])))
576
        {
577
          // check if photo_data really contains JPEG data
578
          if((array_key_exists('type', $entry['photo_data'][0])) and (is_array($entry['photo_data'][0]['type'])) and
579
             ($entry['photo_data'][0]['type'][0] == 'jpeg' or $entry['photo_data'][0]['type'][0] == 'jpg'))
580
          {
581
            // get photo, rename, base64 convert and save as jpg
582
            $photo_data = $entry['photo_data'][0]['value'];
583
            $photo_version = substr(sha1($photo_data), 0, 5);
584
            $photo_file = $this->tmpdir . '/' . "{$entry['photo']}_{$photo_version}.jpg";
585
586
            // check for base64 encoding of the photo data and convert it
587
            // accordingly.
588
            if(((array_key_exists('encoding', $entry['photo_data'][0])) and ($entry['photo_data'][0]['encoding'] == 'b')) or $this->is_base64($photo_data))
589
            {
590
              file_put_contents($photo_file . ".b64", $photo_data);
591
              $this->base64_to_jpeg($photo_file . ".b64", $photo_file);
592
              unlink($photo_file . ".b64");
593
            }
594
            else
595
            {
596
              print "  WARNING: non-base64 encoded photo data found and used." . PHP_EOL;
597
              file_put_contents($photo_file, $photo_data);
598
            }
599
600
            // add contact photo to xml
601
            $person->addChild("imageURL", $this->config['fritzbox_path'] . $this->config['usb_disk'] . "FRITZ/fonpix/" . basename($photo_file));
602
603
            print "  Added photo: " . basename($photo_file) . PHP_EOL;
604
          }
605
          else
606
           print "  WARNING: Only jpg contact photos are currently supported." . PHP_EOL;
607
        }
608
        elseif(substr($entry['photo_data'][0], 0, 4) == 'http')
609
        {
610
          // add contact photo to xml
611
          $person->addChild("imageURL", $entry['photo_data'][0]);
612
613
          print "  Added photo: " . $entry['photo_data'][0] . PHP_EOL;
614
        }
615
        else
616
          print "  WARNING: Only VCard embedded photo data or a reference URL is currently supported." . PHP_EOL;
617
      }
618
619
      $contact->addChild("services");
620
      $contact->addChild("setup");
621
      $contact->addChild("mod_time", (string)time());
622
    }
623
624
    if($root->asXML() !== false)
625
      $this->fbxml = $root->asXML();
626
    else
627
    {
628
      print "  ERROR: created XML data isn't well-formed." . PHP_EOL;
629
      exit(1);
630
    }
631
  }
632
633
  public function _convert_text($text)
634
  {
635
    $text = htmlspecialchars($text);
636
    return $text;
637
  }
638
639
  public function _concat($text1, $text2)
640
  {
641
    if($text1 == '')
642
      return $text2;
643
    elseif($text2 == '')
644
      return $text1;
645
    else
646
      return $text1 . ", " . $text2;
647
  }
648
649
  public function _parse_fb_result($text)
650
  {
651
    if(preg_match("/\<h2\>([^\<]+)\<\/h2\>/", $text, $matches) == 1 && !empty($matches))
652
      return $matches[1];
653
    else
654
      return "Error while uploading xml to fritzbox";
655
  }
656
657
  public function upload_to_fb()
658
  {
659
    // if the user wants to save the xml to a separate file, we do so now
660
    if(array_key_exists('output_file', $this->config))
661
    {
662
      // build md5 hash of previous stored xml without <mod_time> Elements
663
      $oldphonebhash = md5(preg_replace("/<mod_time>(\\d{10})/","",file_get_contents($this->config['output_file'],'r'),-1,$debugoldtsreplace));
664
      $output = fopen($this->config['output_file'], 'w');
665
      if($output)
666
      {
667
        fwrite($output, $this->fbxml);
668
        fclose($output);
669
        print " Saved to file " . $this->config['output_file'] . PHP_EOL;
670
      }
671
	  if (array_key_exists('output_and_upload', $this->config) and $this->config['output_and_upload'])
672
	  {
673
	  	$newphonebhash = md5(preg_replace("/<mod_time>(\\d{10})/","",file_get_contents($this->config['output_file'],'r'),-1,$debugnewtsreplace));
674
	  	print " INFO: Compare old and new phonebook file versions." . PHP_EOL . " INFO: old version: " . $oldphonebhash . PHP_EOL . " INFO: new version: " . $newphonebhash . PHP_EOL;
675
	  	if($oldphonebhash === $newphonebhash)
676
      	{
677
      	print " INFO: Same versions ==> No changes in phonebook or images" . PHP_EOL . " EXIT: No need to upload phonebook to the FRITZ!Box.". PHP_EOL;
678
      	return 0;
679
      	}
680
      	else
681
      	print " INFO: Different versions ==> Changes in phonebook." . PHP_EOL . " INFO: Changes dedected! Continue with upload." . PHP_EOL;
682
      }
683
	  else
684
      return 0;  
685
    }
686
    // now we upload the photo jpgs first being stored in the
687
    // temp directory.
688
689
    // perform an ftps-connection to copy over the photos to a specified directory
690
    $ftp_server = $this->config['fritzbox_ip_ftp'];
691
    $conn_id = ftp_ssl_connect($ftp_server);
692 View Code Duplication
    if($conn_id == false)
0 ignored issues
show
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
693
    {
694
      print " WARNING: Secure connection to FTP-server '" . $ftp_server . "' failed, retrying without SSL." . PHP_EOL;
695
      $conn_id = ftp_connect($ftp_server);
696
    }
697
698
    if($conn_id != false)
699
    {
700
      ftp_set_option($conn_id, FTP_TIMEOUT_SEC, 60);
701
      $login_result = ftp_login($conn_id, $this->config['fritzbox_user'], $this->config['fritzbox_pw']);
702
      if($login_result === true)
703
      {
704
        ftp_pasv($conn_id, true);
705
706
        // create remote photo path on FRITZ!Box if it doesn't exist
707
        $remote_path = $this->config['usb_disk'] . "/FRITZ/fonpix";
708
        $all_existing_files = ftp_nlist($conn_id, $remote_path);
709
        if($all_existing_files == false)
710
        {
711
          ftp_mkdir($conn_id, $remote_path);
712
          $all_existing_files = array();
713
        }
714
715
        // now iterate through all jpg files in tempdir and upload them if necessary
716
        $dir = new DirectoryIterator($this->tmpdir);
717
        foreach($dir as $fileinfo)
718
        {
719
          if(!$fileinfo->isDot())
720
          {
721
            if($fileinfo->getExtension() == "jpg")
722
            {
723
              $file = $fileinfo->getFilename();
724
725
              print " FTP-Upload '" . $file . "'...";
726
              if(!in_array($remote_path . "/" . $file, $all_existing_files))
727
              {
728
                if(!ftp_put($conn_id, $remote_path . "/" . $file, $fileinfo->getPathname(), FTP_BINARY))
729
                {
730
                  // retry when a fault occurs.
731
                  print " retrying... ";
732
                  $conn_id = ftp_ssl_connect($ftp_server);
733 View Code Duplication
                  if($conn_id == false)
0 ignored issues
show
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
734
                  {
735
                    print " WARNING: Secure re-connection to FTP-server '" . $ftp_server . "' failed, retrying without SSL." . PHP_EOL;
736
                    $conn_id = ftp_connect($ftp_server);
737
                  }
738
739
                  if($conn_id == false)
740
                  {
741
                    print " ERROR: couldn't re-connect to FTP server '" . $ftp_server . "', abortіng." . PHP_EOL;
742
                    break;
743
                  }
744
745
                  $login_result = ftp_login($conn_id, $this->config['fritzbox_user'], $this->config['fritzbox_pw']);
746
                  if($login_result === false)
747
                  {
748
                    print " ERROR: couldn't re-login to FTP-server '" . $ftp_server . "' with provided username/password settings." . PHP_EOL;
749
                    break;
750
                  }
751
752
                  ftp_pasv($conn_id, true);
753
                  if(!ftp_put($conn_id, $remote_path . "/" . $file, $fileinfo->getPathname(), FTP_BINARY))
754
                    print " ERROR: while uploading file " . $fileinfo->getFilename() . PHP_EOL;
755
                  else
756
                    print " ok." . PHP_EOL;
757
                }
758
                else
759
                  print " ok." . PHP_EOL;
760
761
                // cleanup old files
762
                foreach($all_existing_files as $existing_file)
763
                {
764
                  if(strpos($existing_file, $remote_path . "/" . substr($file, 0, -10)) !== false)
765
                  {
766
                    print " FTP-Delete: " . $existing_file . PHP_EOL;
767
                    ftp_delete($conn_id, $remote_path . "/" . basename($existing_file));
768
                  }
769
                }
770
              }
771
              else
772
                print " already exists." . PHP_EOL;
773
            }
774
          }
775
        }
776
      }
777
      else
778
        print " ERROR: couldn't login to FTP-server '" . $ftp_server . "' with provided username/password settings." . PHP_EOL;
779
780
      // close ftp connection
781
      ftp_close($conn_id);
782
    }
783
    else
784
      print " ERROR: couldn't connect to FTP server '" . $ftp_server . "'." . PHP_EOL;
785
786
    // in case numeric IP is given, try to resolve to hostname. Otherwise Fritzbox may decline login, because it is determine to be (prohibited) remote access
787
    $hostname = $this->config['fritzbox_ip'];
788
    if(filter_var($hostname, FILTER_VALIDATE_IP))
789
    {
790
      $hostname = gethostbyaddr($hostname);
791
      if($hostname == $this->config['fritzbox_ip'])
792
        print " WARNING: Unable to get hostname for IP address (" . $this->config['fritzbox_ip'] . ") <" . $hostname . "<" . PHP_EOL;
793
      else
794
      {
795
        print " INFO: Given IP address (" . $this->config['fritzbox_ip'] . ") has hostname " . $hostname . "." . PHP_EOL;
796
        $this->config['fritzbox_ip'] = $hostname;
797
      }
798
    }
799
    
800
    // lets post the phonebook xml to the FRITZ!Box
801
    print " Uploading Phonebook XML to " . $this->config['fritzbox_ip'] . PHP_EOL;
802
    try
803
    {
804
      $fritz = new fritzbox_api($this->config['fritzbox_pw'],
805
        $this->config['fritzbox_user'],
806
        $this->config['fritzbox_ip'],
807
        $this->config['fritzbox_force_local_login']);
808
809
      $formfields = array(
810
        'PhonebookId' => $this->config['phonebook_number']
811
      );
812
813
      $filefileds = array('PhonebookImportFile' => array(
814
       'type' => 'text/xml',
815
       'filename' => 'updatepb.xml',
816
       'content' => $this->fbxml,
817
       )
818
      );
819
820
      $raw_result = $fritz->doPostFile($formfields, $filefileds); // send the command
821
      $msg = $this->_parse_fb_result($raw_result);
822
      unset($fritz); // destroy the object to log out
823
824
      print "  FRITZ!Box returned message: '" . $msg . "'" . PHP_EOL;
825
    }
826
    catch(Exception $e)
827
    {
828
      print "  ERROR: " . $e->getMessage() . PHP_EOL; // show the error message in anything failed
829
    }
830
  }
831
}
832