crawler.php 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458
  1. #!/bin/php
  2. <?php
  3. /*
  4. This program is free software: you can redistribute it and/or modify
  5. it under the terms of the GNU General Public License as published by
  6. the Free Software Foundation, either version 3 of the License, or
  7. (at your option) any later version.
  8. This program is distributed in the hope that it will be useful,
  9. but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  11. GNU General Public License for more details.
  12. You should have received a copy of the GNU General Public License
  13. along with this program. If not, see <http://www.gnu.org/licenses/>.
  14. */
  15. define('N',"\n");
  16. declare(ticks=1);
  17. pcntl_signal(SIGTERM,'signalHandler');// Termination ('kill' was called)
  18. pcntl_signal(SIGHUP,'signalHandler');// Terminal log-out
  19. pcntl_signal(SIGINT,'signalHandler');// Interrupted (Ctrl-C is pressed)
  20. function signalHandler($signal) {
  21. global $link, $logf, $jsonf;
  22. lecho(N.'Sono stato interrotto.'.N);
  23. if ($link) {
  24. lecho('La connessione MySQL è aperta, la chiudo.'.N);
  25. mysqli_close($link);
  26. }
  27. if ($jsonf) {
  28. echo('Il file di dump json è aperto, lo chiudo.'.N);
  29. fwrite($jsonf,'"Fine?": true'.N.'}'.N);
  30. fclose($jsonf);
  31. }
  32. if ($logf) {
  33. echo('Il file di log è aperto, lo chiudo.'.N);
  34. fclose($logf);
  35. }
  36. exit(2);
  37. }
  38. $opts=array(
  39. 'timeout'=>3,
  40. 'log'=>true,
  41. 'jsonfp'=>'instances.json',
  42. 'jsonwrite'=>true,
  43. 'jsonread'=>false
  44. );
  45. use function mysqli_real_escape_string as myesc;
  46. function tosec($str) {
  47. if (preg_match('/^([0-9]+)([smogSMA]?)/',$str,$buf)===1) {
  48. switch ($buf[2]) {
  49. case '':
  50. case 's':
  51. return($buf[1]);
  52. break;
  53. case 'm':
  54. return($buf[1]*60);
  55. break;
  56. case 'o':
  57. return($buf[1]*60*60);
  58. break;
  59. case 'g':
  60. return($buf[1]*60*60*24);
  61. break;
  62. case 'S':
  63. return($buf[1]*60*60*24*7);
  64. break;
  65. case 'M':
  66. return($buf[1]*60*60*24*30);
  67. break;
  68. case 'A':
  69. return($buf[1]*60*60*24*365);
  70. break;
  71. }
  72. } else {
  73. return(false);
  74. }
  75. }
  76. function mexit($msg,$code,$closemy=false) {
  77. global $link;
  78. lecho($msg);
  79. if ($closemy)
  80. mysqli_close($link);
  81. if ($logf)
  82. fclose($logf);
  83. exit($code);
  84. }
  85. function lecho($msg,$logonly=false) {
  86. global $opts, $logf;
  87. if (!$logonly)
  88. echo($msg);
  89. if ($opts['log'])
  90. fwrite($logf,$msg);
  91. }
  92. $logfp='crawler.log';
  93. if ($opts['log']) {
  94. $logf=@fopen(__DIR__.'/'.$logfp,'w')
  95. or mexit('Non ho potuto aprire in scrittura il file di log «'.$logfp.'».',1);
  96. }
  97. $inifp='../sec/mastostartadmin.ini';
  98. $iniarr=parse_ini_file($inifp)
  99. or mexit('Impossibile aprire il file di configurazione «'.$inifp.'»'.N,1);
  100. $link=mysqli_connect($iniarr['db_host'],$iniarr['db_admin_name'],$iniarr['db_admin_password'],$iniarr['db_name'],$iniarr['db_port'],$iniarr['db_socket'])
  101. or mexit(mysqli_error($link).N,1);
  102. mysqli_set_charset($link,'utf8');
  103. $contextopts=array(
  104. 'http'=>array(
  105. 'timeout'=>$opts['timeout']
  106. ),
  107. 'socket'=>array(
  108. 'tcp_nodelay'=>true
  109. )
  110. );
  111. $context=stream_context_create($contextopts);
  112. $blacklist=array();
  113. lecho('Carico la blacklist dal database...'.N);
  114. $res=mysqli_query($link,'SELECT * FROM Blacklist')
  115. or mexit(mysqli_error($link).N,3,true);
  116. lecho(mysqli_num_rows($res).' istanze nella blacklist.'.N);
  117. while($row=mysqli_fetch_assoc($res)) {
  118. $blacklist[$row['Domain']]=$row;
  119. }
  120. function pgdatetomy($pgdate) {
  121. if (preg_match('/^(\d+)-(\d+)-(\d+)[ T]{1}(\d+):(\d+):(\d+)\.(\d+)Z?$/',$pgdate,$buf)===1) {
  122. return(mktime($buf[4],$buf[5],$buf[6],$buf[2],$buf[3],$buf[1])+floatval('0.'.$buf[7]));
  123. } else {
  124. return(false);
  125. }
  126. }
  127. function blpgdumplinetomy($line) {
  128. $truefalse=array('f'=>0,'t'=>1);
  129. $row=explode("\t",$line);
  130. $row=array('Domain'=>$row[0],
  131. 'CreatedAt'=>pgdatetomy($row[1]),
  132. 'ModifiedAt'=>pgdatetomy($row[2]),
  133. 'Severity'=>$row[3],
  134. 'RejectMedia'=>$truefalse[$row[4]],
  135. 'RejectReports'=>$truefalse[$row[5]],
  136. 'PublicComment'=>$row[6]);
  137. return($row);
  138. }
  139. $blacklistnew=array();
  140. $insts=array();
  141. lecho('Carico le istanze di partenza...'.N);
  142. $res=mysqli_query($link,'SELECT Domain FROM StartNodes')
  143. or mexit(mysqli_error($link).N,3,true);
  144. lecho(mysqli_num_rows($res).' istanze di partenza.'.N);
  145. while($row=mysqli_fetch_assoc($res)) {
  146. $insts[$row['Domain']]=null;
  147. lecho('Recupero la lista delle istanze note a «'.$row['Domain'].'» ... ');
  148. $buf=@file_get_contents('https://'.$row['Domain'].'/api/v1/instance/peers',false,$context);
  149. if ($buf!==false) {
  150. lecho('OK :-)'.N);
  151. $peers=json_decode($buf,true);
  152. foreach ($peers as $pdom) {
  153. if (!array_key_exists($pdom,$insts) && strlen($pdom)<=64) {
  154. $insts[$pdom]=null;
  155. }
  156. }
  157. } else {
  158. lecho('ERRORE :-('.N);
  159. }
  160. lecho('Recupero la blacklist di «'.$row['Domain'].'» ... ');
  161. $buf=@file_get_contents('https://'.$row['Domain'].'/domain_blocks.txt',false,$context);
  162. if ($buf!==false) {
  163. lecho('OK :-)'.N);
  164. $buf=explode(N,$buf);
  165. foreach ($buf as $line) {
  166. if (preg_match('/(^#.*$)|(^\s*$)/',$line)===0) {
  167. $brow=blpgdumplinetomy($line);
  168. if (!array_key_exists($brow['Domain'],$blacklist)) {
  169. $blacklistnew[$brow['Domain']]=$brow;
  170. }
  171. $blacklist[$brow['Domain']]=$brow;
  172. }
  173. }
  174. } else {
  175. lecho('ERRORE :-('.N);
  176. }
  177. }
  178. //lecho('Carico le istanze note dal DB e aggiungo alla lista di quelle da controllare quelle che non ci sono già.'.N);
  179. $res=mysqli_query($link,'SELECT URI FROM Instances')
  180. or mexit(mysqli_error($link).N,3,true);
  181. while($row=mysqli_fetch_assoc($res)) {
  182. if (!array_key_exists($row['URI'],$insts))
  183. $insts[$row['URI']]=null;
  184. }
  185. ksort($insts);
  186. ksort($blacklist);
  187. ksort($blacklistnew);
  188. lecho('Istanze recuperate: '.count($insts).N);
  189. lecho('Istanze blacklistate: '.count($blacklist).', di cui '.count($blacklistnew).' nuove da aggiungere al DB.'.N);
  190. foreach ($blacklistnew as $row) {
  191. foreach($row as $key=>$val)
  192. $row[$key]=myesc($link,$val);
  193. mysqli_query($link,'INSERT INTO Blacklist (ID, Domain, CreatedAt, ModifiedAt, Severity, RejectMedia, RejectReports, PrivateComment, PublicComment) VALUES (NULL, \''.$row['Domain'].'\', \''.$row['CreatedAt'].'\', \''.$row['ModifiedAt'].'\', \''.$row['Severity'].'\', \''.$row['RejectMedia'].'\', \''.$row['RejectReports'].'\', NULL, \''.$row['PublicComment'].'\')')
  194. or mexit(mysqli_error($link).N,3,true);
  195. }
  196. //INSERT INTO `Instances` (`ID`, `New`, `Chosen`, `Visible`, `BlackListed`, `URI`, `Title`, `ShortDesc`, `LongDesc`, `OurDesc`, `PlaceID`, `Email`, `Software`, `Version`, `UserCount`, `StatusCount`, `DomainCount`, `ActiveUsersMonth`, `ActiveUsersHalfYear`, `Thumb`, `RegOpen`, `RegReqApproval`, `MaxTootChars`, `AdmAccount`, `AdmDisplayName`, `AdmCreatedAt`, `AdmNote`, `AdmURL`, `AdmAvatar`, `AdmHeader`) VALUES (NULL, '1', '0', '0', '0', 'pantagruel.dnsup.net', 'Pantagruel', 'Descrizione breve', 'Descrizione lunga', 'Istanza molto carina senza soffitto, senza cucina', '1', 'Graume <graume@inventati.org>', 'mastodon', '3.0.1', '2', '12', '345', '5', '10', 'http://www.iedm.it', '1', '0', '540', 'admin', 'Admin', '2019-12-11', 'Note \'admin\'', 'https://rame.altervista.org', 'http://www.iedm.it', 'http://www.iedm.it');
  197. function b2i($bool) {
  198. if ($bool)
  199. return(1);
  200. else
  201. return(0);
  202. }
  203. //array key exists and value is not null
  204. function akeavinn($key,&$arr) {
  205. if (array_key_exists($key,$arr) && !is_null($arr[$key]))
  206. return(true);
  207. else
  208. return(false);
  209. }
  210. function nempty($str) {
  211. if (preg_match('/^\s*$/',$str)===1)
  212. return(null);
  213. else
  214. return($str);
  215. }
  216. function subarim($glue,$key,&$arr) {
  217. $str='';
  218. $i=1;
  219. $carr=count($arr);
  220. foreach ($arr as $inarr) {
  221. $str.=$inarr[$key];
  222. if ($i<$carr)
  223. $str.=$glue;
  224. $i++;
  225. }
  226. return($str);
  227. }
  228. function notify($msg,$sev) {
  229. global $link;
  230. mysqli_query($link,'INSERT INTO Notifications (ID, Notification, Severity, Microtime) VALUES (NULL, \''.myesc($link,$msg).'\', '.$sev.', '.microtime().')')
  231. or mexit(mysqli_error($link).N,3,true);
  232. }
  233. /*
  234. * Nodeinfo ('https://'.$dom.'/nodeinfo/2.0') è stato aggiunto nella 3.0.0
  235. * Trends ('https://'.$dom.'/api/v1/trends') è stato aggiunto nella 3.0.0
  236. * Activity ('https://'.$dom.'/api/v1/instance/activity') è stato aggiunto nella 2.1.2
  237. */
  238. if ($opts['jsonwrite']) {
  239. $jsonf=@fopen(__DIR__.'/'.$opts['jsonfp'],'w')
  240. or mexit('Non ho potuto aprire in scrittura il file di dump delle info json «'.$opts['jsonfp'].'».',1);
  241. fwrite($jsonf,'{'.N);
  242. }
  243. $cinsts=count($insts);
  244. $i=0;
  245. $ok=0;
  246. foreach ($insts as $dom=>$row) {
  247. $i++;
  248. $info=null;
  249. lecho('~~~~~~~~~~~~~~~'.N);
  250. lecho('Provo a recuperare info su «'.$dom.'» ['.$i.'/'.$cinsts.' ('.$ok.' OK) - '.round(100/$cinsts*$i).'%]'.N);
  251. lecho('Provo a recuperare le informazioni API sull’istanza ... ');
  252. $buf=@file_get_contents('https://'.$dom.'/api/v1/instance',false,$context);
  253. if ($buf!==false) {
  254. $ok++;
  255. lecho('OK :-)'.N);
  256. $info=json_decode($buf,true);
  257. if (array_key_exists('version',$info)) {
  258. if ($info['version']>='2.1.2') {
  259. lecho('Provo a recuperare le informazioni API sull’attività dell’istanza ... ');
  260. $buf=@file_get_contents('https://'.$dom.'/api/v1/instance/activity',false,$context);
  261. if ($buf!==false) {
  262. lecho('OK :-)'.N);
  263. $info['x-activity']=json_decode($buf,true);
  264. } else {
  265. lecho('ERRORE :-('.N);
  266. }
  267. }
  268. if ($info['version']>='3.0.0') {
  269. lecho('Provo a recuperare le informazioni Nodeinfo sull’istanza ... ');
  270. $buf=@file_get_contents('https://'.$dom.'/nodeinfo/2.0',false,$context);
  271. if ($buf!==false) {
  272. lecho('OK :-)'.N);
  273. $info['x-nodeinfo']=json_decode($buf,true);
  274. } else {
  275. lecho('ERRORE :-('.N);
  276. }
  277. lecho('Provo a recuperare le informazioni API sui trends dell’istanza ... ');
  278. $buf=@file_get_contents('https://'.$dom.'/api/v1/trends',false,$context);
  279. if ($buf!==false) {
  280. lecho('OK :-)'.N);
  281. $info['x-trends']=json_decode($buf,true);
  282. } else {
  283. lecho('ERRORE :-('.N);
  284. }
  285. }
  286. }
  287. } else {
  288. lecho('ERRORE :-('.N);
  289. }
  290. if (!is_null($info) && akeavinn('uri',$info) && !is_null(nempty($info['uri']))) {
  291. lecho(json_encode($info,JSON_PRETTY_PRINT).N,true);
  292. if ($opts['jsonwrite'])
  293. fwrite($jsonf,'"'.$info['uri'].'": '.json_encode($info,JSON_PRETTY_PRINT).','.N);
  294. //INSERT INTO `Instances` (`ID`, `New`, `Chosen`, `Visible`, `BlackListed`, `URI`, `Title`, `ShortDesc`, `LongDesc`, `OurDesc`, `PlaceID`, `Email`, `Software`, `Version`, `UserCount`, `StatusCount`, `DomainCount`, `ActiveUsersMonth`, `ActiveUsersHalfYear`, `Thumb`, `RegOpen`, `RegReqApproval`, `MaxTootChars`, `AdmAccount`, `AdmDisplayName`, `AdmCreatedAt`, `AdmNote`, `AdmURL`, `AdmAvatar`, `AdmHeader`) VALUES (NULL, '1', '0', '0', '0', 'pantagruel.dnsup.net', 'Pantagruel', 'Descrizione breve', 'Descrizione lunga', 'Istanza molto carina senza soffitto, senza cucina', '1', 'Graume <graume@inventati.org>', 'mastodon', '3.0.1', '2', '12', '345', '5', '10', 'http://www.iedm.it', '1', '0', '540', 'admin', 'Admin', '2019-12-11', 'Note \'admin\'', 'https://rame.altervista.org', 'http://www.iedm.it', 'http://www.iedm.it');
  295. $instrow=array('ID'=>null, 'New'=>0, 'Chosen'=>0, 'Visible'=>0, 'BlackListed'=>0, 'URI'=>null, 'Title'=>null, 'ShortDesc'=>null, 'LongDesc'=>null, 'OurDesc'=>null, 'PlaceID'=>null, 'Email'=>null, 'Software'=>null, 'Version'=>null, 'UserCount'=>null, 'StatusCount'=>null, 'DomainCount'=>null, 'ActiveUsersMonth'=>null, 'ActiveUsersHalfYear'=>null, 'Thumb'=>null, 'RegOpen'=>null, 'RegReqApproval'=>null, 'MaxTootChars'=>null, 'AdmAccount'=>null, 'AdmDisplayName'=>null, 'AdmCreatedAt'=>null, 'AdmNote'=>null, 'AdmURL'=>null, 'AdmAvatar'=>null, 'AdmHeader'=>null);
  296. if (array_key_exists($info['uri'],$blacklist))
  297. $instrow['BlackListed']=1;
  298. $instrow['URI']=nempty($info['uri']);
  299. if (akeavinn('title',$info))
  300. $instrow['Title']=nempty($info['title']);
  301. if (akeavinn('short_description',$info))
  302. $instrow['ShortDesc']=nempty($info['short_description']);
  303. if (akeavinn('description',$info))
  304. $instrow['LongDesc']=nempty($info['description']);
  305. if (akeavinn('email',$info))
  306. $instrow['Email']=nempty($info['email']);
  307. if (akeavinn('version',$info))
  308. $instrow['Version']=nempty($info['version']);
  309. if (akeavinn('stats',$info)) {
  310. if (akeavinn('user_count',$info['stats']))
  311. $instrow['UserCount']=$info['stats']['user_count'];
  312. if (akeavinn('status_count',$info['stats']))
  313. $instrow['StatusCount']=$info['stats']['status_count'];
  314. if (akeavinn('domain_count',$info['stats']))
  315. $instrow['DomainCount']=$info['stats']['domain_count'];
  316. }
  317. if (akeavinn('thumbnail',$info))
  318. $instrow['Thumb']=nempty($info['thumbnail']);
  319. if (akeavinn('max_toot_chars',$info))
  320. $instrow['MaxTootChars']=$info['max_toot_chars'];
  321. if (akeavinn('registrations',$info))
  322. $instrow['RegOpen']=b2i($info['registrations']);
  323. if (akeavinn('approval_required',$info))
  324. $instrow['RegReqApproval']=b2i($info['approval_required']);
  325. if (akeavinn('contact_account',$info)) {
  326. if (akeavinn('acct',$info['contact_account']))
  327. $instrow['AdmAccount']=nempty($info['contact_account']['acct']);
  328. if (akeavinn('display_name',$info['contact_account']))
  329. $instrow['AdmDisplayName']=nempty($info['contact_account']['display_name']);
  330. if (akeavinn('created_at',$info['contact_account']))
  331. $instrow['AdmCreatedAt']=pgdatetomy($info['contact_account']['created_at']);
  332. if (akeavinn('note',$info['contact_account']))
  333. $instrow['AdmNote']=nempty(strip_tags($info['contact_account']['note'],'<a>'));
  334. if (akeavinn('url',$info['contact_account']))
  335. $instrow['AdmURL']=nempty($info['contact_account']['url']);
  336. if (akeavinn('avatar',$info['contact_account']))
  337. $instrow['AdmAvatar']=nempty($info['contact_account']['avatar']);
  338. if (akeavinn('header',$info['contact_account']))
  339. $instrow['AdmHeader']=nempty($info['contact_account']['header']);
  340. }
  341. if (akeavinn('x-nodeinfo',$info)) {
  342. if (akeavinn('software',$info['x-nodeinfo']) && akeavinn('name',$info['x-nodeinfo']['software']))
  343. $instrow['Software']=nempty($info['x-nodeinfo']['software']['name']);
  344. if (akeavinn('usage',$info['x-nodeinfo']) && akeavinn('users',$info['x-nodeinfo']['usage'])) {
  345. if (akeavinn('activeMonth',$info['x-nodeinfo']['usage']['users']))
  346. $instrow['ActiveUsersMonth']=$info['x-nodeinfo']['usage']['users']['activeMonth'];
  347. if (akeavinn('activeHalfyear',$info['x-nodeinfo']['usage']['users']))
  348. $instrow['ActiveUsersHalfYear']=$info['x-nodeinfo']['usage']['users']['activeHalfyear'];
  349. }
  350. }
  351. $res=mysqli_query($link,'SELECT * FROM Instances WHERE URI=\''.myesc($link,$instrow['URI']).'\'')
  352. or mexit(mysqli_error($link).N,3,true);
  353. if (mysqli_num_rows($res)>0) {
  354. lecho('«'.$instrow['URI'].'» è già presente nel DB, la aggiorno...'.N);
  355. $oldinstrow=mysqli_fetch_assoc($res);
  356. $query='UPDATE Instances SET ';
  357. foreach ($instrow as $field=>$value) {
  358. if (!is_null($value))
  359. $query.=$field.'=\''.myesc($link,$value).'\', ';
  360. else
  361. $query.=$field.'=\'NULL\', ';
  362. }
  363. $query=substr($query,0,-2).' WHERE Instances.ID='.$oldinstrow['ID'];
  364. echo('QUERONA DI UPDATE: «'.$query.'».'.N);
  365. /* $res=mysql_query($link,'SELECT InstID, LangID, Pos, Code FROM InstLangs LEFT JOIN Languages ON Languages.ID=LangID WHERE InstID='.$oldinstrow['ID'].' ORDER BY Pos ASC')
  366. or mexit(mysqli_error($link).N,3,true);
  367. $oldinstlangs=array();
  368. while ($row=mysql_fetch_assoc($res))
  369. $oldinstlangs[]=$row;
  370. if (akeavinn('languages',$info)) {
  371. $instlangs=array();
  372. $pos=0;
  373. foreach ($info['languages'] as $lang) {
  374. $res=mysqli_query($link,'SELECT * FROM Languages WHERE Code=\''.myesc($link,$lang).'\'')
  375. or mexit(mysqli_error($link).N,3,true);
  376. if (mysqli_num_rows($res)<1) {
  377. mysqli_query($link,'INSERT INTO Languages (ID, Code, Name) VALUES (NULL, \''.myesc($link,$lang).'\', NULL)')
  378. or mexit(mysqli_error($link).N,3,true);
  379. $langid=mysqli_insert_id($link);
  380. notify('L’aggiornamento dei dati relativi all’istanza «<a href="editinst.php?id='.$oldinstrow['ID'].'">'.$info['URI'].'</a>» ha aggiunto un codice lingua non ancora noto, «'.$lang.'», di cui non conosco il nome per esteso. Puoi <a href="editlang.php?id='.$langid.'">editarlo qui</a>.',1);
  381. } else {
  382. $row=mysqli_fetch_assoc($res);
  383. $langid=$row['ID'];
  384. }
  385. $pos++;
  386. $instlangs[]=array('InstID'=>$oldinstrow['ID'],'LangID'=>$langid,'Pos'=>$pos,'Code'=>$lang);
  387. }
  388. print_r($instlangs);
  389. print_r($oldinstlangs);
  390. if ($instlangs!=$oldinstlangs) {
  391. notify('La lista delle lingue utilizzate dichiarate dall’istanza «<a href="editinst.php?id='.$oldinstrow['ID'].'">'.$info['URI'].'</a>» è cambiata da «'.subarim(', ','Code',$oldinstlangs).'» a «'.subarim(', ','Code',$oldinstlangs).'».',1);
  392. mysqli_query($link,'DELETE FROM InstLangs WHERE InstID='.$oldinstrow['ID'])
  393. or mexit(mysqli_error($link).N,3,true);
  394. foreach ($instlangs as $row) {
  395. mysqli_query($link,'INSERT INTO InstLangs (InstID, LangID, Pos) VALUES ('.$row['InstID'].', '.$row['LangID'].', '.$row['Pos'].')')
  396. or mexit(mysqli_error($link).N,3,true);
  397. }
  398. }
  399. }*/
  400. } else {
  401. lecho('«'.$info['uri'].'» non è già presente nel DB, la aggiungo...'.N);
  402. $instrow['New']=1;
  403. $fields=array();
  404. $values='';
  405. foreach ($instrow as $field=>$value) {
  406. $fields[]=$field;
  407. if (!is_null($value))
  408. $values.='\''.myesc($link,$value).'\', ';
  409. else
  410. $values.='NULL, ';
  411. }
  412. $values=substr($values,0,-2);
  413. $query='INSERT INTO Instances ('.implode(', ',$fields).') VALUES ('.$values.')';
  414. echo('QUERONA DI INSERT: «'.$query.'»'.N);
  415. }
  416. // var_dump($instrow);
  417. }
  418. }
  419. mysqli_close($link);
  420. if ($opts['jsonwrite']) {
  421. fwrite($jsonf,'"Fine?": true'.N.'}'.N);
  422. fclose($jsonf);
  423. }
  424. if ($opts['log'])
  425. fclose($logf);
  426. exit(0);
  427. ?>