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.php (12 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
    $imgseqfname = 1;
200
    $snum = 0;
201
202
    foreach($this->config['carddav'] as $conf)
0 ignored issues
show
The expression $this->config['carddav'] of type string|null is not guaranteed to be traversable. How about adding an additional type check?

There are different options of fixing this problem.

  1. If you want to be on the safe side, you can add an additional type-check:

    $collection = json_decode($data, true);
    if ( ! is_array($collection)) {
        throw new \RuntimeException('$collection must be an array.');
    }
    
    foreach ($collection as $item) { /** ... */ }
    
  2. If you are sure that the expression is traversable, you might want to add a doc comment cast to improve IDE auto-completion and static analysis:

    /** @var array $collection */
    $collection = json_decode($data, true);
    
    foreach ($collection as $item) { /** .. */ }
    
  3. Mark the issue as a false-positive: Just hover the remove button, in the top-right corner of this issue for more options.

Loading history...
203
    {
204
      print " [" . $snum . "]: " . $conf['url'] . " ";
205
      $carddav = new CardDavPHP\CardDavBackend($conf['url']);
206
      $carddav->setAuth($conf['user'], $conf['pw']);
207
208
      // set the vcard extension in case the user
209
      // defined it in the config
210
      if(isset($conf['extension']))
211
        $carddav->setVcardExtension($conf['extension']);
212
213
      // retrieve data from the CardDAV server now
214
      $xmldata =  $carddav->get();
215
216
      // identify if we received UTF-8 encoded data from the
217
      // CardDAV server and if not reencode it since the FRITZ!Box
218
      // requires UTF-8 encoded data
219
      if(iconv('utf-8', 'utf-8//IGNORE', $xmldata) != $xmldata)
220
        $xmldata = utf8_encode($xmldata);
221
222
      // read raw_vcard data from xml response
223
      $raw_vcards = array();
224
      $xmlvcard = new SimpleXMLElement($xmldata);
225
226
      foreach($xmlvcard->element as $vcard_element)
227
      {
228
        $id = $vcard_element->id->__toString();
229
        $value = (string)$vcard_element->vcard->__toString();
230
        $raw_vcards[$id] = $value;
231
      }
232
233
      print " " . count($raw_vcards) . " VCards retrieved." . PHP_EOL;
234
235
      // parse raw_vcards
236
      $result = array();
0 ignored issues
show
$result is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
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]))
243
          $name_arr = $vcard_obj->n[0];
244
        $org_arr = null;
245
        if(isset($vcard_obj->org[0]))
246
          $org_arr = $vcard_obj->org[0];
247
        $addnames = '';
248
        $prefix = '';
249
        $suffix = '';
250
        $orgname = '';
251
        $firstname = '';
0 ignored issues
show
$firstname is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
252
        $lastname = '';
0 ignored issues
show
$lastname is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
253
254
        // Build name Parts if existing ans switch to true in config
255
        if(isset($name_arr['prefixes']) AND $this->config['prefix'])
256
          $prefix = trim($name_arr['prefixes']);
257
258
        if(isset($name_arr['suffixes']) AND $this->config['suffix'])
259
          $suffix = trim($name_arr['suffixes']);
260
261
        if(isset($name_arr['additionalnames']) AND $this->config['addnames'])
262
          $addnames = trim($name_arr['additionalnames']);
263
264
        if(isset($org_arr['name']) AND $this->config['orgname'])
265
          $orgname = trim($org_arr['name']);
266
267
        $firstname = trim($name_arr['firstname']);
268
        $lastname = trim($name_arr['lastname']);
269
270
        // the following section implemented different ways of constructing the
271
        // final phonebook name entry depending on user preferred settings
272
        // selectable in the config file. Possible options are:
273
        //
274
        // $this->config['fullname_format']:
275
        //
276
        // 0: "Prefix Lastname, Firstname AdditionalNames Suffix (orgname)"
277
        // 1: "Prefix Firstname Lastname AdditionalNames Suffix (orgname)"
278
        // 2: "Prefix Firstname AdditionalNames Lastname Suffix (orgname)"
279
        //
280
        $name = '';
281
        $format = $this->config['fullname_format'];
282
283
        // Prefix
284
        if(!empty($prefix))
285
          $name .= $prefix;
286
287 View Code Duplication
        if($format == 0)
288
        {
289
          // Lastname
290
          if(!empty($name) AND !empty($lastname))
291
            $name .= ' ' . $lastname;
292
          else
293
            $name .= $lastname;
294
        }
295
        else
296
        {
297
          // Firstname
298
          if(!empty($name) AND !empty($firstname))
299
            $name .= ' ' . $firstname;
300
          else
301
            $name .= $firstname;
302
        }
303
304 View Code Duplication
        if($format == 2)
305
        {
306
          // AdditionalNames
307
          if(!empty($name) AND !empty($addnames))
308
            $name .= ' ' . $addnames;
309
          else
310
            $name .= $addnames;
311
        }
312
313 View Code Duplication
        if($format == 0)
314
        {
315
          // Firstname
316
          if(!empty($name) AND !empty($firstname))
317
            $name .= ', ' . $firstname;
318
          else
319
            $name .= $firstname;
320
        }
321
        else
322
        {
323
          // Lastname
324
          if(!empty($name) AND !empty($lastname))
325
            $name .= ' ' . $lastname;
326
          else
327
            $name .= $lastname;
328
        }
329
330 View Code Duplication
        if($format != 2)
331
        {
332
          // AdditionalNames
333
          if(!empty($name) AND !empty($addnames))
334
            $name .= ' ' . $addnames;
335
          else
336
            $name .= $addnames;
337
        }
338
339
        // Suffix
340
        if(!empty($name) AND !empty($suffix))
341
          $name .= ' ' . $suffix;
342
        else
343
          $name .= $suffix;
344
345
        // OrgName
346
        if(!empty($name) AND !empty($orgname))
347
          $name .= ' (' . $orgname . ')';
348
        else
349
          $name .= $orgname;
350
351
        // make sure to trim whitespaces and double spaces
352
        $name = trim(str_replace('  ', ' ', $name));
353
354
        if(empty($name))
355
        {
356
          print '  WARNING: No fullname, lastname or orgname found!';
357
          $name = 'UNKNOWN';
358
        }
359
360
        // format filename of contact photo; remove special letters, added config option for sequential filnames default is false
361
        if($vcard_obj->photo)
362
        {
363
          if(isset($this->config['seq_photo_name']) AND $this->config['seq_photo_name'] == true)
0 ignored issues
show
Bug Best Practice introduced by
It seems like you are loosely comparing $this->config['seq_photo_name'] of type string to the boolean true. If you are specifically checking for a non-empty string, consider using the more explicit !== '' instead.
Loading history...
364
          {
365
            $photo = $imgseqfname;
366
            $imgseqfname++;
367
          }
368
          else
369
          {
370
            $photo = str_replace(array(',','&',' ','/','ä','ö','ü','Ä','Ö','Ü','ß','á','à','ó','ò','ú','ù','í','ø'),
371
            array('','_','_','_','ae','oe','ue','Ae','Oe','Ue','ss','a','a','o','o','u','u','i','oe'),$name);
372
          }
373
        }
374
        else
375
          $photo = '';
376
377
        // phone
378
        $phone_no = array();
379
        if($vcard_obj->categories)
380
          $categories = $vcard_obj->categories[0];
381
        else
382
          $categories = array();
383
384
        $quick_dial_for_nr = null;
0 ignored issues
show
$quick_dial_for_nr is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
385
        $quick_dial_nr = null;
0 ignored issues
show
$quick_dial_nr is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
386
        
387
        // check for quickdial entry
388
        if(isset($vcard_obj->note[0]))
389
        {
390
          $note = $vcard_obj->note[0];
391
          $notes = explode($this->config['quickdial_keyword'], $note);
392
          foreach($notes as $linenr => $linecontent)
393
          {
394
            $found = strrpos($linecontent , ":**7");
395
            if($found > 0)
396
            {
397
              $pos_qd_start = strrpos($linecontent , ":**7" );
398
              $quick_dial_for_nr = preg_replace("/[^0-9+]/", "",substr($linecontent , 0, $pos_qd_start));
399
              $quick_dial_nr = intval(substr($linecontent , $pos_qd_start+4, 3));
400
              $quick_dial_arr[$quick_dial_for_nr]=$quick_dial_nr;
401
            }
402
          }
403
        }
404
405
        // e-mail addresses
406
        $email_add = array();
407
        $vip = isset($this->config['group_vip']) && in_array((string)$this->config['group_vip'], $categories);
408
409
        if(array_key_exists('group_filter',$this->config))
410
        {
411
          $add_entry = 0;
412
          foreach($this->config['group_filter'] as $group_filter)
0 ignored issues
show
The expression $this->config['group_filter'] of type string|null is not guaranteed to be traversable. How about adding an additional type check?

There are different options of fixing this problem.

  1. If you want to be on the safe side, you can add an additional type-check:

    $collection = json_decode($data, true);
    if ( ! is_array($collection)) {
        throw new \RuntimeException('$collection must be an array.');
    }
    
    foreach ($collection as $item) { /** ... */ }
    
  2. If you are sure that the expression is traversable, you might want to add a doc comment cast to improve IDE auto-completion and static analysis:

    /** @var array $collection */
    $collection = json_decode($data, true);
    
    foreach ($collection as $item) { /** .. */ }
    
  3. Mark the issue as a false-positive: Just hover the remove button, in the top-right corner of this issue for more options.

Loading history...
413
          {
414
            if(in_array($group_filter,$categories))
415
            {
416
              $add_entry = 1;
417
              break;
418
            }
419
          }
420
        } 
421
        else
422
          $add_entry = 1;
423
424
        if($add_entry == 1)
425
        {
426
          foreach($vcard_obj->tel as $t)
427
          {
428
            $prio = 0;
429
            $quickdial =null;
430
            
431
            if(!is_array($t) || empty($t['type']))
432
            {
433
              $type = "mobile";
434
              $phone_number = $t;
435
            }
436
            else
437
            {
438
              $phone_number = $t['value'];
439
              
440
              $phone_number_clean = preg_replace("/[^0-9+]/", "",$phone_number);
441
              foreach($quick_dial_arr as $qd_phone_nr => $value)
442
              {
443
                if($qd_phone_nr == $phone_number_clean)
444
                {
445
                  //Set quickdial
446
                  if($value == 1)
447
                    print "\nWARNING: Quickdial value 1 (**701) is not possible but used! \n";
448
                  elseif($value >= 100)
449
                    print "\nWARNING: Quickdial value bigger than 99 (**799) is not possible but used! \n";
450
451
                  $quickdial = $value;
452
                }
453
              }
454
455
              $typearr_lower = unserialize(strtolower(serialize($t['type'])));
456
457
              // find out priority
458
              if(in_array("pref", $typearr_lower))
459
                $prio = 1;
460
461
              // set the proper type
462
              if(in_array("cell", $typearr_lower))
463
                $type = "mobile";
464
              elseif(in_array("home", $typearr_lower))
465
                $type = "home";
466
              elseif(in_array("fax", $typearr_lower))
467
                $type = "fax_work";
468
              elseif(in_array("work", $typearr_lower))
469
                $type = "work";
470
              elseif(in_array("other", $typearr_lower))
471
                $type = "other";
472
              elseif(in_array("dom", $typearr_lower))
473
                $type = "other";
474
              else
475
                continue;
476
            }
477
            $phone_no[] =  array("type"=>$type, "prio"=>$prio, "quickdial"=>$quickdial, "value" => $this->_clear_phone_number($phone_number));
478
          }
479
480
          // request email address and type
481
          if($vcard_obj->email)
482
          {
483
            foreach($vcard_obj->email as $e)
484
            {
485
              if(empty($e['type']))
486
              {
487
                $type_email = "work";
488
                $email = $e;
489
              }
490
              else
491
              {
492
                $email = $e['value'];
493
                $typearr_lower = unserialize(strtolower(serialize($e['type'])));
494
                if(in_array("work", $typearr_lower))
495
                  $type_email = "work";
496
                elseif(in_array("home", $typearr_lower))
497
                  $type_email = "home";
498
                elseif(in_array("other", $typearr_lower))
499
                  $type_email = "other";
500
                else
501
                  continue;
502
              }
503
504
              // DEBUG: print out the email address on the console
505
              //print $type_email.": ".$email."\n";
506
507
              $email_add[] = array("type"=>$type_email, "value" => $email);
508
            }
509
          }
510
          $entries[] = array("realName" => $name, "telephony" => $phone_no, "email" => $email_add, "vip" => $vip, "photo" => $photo, "photo_data" => $vcard_obj->photo);
511
        }
512
      }
513
514
      $snum++;
515
    }
516
517
    $this->entries = $entries;
518
  }
519
520
  private function _clear_phone_number($number)
521
  {
522
    return preg_replace("/[^0-9+]/", "", $number);
523
  }
524
525
  public function build_fb_xml()
526
  {
527
    if(empty($this->entries))
528
      throw new Exception('No entries available! Call get_carddav_entries or set $this->entries manually!');
529
530
    // create FB XML in utf-8 format
531
    $root = new SimpleXMLElement('<?xml version="1.0" encoding="UTF-8"?><phonebooks><phonebook></phonebook></phonebooks>');
532
    $pb = $root->phonebook;
533
    $pb->addAttribute("name",$this->config['phonebook_name']);
534
535
    foreach($this->entries as $entry)
536
    {
537
      $contact = $pb->addChild("contact");
538
      $contact->addChild("category", $entry['vip']);
539
      $person = $contact->addChild("person");
540
      $person->addChild("realName", $this->_convert_text($entry['realName']));
541
542
      echo " VCard: '" . utf8_decode($entry['realName']) . "'" . PHP_EOL;
543
544
      // telephone: put the phonenumbers into the fritzbox xml file
545
      $telephony = $contact->addChild("telephony");
546
      $id = 0;
547
      foreach($entry['telephony'] as $tel)
548
      {
549
        $num = $telephony->addChild("number", $tel['value']);
550
        $num->addAttribute("type", $tel['type']);
551
        $num->addAttribute("vanity","");
552
        $num->addAttribute("prio", $tel['prio']);
553
        $num->addAttribute("id", $id);
554
555
        if(isset($tel['quickdial']))
556
        {
557
          $num->addAttribute("quickdial",$tel['quickdial']);
558
          print "  Added quickdial: " . $tel['quickdial'] . " for: " . $tel['value'] . " (" . $tel['type'] . ")" . PHP_EOL;
559
        }
560
561
        $id++;
562
        print "  Added phone: " . $tel['value'] . " (" . $tel['type'] . ")" . PHP_EOL;
563
      }
564
565
      // output a warning if no telephone number was found
566
      if($id == 0)
567
        print "  WARNING: no phone entry found. VCard will be ignored." . PHP_EOL;
568
569
      // email: put the email addresses into the fritzbox xml file
570
      $email = $contact->addChild("services");
571
      $id = 0;
572
      foreach($entry['email'] as $mail)
573
      {
574
        $mail_adr = $email->addChild("email", $mail['value']);
575
        $mail_adr->addAttribute("classifier", $mail['type']);
576
        $mail_adr->addAttribute("id", $id);
577
        $id++;
578
579
        print "  Added email: " . $mail['value'] . " (" . $mail['type'] . ")" . PHP_EOL;
580
      }
581
582
      // check for a photo being part of the VCard
583
      if(($entry['photo']) and ($entry['photo_data']) and (is_array($entry['photo_data'])) and ($entry['photo_data'][0]))
584
      {
585
        // check if 'photo_data'[0] is an array as well because then
586
        // we have to extract ['value'] and friends.
587
        if(is_array($entry['photo_data'][0]) and (array_key_exists('value', $entry['photo_data'][0])))
588
        {
589
          // check if photo_data really contains JPEG data
590
          if((array_key_exists('type', $entry['photo_data'][0])) and (is_array($entry['photo_data'][0]['type'])) and
591
             ($entry['photo_data'][0]['type'][0] == 'jpeg' or $entry['photo_data'][0]['type'][0] == 'jpg'))
592
          {
593
            // get photo, rename, base64 convert and save as jpg
594
            $photo_data = $entry['photo_data'][0]['value'];
595
            $photo_version = substr(sha1($photo_data), 0, 5);
596
            $photo_file = $this->tmpdir . '/' . "{$entry['photo']}_{$photo_version}.jpg";
597
598
            // check for base64 encoding of the photo data and convert it
599
            // accordingly.
600
            if(((array_key_exists('encoding', $entry['photo_data'][0])) and ($entry['photo_data'][0]['encoding'] == 'b')) or $this->is_base64($photo_data))
601
            {
602
              file_put_contents($photo_file . ".b64", $photo_data);
603
              $this->base64_to_jpeg($photo_file . ".b64", $photo_file);
604
              unlink($photo_file . ".b64");
605
            }
606
            else
607
            {
608
              print "  WARNING: non-base64 encoded photo data found and used." . PHP_EOL;
609
              file_put_contents($photo_file, $photo_data);
610
            }
611
612
            // add contact photo to xml
613
            $person->addChild("imageURL", $this->config['fritzbox_path'].$this->config['usb_disk']."FRITZ/fonpix/".basename($photo_file));
614
615
            print "  Added photo: " . basename($photo_file) . PHP_EOL;
616
          }
617
          else
618
           print "  WARNING: Only jpg contact photos are currently supported." . PHP_EOL;
619
        }
620
        elseif(substr($entry['photo_data'][0], 0, 4) == 'http')
621
        {
622
          // add contact photo to xml
623
          $person->addChild("imageURL", $entry['photo_data'][0]);
624
625
          print "  Added photo: " . $entry['photo_data'][0] . PHP_EOL;
626
        }
627
        else
628
          print "  WARNING: Only VCard embedded photo data or a reference URL is currently supported." . PHP_EOL;
629
      }
630
631
      $contact->addChild("services");
632
      $contact->addChild("setup");
633
      $contact->addChild("mod_time", (string)time());
634
    }
635
636
    $this->fbxml = $root->asXML();
637
  }
638
639
  public function _convert_text($text)
640
  {
641
    $text = htmlspecialchars($text);
642
    return $text;
643
  }
644
645
  public function _concat ($text1,$text2)
646
  {
647
    if($text1 == '')
648
      return $text2;
649
    elseif($text2 == '')
650
      return $text1;
651
    else
652
      return $text1.", ".$text2;
653
  }
654
655
  public function _parse_fb_result($text)
656
  {
657
    preg_match("/\<h2\>([^\<]+)\<\/h2\>/", $text, $matches);
658
    if($matches)
659
      return $matches[1];
660
    else
661
      return "Error while uploading xml to fritzbox";
662
  }
663
664
  public function upload_to_fb()
665
  {
666
    // if the user wants to save the xml to a separate file, we do so now
667
    if(array_key_exists('output_file',$this->config))
668
    {
669
      $output = fopen($this->config['output_file'], 'w');
670
      if($output)
671
      {
672
        fwrite($output, $this->fbxml);
673
        fclose($output);
674
      }
675
676
      return 0;
677
    }
678
679
    // now we upload the photo jpgs first being stored in the
680
    // temp directory.
681
682
    // perform an ftps-connection to copy over the photos to a specified directory
683
    $ftp_server = $this->config['fritzbox_ip_ftp'];
684
    $conn_id = ftp_ssl_connect($ftp_server);
685 View Code Duplication
    if($conn_id == false)
686
    {
687
      print " WARNING: Secure connection to FTP-server '" . $ftp_server . "' failed, retrying without SSL." . PHP_EOL;
688
      $conn_id = ftp_connect($ftp_server);
689
    }
690
691
    if($conn_id != false)
692
    {
693
      ftp_set_option($conn_id, FTP_TIMEOUT_SEC, 60);
694
      $login_result = ftp_login($conn_id, $this->config['fritzbox_user'], $this->config['fritzbox_pw']);
695
      if($login_result == true)
0 ignored issues
show
Coding Style Best Practice introduced by
It seems like you are loosely comparing two booleans. Considering using the strict comparison === instead.

When comparing two booleans, it is generally considered safer to use the strict comparison operator.

Loading history...
696
      {
697
        ftp_pasv($conn_id, true);
698
699
        // create remote photo path on FRITZ!Box if it doesn't exist
700
        $remote_path = $this->config['usb_disk']."/FRITZ/fonpix";
701
        $all_existing_files = ftp_nlist($conn_id, $remote_path);
702
        if($all_existing_files == false)
703
        {
704
          ftp_mkdir($conn_id, $remote_path);
705
          $all_existing_files = array();
706
        }
707
708
        // now iterate through all jpg files in tempdir and upload them if necessary
709
        $dir = new DirectoryIterator($this->tmpdir);
710
        foreach($dir as $fileinfo)
711
        {
712
          if(!$fileinfo->isDot())
713
          {
714
            if($fileinfo->getExtension() == "jpg")
715
            {
716
              $file = $fileinfo->getFilename();
717
718
              print " FTP-Upload '" . $file . "'...";
719
              if(!in_array($remote_path . "/" . $file, $all_existing_files))
720
              {
721
                if(!ftp_put($conn_id, $remote_path . "/" . $file, $fileinfo->getPathname(), FTP_BINARY))
722
                {
723
                  // retry when a fault occurs.
724
                  print " retrying... ";
725
                  $conn_id = ftp_ssl_connect($ftp_server);
726 View Code Duplication
                  if($conn_id == false)
727
                  {
728
                    print " WARNING: Secure re-connection to FTP-server '" . $ftp_server . "' failed, retrying without SSL." . PHP_EOL;
729
                    $conn_id = ftp_connect($ftp_server);
730
                  }
731
732
                  if($conn_id == false)
733
                  {
734
                    print " ERROR: couldn't re-connect to FTP server '" . $ftp_server . "', abortіng." . PHP_EOL;
735
                    break;
736
                  }
737
738
                  $login_result = ftp_login($conn_id, $this->config['fritzbox_user'], $this->config['fritzbox_pw']);
739
                  if($login_result == false)
0 ignored issues
show
Coding Style Best Practice introduced by
It seems like you are loosely comparing two booleans. Considering using the strict comparison === instead.

When comparing two booleans, it is generally considered safer to use the strict comparison operator.

Loading history...
740
                  {
741
                    print " ERROR: couldn't re-login to FTP-server '" . $ftp_server . "' with provided username/password settings." . PHP_EOL;
742
                    break;
743
                  }
744
745
                  ftp_pasv($conn_id, true);
746
                  if(!ftp_put($conn_id, $remote_path . "/" . $file, $fileinfo->getPathname(), FTP_BINARY))
747
                    print " ERROR: while uploading file " . $fileinfo->getFilename() . PHP_EOL;
748
                  else
749
                    print " ok." . PHP_EOL;
750
                }
751
                else
752
                  print " ok." . PHP_EOL;
753
754
                // cleanup old files
755
                foreach($all_existing_files as $existing_file)
756
                {
757
                  if(strpos($existing_file, $remote_path."/".substr($file, 0, -10)) !== false)
758
                  {
759
                    print " FTP-Delete: " . $existing_file . PHP_EOL;
760
                    ftp_delete($conn_id, $remote_path . "/" . basename($existing_file));
761
                  }
762
                }
763
              }
764
              else
765
                print " already exists." . PHP_EOL;
766
            }
767
          }
768
        }
769
      }
770
      else
771
        print " ERROR: couldn't login to FTP-server '" . $ftp_server . "' with provided username/password settings." . PHP_EOL;
772
773
      // close ftp connection
774
      ftp_close($conn_id);
775
    }
776
    else
777
      print " ERROR: couldn't connect to FTP server '" . $ftp_server . "'." . PHP_EOL;
778
779
    // 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
780
    $hostname = $this->config['fritzbox_ip'];
781
    if(filter_var($hostname, FILTER_VALIDATE_IP))
782
    {
783
      $hostname = gethostbyaddr($hostname);
784
      if($hostname ==  $this->config['fritzbox_ip'])
785
        print " WARNING: Unable to get hostname for IP address (". $this->config['fritzbox_ip'] .") <" . $hostname . "<" . PHP_EOL;
786
      else
787
      {
788
        print " INFO: Given IP address (". $this->config['fritzbox_ip'] .") has hostname ". $hostname . "." . PHP_EOL;
789
        $this->config['fritzbox_ip'] = $hostname;
790
      }
791
    }
792
793
    // lets post the phonebook xml to the FRITZ!Box
794
    print " Uploading Phonebook XML to " . $this->config['fritzbox_ip'] . PHP_EOL;
795
    try
796
    {
797
      $fritz = new fritzbox_api($this->config['fritzbox_pw'],
798
        $this->config['fritzbox_user'],
799
        $this->config['fritzbox_ip'],
800
        $this->config['fritzbox_force_local_login']);
801
802
      $formfields = array(
803
        'PhonebookId' => $this->config['phonebook_number']
804
      );
805
806
      $filefileds = array('PhonebookImportFile' => array(
807
       'type' => 'text/xml',
808
       'filename' => 'updatepb.xml',
809
       'content' => $this->fbxml,
810
       )
811
      );
812
813
      $raw_result =  $fritz->doPostFile($formfields, $filefileds);   // send the command
814
      $msg = $this->_parse_fb_result($raw_result);
815
      $fritz = null;  // destroy the object to log out
0 ignored issues
show
$fritz is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
816
817
      print "  FRITZ!Box returned message: '" . $msg . "'" . PHP_EOL;
818
    }
819
    catch(Exception $e)
820
    {
821
      print "  ERROR: " . $e->getMessage() . PHP_EOL;     // show the error message in anything failed
822
    }
823
  }
824
}
825
?>
0 ignored issues
show
It is not recommended to use PHP's closing tag ?> in files other than templates.

Using a closing tag in PHP files that only contain PHP code is not recommended as you might accidentally add whitespace after the closing tag which would then be output by PHP. This can cause severe problems, for example headers cannot be sent anymore.

A simple precaution is to leave off the closing tag as it is not required, and it also has no negative effects whatsoever.

Loading history...
826