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
Push — master ( 6a121b...8b886b )
by Jens
02:50
created

CardDAV2FB::get_carddav_entries()   D

Complexity

Conditions 72
Paths 2

Size

Total Lines 320
Code Lines 179

Duplication

Lines 48
Ratio 15 %

Importance

Changes 36
Bugs 5 Features 6
Metric Value
cc 72
eloc 179
c 36
b 5
f 6
nc 2
nop 0
dl 48
loc 320
rs 4.1818

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

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
    $imgseqfname = 1;
200
    $snum = 0;
201
202
    if(is_array($this->config['carddav']))
203
    {
204
      foreach($this->config['carddav'] as $conf)
205
      {
206
        print " [" . $snum . "]: " . $conf['url'] . " ";
207
        $carddav = new CardDavPHP\CardDavBackend($conf['url']);
208
        $carddav->setAuth($conf['user'], $conf['pw']);
209
210
        // set the vcard extension in case the user
211
        // defined it in the config
212
        if(isset($conf['extension']))
213
          $carddav->setVcardExtension($conf['extension']);
214
215
        // retrieve data from the CardDAV server now
216
        $xmldata =  $carddav->get();
217
218
        // identify if we received UTF-8 encoded data from the
219
        // CardDAV server and if not reencode it since the FRITZ!Box
220
        // requires UTF-8 encoded data
221
        if(iconv('utf-8', 'utf-8//IGNORE', $xmldata) != $xmldata)
222
          $xmldata = utf8_encode($xmldata);
223
224
        // read raw_vcard data from xml response
225
        $raw_vcards = array();
226
        $xmlvcard = new SimpleXMLElement($xmldata);
227
228
        foreach($xmlvcard->element as $vcard_element)
229
        {
230
          $id = $vcard_element->id->__toString();
231
          $value = (string)$vcard_element->vcard->__toString();
232
          $raw_vcards[$id] = $value;
233
        }
234
235
        print " " . count($raw_vcards) . " VCards retrieved." . PHP_EOL;
236
237
        // parse raw_vcards
238
        $quick_dial_arr = array();
239
        foreach($raw_vcards as $v)
240
        {
241
          $vcard_obj = new vCard(false, $v);
242
          $name_arr = null;
243
          if(isset($vcard_obj->n[0]))
0 ignored issues
show
Documentation introduced by
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
            $name_arr = $vcard_obj->n[0];
0 ignored issues
show
Documentation introduced by
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...
245
          $org_arr = null;
246
          if(isset($vcard_obj->org[0]))
0 ignored issues
show
Documentation introduced by
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
            $org_arr = $vcard_obj->org[0];
0 ignored issues
show
Documentation introduced by
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...
248
          $addnames = '';
249
          $prefix = '';
250
          $suffix = '';
251
          $orgname = '';
252
253
          // Build name Parts if existing ans switch to true in config
254
          if(isset($name_arr['prefixes']) AND $this->config['prefix'])
255
            $prefix = trim($name_arr['prefixes']);
256
257
          if(isset($name_arr['suffixes']) AND $this->config['suffix'])
258
            $suffix = trim($name_arr['suffixes']);
259
260
          if(isset($name_arr['additionalnames']) AND $this->config['addnames'])
261
            $addnames = trim($name_arr['additionalnames']);
262
263
          if(isset($org_arr['name']) AND $this->config['orgname'])
264
            $orgname = trim($org_arr['name']);
265
266
          $firstname = trim($name_arr['firstname']);
267
          $lastname = trim($name_arr['lastname']);
268
269
          // the following section implemented different ways of constructing the
270
          // final phonebook name entry depending on user preferred settings
271
          // selectable in the config file. Possible options are:
272
          //
273
          // $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...
274
          //
275
          // 0: "Prefix Lastname, Firstname AdditionalNames Suffix (orgname)"
276
          // 1: "Prefix Firstname Lastname AdditionalNames Suffix (orgname)"
277
          // 2: "Prefix Firstname AdditionalNames Lastname Suffix (orgname)"
278
          //
279
          $name = '';
280
          $format = $this->config['fullname_format'];
281
282
          // Prefix
283
          if(!empty($prefix))
284
            $name .= $prefix;
285
286 View Code Duplication
          if($format == 0)
0 ignored issues
show
Duplication introduced by
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...
287
          {
288
            // Lastname
289
            if(!empty($name) AND !empty($lastname))
290
              $name .= ' ' . $lastname;
291
            else
292
              $name .= $lastname;
293
          }
294
          else
295
          {
296
            // Firstname
297
            if(!empty($name) AND !empty($firstname))
298
              $name .= ' ' . $firstname;
299
            else
300
              $name .= $firstname;
301
          }
302
303 View Code Duplication
          if($format == 2)
0 ignored issues
show
Duplication introduced by
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...
304
          {
305
            // AdditionalNames
306
            if(!empty($name) AND !empty($addnames))
307
              $name .= ' ' . $addnames;
308
            else
309
              $name .= $addnames;
310
          }
311
312 View Code Duplication
          if($format == 0)
0 ignored issues
show
Duplication introduced by
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...
313
          {
314
            // Firstname
315
            if(!empty($name) AND !empty($firstname))
316
              $name .= ', ' . $firstname;
317
            else
318
              $name .= $firstname;
319
          }
320
          else
321
          {
322
            // Lastname
323
            if(!empty($name) AND !empty($lastname))
324
              $name .= ' ' . $lastname;
325
            else
326
              $name .= $lastname;
327
          }
328
329 View Code Duplication
          if($format != 2)
0 ignored issues
show
Duplication introduced by
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...
330
          {
331
            // AdditionalNames
332
            if(!empty($name) AND !empty($addnames))
333
              $name .= ' ' . $addnames;
334
            else
335
              $name .= $addnames;
336
          }
337
338
          // Suffix
339
          if(!empty($name) AND !empty($suffix))
340
            $name .= ' ' . $suffix;
341
          else
342
            $name .= $suffix;
343
344
          // OrgName
345
          if(!empty($name) AND !empty($orgname))
346
            $name .= ' (' . $orgname . ')';
347
          else
348
            $name .= $orgname;
349
350
          // make sure to trim whitespaces and double spaces
351
          $name = trim(str_replace('  ', ' ', $name));
352
353
          if(empty($name))
354
          {
355
            print '  WARNING: No fullname, lastname or orgname found!';
356
            $name = 'UNKNOWN';
357
          }
358
359
          // format filename of contact photo; remove special letters, added config option for sequential filnames default is false
360
          if($vcard_obj->photo)
0 ignored issues
show
Documentation introduced by
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...
361
          {
362
            if(isset($this->config['seq_photo_name']) AND $this->config['seq_photo_name'] == true)
363
            {
364
              $photo = $imgseqfname;
365
              $imgseqfname++;
366
            }
367
            else
368
            {
369
              $photo = str_replace(array(',','&',' ','/','ä','ö','ü','Ä','Ö','Ü','ß','á','à','ó','ò','ú','ù','í','ø'),
370
              array('','_','_','_','ae','oe','ue','Ae','Oe','Ue','ss','a','a','o','o','u','u','i','oe'),$name);
371
            }
372
          }
373
          else
374
            $photo = '';
375
376
          // phone
377
          $phone_no = array();
378
          if($vcard_obj->categories)
0 ignored issues
show
Documentation introduced by
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...
379
            $categories = $vcard_obj->categories[0];
0 ignored issues
show
Documentation introduced by
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...
380
          else
381
            $categories = array();
382
383
          // check for quickdial entry
384
          if(isset($vcard_obj->note[0]))
0 ignored issues
show
Documentation introduced by
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...
385
          {
386
            $note = $vcard_obj->note[0];
0 ignored issues
show
Documentation introduced by
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...
387
            $notes = explode($this->config['quickdial_keyword'], $note);
388
            foreach($notes as $linenr => $linecontent)
389
            {
390
              $found = strrpos($linecontent , ":**7");
391
              if($found > 0)
392
              {
393
                $pos_qd_start = strrpos($linecontent , ":**7" );
394
                $quick_dial_for_nr = preg_replace("/[^0-9+]/", "",substr($linecontent , 0, $pos_qd_start));
395
                $quick_dial_nr = intval(substr($linecontent , $pos_qd_start+4, 3));
396
                $quick_dial_arr[$quick_dial_for_nr]=$quick_dial_nr;
397
              }
398
            }
399
          }
400
401
          // e-mail addresses
402
          $email_add = array();
403
          $vip = isset($this->config['group_vip']) && in_array((string)$this->config['group_vip'], $categories);
404
405
          if(array_key_exists('group_filter',$this->config) && is_array($this->config['group_filter']))
406
          {
407
            $add_entry = 0;
408
            foreach($this->config['group_filter'] as $group_filter)
409
            {
410
              if(in_array($group_filter,$categories))
411
              {
412
                $add_entry = 1;
413
                break;
414
              }
415
            }
416
          } 
417
          else
418
            $add_entry = 1;
419
420
          if($add_entry == 1)
421
          {
422
            foreach($vcard_obj->tel as $t)
0 ignored issues
show
Documentation introduced by
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...
423
            {
424
              $prio = 0;
425
              $quickdial =null;
426
              
427
              if(!is_array($t) || empty($t['type']))
428
              {
429
                $type = "mobile";
430
                $phone_number = $t;
431
              }
432
              else
433
              {
434
                $phone_number = $t['value'];
435
                
436
                $phone_number_clean = preg_replace("/[^0-9+]/", "",$phone_number);
437
                foreach($quick_dial_arr as $qd_phone_nr => $value)
438
                {
439
                  if($qd_phone_nr == $phone_number_clean)
440
                  {
441
                    //Set quickdial
442
                    if($value == 1)
443
                      print "\nWARNING: Quickdial value 1 (**701) is not possible but used! \n";
444
                    elseif($value >= 100)
445
                      print "\nWARNING: Quickdial value bigger than 99 (**799) is not possible but used! \n";
446
447
                    $quickdial = $value;
448
                  }
449
                }
450
451
                $typearr_lower = unserialize(strtolower(serialize($t['type'])));
452
453
                // find out priority
454
                if(in_array("pref", $typearr_lower))
455
                  $prio = 1;
456
457
                // set the proper type
458
                if(in_array("cell", $typearr_lower))
459
                  $type = "mobile";
460
                elseif(in_array("home", $typearr_lower))
461
                  $type = "home";
462
                elseif(in_array("fax", $typearr_lower))
463
                  $type = "fax_work";
464
                elseif(in_array("work", $typearr_lower))
465
                  $type = "work";
466
                elseif(in_array("other", $typearr_lower))
467
                  $type = "other";
468
                elseif(in_array("dom", $typearr_lower))
469
                  $type = "other";
470
                else
471
                  continue;
472
              }
473
              $phone_no[] =  array("type"=>$type, "prio"=>$prio, "quickdial"=>$quickdial, "value" => $this->_clear_phone_number($phone_number));
474
            }
475
476
            // request email address and type
477
            if($vcard_obj->email)
0 ignored issues
show
Documentation introduced by
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...
478
            {
479
              foreach($vcard_obj->email as $e)
0 ignored issues
show
Documentation introduced by
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...
480
              {
481
                if(empty($e['type']))
482
                {
483
                  $type_email = "work";
484
                  $email = $e;
485
                }
486
                else
487
                {
488
                  $email = $e['value'];
489
                  $typearr_lower = unserialize(strtolower(serialize($e['type'])));
490
                  if(in_array("work", $typearr_lower))
491
                    $type_email = "work";
492
                  elseif(in_array("home", $typearr_lower))
493
                    $type_email = "home";
494
                  elseif(in_array("other", $typearr_lower))
495
                    $type_email = "other";
496
                  else
497
                    continue;
498
                }
499
500
                // DEBUG: print out the email address on the console
501
                //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...
502
503
                $email_add[] = array("type"=>$type_email, "value" => $email);
504
              }
505
            }
506
            $entries[] = array("realName" => $name, "telephony" => $phone_no, "email" => $email_add, "vip" => $vip, "photo" => $photo, "photo_data" => $vcard_obj->photo);
0 ignored issues
show
Documentation introduced by
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...
507
          }
508
        }
509
510
        $snum++;
511
      }
512
    }
513
514
    $this->entries = $entries;
515
  }
516
517
  private function _clear_phone_number($number)
518
  {
519
    return preg_replace("/[^0-9+]/", "", $number);
520
  }
521
522
  public function build_fb_xml()
523
  {
524
    if(empty($this->entries))
525
      throw new Exception('No entries available! Call get_carddav_entries or set $this->entries manually!');
526
527
    // create FB XML in utf-8 format
528
    $root = new SimpleXMLElement('<?xml version="1.0" encoding="UTF-8"?><phonebooks><phonebook></phonebook></phonebooks>');
529
    $pb = $root->phonebook;
1 ignored issue
show
Bug introduced by
The property phonebook does not seem to exist in SimpleXMLElement.

An attempt at access to an undefined property has been detected. This may either be a typographical error or the property has been renamed but there are still references to its old name.

If you really want to allow access to undefined properties, you can define magic methods to allow access. See the php core documentation on Overloading.

Loading history...
530
    $pb->addAttribute("name",$this->config['phonebook_name']);
531
532
    foreach($this->entries as $entry)
533
    {
534
      $contact = $pb->addChild("contact");
535
      $contact->addChild("category", $entry['vip']);
536
      $person = $contact->addChild("person");
537
      $person->addChild("realName", $this->_convert_text($entry['realName']));
538
539
      echo " VCard: '" . utf8_decode($entry['realName']) . "'" . PHP_EOL;
540
541
      // telephone: put the phonenumbers into the fritzbox xml file
542
      $telephony = $contact->addChild("telephony");
543
      $id = 0;
544
      foreach($entry['telephony'] as $tel)
545
      {
546
        $num = $telephony->addChild("number", $tel['value']);
547
        $num->addAttribute("type", $tel['type']);
548
        $num->addAttribute("vanity","");
549
        $num->addAttribute("prio", $tel['prio']);
550
        $num->addAttribute("id", $id);
551
552
        if(isset($tel['quickdial']))
553
        {
554
          $num->addAttribute("quickdial",$tel['quickdial']);
555
          print "  Added quickdial: " . $tel['quickdial'] . " for: " . $tel['value'] . " (" . $tel['type'] . ")" . PHP_EOL;
556
        }
557
558
        $id++;
559
        print "  Added phone: " . $tel['value'] . " (" . $tel['type'] . ")" . PHP_EOL;
560
      }
561
562
      // output a warning if no telephone number was found
563
      if($id == 0)
564
        print "  WARNING: no phone entry found. VCard will be ignored." . PHP_EOL;
565
566
      // email: put the email addresses into the fritzbox xml file
567
      $email = $contact->addChild("services");
568
      $id = 0;
569
      foreach($entry['email'] as $mail)
570
      {
571
        $mail_adr = $email->addChild("email", $mail['value']);
572
        $mail_adr->addAttribute("classifier", $mail['type']);
573
        $mail_adr->addAttribute("id", $id);
574
        $id++;
575
576
        print "  Added email: " . $mail['value'] . " (" . $mail['type'] . ")" . PHP_EOL;
577
      }
578
579
      // check for a photo being part of the VCard
580
      if(($entry['photo']) and ($entry['photo_data']) and (is_array($entry['photo_data'])) and ($entry['photo_data'][0]))
581
      {
582
        // check if 'photo_data'[0] is an array as well because then
583
        // we have to extract ['value'] and friends.
584
        if(is_array($entry['photo_data'][0]) and (array_key_exists('value', $entry['photo_data'][0])))
585
        {
586
          // check if photo_data really contains JPEG data
587
          if((array_key_exists('type', $entry['photo_data'][0])) and (is_array($entry['photo_data'][0]['type'])) and
588
             ($entry['photo_data'][0]['type'][0] == 'jpeg' or $entry['photo_data'][0]['type'][0] == 'jpg'))
589
          {
590
            // get photo, rename, base64 convert and save as jpg
591
            $photo_data = $entry['photo_data'][0]['value'];
592
            $photo_version = substr(sha1($photo_data), 0, 5);
593
            $photo_file = $this->tmpdir . '/' . "{$entry['photo']}_{$photo_version}.jpg";
594
595
            // check for base64 encoding of the photo data and convert it
596
            // accordingly.
597
            if(((array_key_exists('encoding', $entry['photo_data'][0])) and ($entry['photo_data'][0]['encoding'] == 'b')) or $this->is_base64($photo_data))
598
            {
599
              file_put_contents($photo_file . ".b64", $photo_data);
600
              $this->base64_to_jpeg($photo_file . ".b64", $photo_file);
601
              unlink($photo_file . ".b64");
602
            }
603
            else
604
            {
605
              print "  WARNING: non-base64 encoded photo data found and used." . PHP_EOL;
606
              file_put_contents($photo_file, $photo_data);
607
            }
608
609
            // add contact photo to xml
610
            $person->addChild("imageURL", $this->config['fritzbox_path'].$this->config['usb_disk']."FRITZ/fonpix/".basename($photo_file));
611
612
            print "  Added photo: " . basename($photo_file) . PHP_EOL;
613
          }
614
          else
615
           print "  WARNING: Only jpg contact photos are currently supported." . PHP_EOL;
616
        }
617
        elseif(substr($entry['photo_data'][0], 0, 4) == 'http')
618
        {
619
          // add contact photo to xml
620
          $person->addChild("imageURL", $entry['photo_data'][0]);
621
622
          print "  Added photo: " . $entry['photo_data'][0] . PHP_EOL;
623
        }
624
        else
625
          print "  WARNING: Only VCard embedded photo data or a reference URL is currently supported." . PHP_EOL;
626
      }
627
628
      $contact->addChild("services");
629
      $contact->addChild("setup");
630
      $contact->addChild("mod_time", (string)time());
631
    }
632
633
    $this->fbxml = $root->asXML();
0 ignored issues
show
Documentation Bug introduced by
It seems like $root->asXML() can also be of type false. However, the property $fbxml is declared as type string. Maybe add an additional type check?

Our type inference engine has found a suspicous assignment of a value to a property. This check raises an issue when a value that can be of a mixed type is assigned to a property that is type hinted more strictly.

For example, imagine you have a variable $accountId that can either hold an Id object or false (if there is no account id yet). Your code now assigns that value to the id property of an instance of the Account class. This class holds a proper account, so the id value must no longer be false.

Either this assignment is in error or a type check should be added for that assignment.

class Id
{
    public $id;

    public function __construct($id)
    {
        $this->id = $id;
    }

}

class Account
{
    /** @var  Id $id */
    public $id;
}

$account_id = false;

if (starsAreRight()) {
    $account_id = new Id(42);
}

$account = new Account();
if ($account instanceof Id)
{
    $account->id = $account_id;
}
Loading history...
634
  }
635
636
  public function _convert_text($text)
637
  {
638
    $text = htmlspecialchars($text);
639
    return $text;
640
  }
641
642
  public function _concat ($text1,$text2)
643
  {
644
    if($text1 == '')
645
      return $text2;
646
    elseif($text2 == '')
647
      return $text1;
648
    else
649
      return $text1.", ".$text2;
650
  }
651
652
  public function _parse_fb_result($text)
653
  {
654
    preg_match("/\<h2\>([^\<]+)\<\/h2\>/", $text, $matches);
655
    if($matches)
0 ignored issues
show
Bug Best Practice introduced by
The expression $matches of type string[] is implicitly converted to a boolean; are you sure this is intended? If so, consider using ! empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
656
      return $matches[1];
657
    else
658
      return "Error while uploading xml to fritzbox";
659
  }
660
661
  public function upload_to_fb()
662
  {
663
    // if the user wants to save the xml to a separate file, we do so now
664
    if(array_key_exists('output_file',$this->config))
665
    {
666
      $output = fopen($this->config['output_file'], 'w');
667
      if($output)
668
      {
669
        fwrite($output, $this->fbxml);
670
        fclose($output);
671
      }
672
673
      return 0;
674
    }
675
676
    // now we upload the photo jpgs first being stored in the
677
    // temp directory.
678
679
    // perform an ftps-connection to copy over the photos to a specified directory
680
    $ftp_server = $this->config['fritzbox_ip_ftp'];
681
    $conn_id = ftp_ssl_connect($ftp_server);
682 View Code Duplication
    if($conn_id == false)
0 ignored issues
show
Duplication introduced by
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...
683
    {
684
      print " WARNING: Secure connection to FTP-server '" . $ftp_server . "' failed, retrying without SSL." . PHP_EOL;
685
      $conn_id = ftp_connect($ftp_server);
686
    }
687
688
    if($conn_id != false)
689
    {
690
      ftp_set_option($conn_id, FTP_TIMEOUT_SEC, 60);
691
      $login_result = ftp_login($conn_id, $this->config['fritzbox_user'], $this->config['fritzbox_pw']);
692
      if($login_result === true)
693
      {
694
        ftp_pasv($conn_id, true);
695
696
        // create remote photo path on FRITZ!Box if it doesn't exist
697
        $remote_path = $this->config['usb_disk']."/FRITZ/fonpix";
698
        $all_existing_files = ftp_nlist($conn_id, $remote_path);
699
        if($all_existing_files == false)
700
        {
701
          ftp_mkdir($conn_id, $remote_path);
702
          $all_existing_files = array();
703
        }
704
705
        // now iterate through all jpg files in tempdir and upload them if necessary
706
        $dir = new DirectoryIterator($this->tmpdir);
707
        foreach($dir as $fileinfo)
708
        {
709
          if(!$fileinfo->isDot())
710
          {
711
            if($fileinfo->getExtension() == "jpg")
712
            {
713
              $file = $fileinfo->getFilename();
714
715
              print " FTP-Upload '" . $file . "'...";
716
              if(!in_array($remote_path . "/" . $file, $all_existing_files))
717
              {
718
                if(!ftp_put($conn_id, $remote_path . "/" . $file, $fileinfo->getPathname(), FTP_BINARY))
719
                {
720
                  // retry when a fault occurs.
721
                  print " retrying... ";
722
                  $conn_id = ftp_ssl_connect($ftp_server);
723 View Code Duplication
                  if($conn_id == false)
0 ignored issues
show
Duplication introduced by
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...
724
                  {
725
                    print " WARNING: Secure re-connection to FTP-server '" . $ftp_server . "' failed, retrying without SSL." . PHP_EOL;
726
                    $conn_id = ftp_connect($ftp_server);
727
                  }
728
729
                  if($conn_id == false)
730
                  {
731
                    print " ERROR: couldn't re-connect to FTP server '" . $ftp_server . "', abortіng." . PHP_EOL;
732
                    break;
733
                  }
734
735
                  $login_result = ftp_login($conn_id, $this->config['fritzbox_user'], $this->config['fritzbox_pw']);
736
                  if($login_result === false)
737
                  {
738
                    print " ERROR: couldn't re-login to FTP-server '" . $ftp_server . "' with provided username/password settings." . PHP_EOL;
739
                    break;
740
                  }
741
742
                  ftp_pasv($conn_id, true);
743
                  if(!ftp_put($conn_id, $remote_path . "/" . $file, $fileinfo->getPathname(), FTP_BINARY))
744
                    print " ERROR: while uploading file " . $fileinfo->getFilename() . PHP_EOL;
745
                  else
746
                    print " ok." . PHP_EOL;
747
                }
748
                else
749
                  print " ok." . PHP_EOL;
750
751
                // cleanup old files
752
                foreach($all_existing_files as $existing_file)
753
                {
754
                  if(strpos($existing_file, $remote_path."/".substr($file, 0, -10)) !== false)
755
                  {
756
                    print " FTP-Delete: " . $existing_file . PHP_EOL;
757
                    ftp_delete($conn_id, $remote_path . "/" . basename($existing_file));
758
                  }
759
                }
760
              }
761
              else
762
                print " already exists." . PHP_EOL;
763
            }
764
          }
765
        }
766
      }
767
      else
768
        print " ERROR: couldn't login to FTP-server '" . $ftp_server . "' with provided username/password settings." . PHP_EOL;
769
770
      // close ftp connection
771
      ftp_close($conn_id);
772
    }
773
    else
774
      print " ERROR: couldn't connect to FTP server '" . $ftp_server . "'." . PHP_EOL;
775
776
    // 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
777
    $hostname = $this->config['fritzbox_ip'];
778
    if(filter_var($hostname, FILTER_VALIDATE_IP))
779
    {
780
      $hostname = gethostbyaddr($hostname);
781
      if($hostname ==  $this->config['fritzbox_ip'])
782
        print " WARNING: Unable to get hostname for IP address (". $this->config['fritzbox_ip'] .") <" . $hostname . "<" . PHP_EOL;
783
      else
784
      {
785
        print " INFO: Given IP address (". $this->config['fritzbox_ip'] .") has hostname ". $hostname . "." . PHP_EOL;
786
        $this->config['fritzbox_ip'] = $hostname;
787
      }
788
    }
789
790
    // lets post the phonebook xml to the FRITZ!Box
791
    print " Uploading Phonebook XML to " . $this->config['fritzbox_ip'] . PHP_EOL;
792
    try
793
    {
794
      $fritz = new fritzbox_api($this->config['fritzbox_pw'],
795
        $this->config['fritzbox_user'],
796
        $this->config['fritzbox_ip'],
797
        $this->config['fritzbox_force_local_login']);
798
799
      $formfields = array(
800
        'PhonebookId' => $this->config['phonebook_number']
801
      );
802
803
      $filefileds = array('PhonebookImportFile' => array(
804
       'type' => 'text/xml',
805
       'filename' => 'updatepb.xml',
806
       'content' => $this->fbxml,
807
       )
808
      );
809
810
      $raw_result =  $fritz->doPostFile($formfields, $filefileds);   // send the command
811
      $msg = $this->_parse_fb_result($raw_result);
812
      unset($fritz);  // destroy the object to log out
813
814
      print "  FRITZ!Box returned message: '" . $msg . "'" . PHP_EOL;
815
    }
816
    catch(Exception $e)
817
    {
818
      print "  ERROR: " . $e->getMessage() . PHP_EOL;     // show the error message in anything failed
819
    }
820
  }
821
}
822