'UNKNOWN_ARCH'); } if(!($ring == 'DEV' || $ring == 'BETA' || $ring == 'RELEASEPREVIEW' || $ring == 'WIF' || $ring == 'WIS' || $ring == 'RP' || $ring == 'RETAIL' || $ring == 'MSIT')) { return array('error' => 'UNKNOWN_RING'); } if(!($flight == 'Mainline' || $flight == 'Active' || $flight == 'Skip')) { return array('error' => 'UNKNOWN_FLIGHT'); } if($flight == 'Skip' && $ring != 'WIF') { return array('error' => 'UNKNOWN_COMBINATION'); } if($build < 9841 || $build > PHP_INT_MAX-1) { return array('error' => 'ILLEGAL_BUILD'); } if($minor < 0 || $minor > PHP_INT_MAX-1) { return array('error' => 'ILLEGAL_MINOR'); } if($ring == 'DEV') $ring = 'WIF'; if($ring == 'BETA') $ring = 'WIS'; if($ring == 'RELEASEPREVIEW') $ring = 'RP'; if($flight == 'Active' && $ring == 'RP') $flight = 'Current'; $build = '10.0.'.$build.'.'.$minor; $type = ucwords(strtolower($type)); if(!($type == 'Production' || $type == 'Test')) { $type = 'Production'; } $cacheHash = hash('sha256', strtolower("api-fetch-$arch-$ring-$flight-$build-$minor-$sku-$type")); $cached = 0; if(file_exists('cache/'.$cacheHash.'.json.gz') && $cacheRequests == 1) { $cache = @gzdecode(@file_get_contents('cache/'.$cacheHash.'.json.gz')); $cache = json_decode($cache, 1); if(!empty($cache['content']) && ($cache['expires'] > time())) { consoleLogger('Using cached response...'); $out = $cache['content']; $cached = 1; } else { $cached = 0; } unset($cache); } if(!$cached) { consoleLogger('Fetching information from the server...'); $postData = composeFetchUpdRequest(uupDevice(), uupEncryptedData(), $arch, $flight, $ring, $build, $sku, $type); $out = sendWuPostRequest('https://fe3cr.delivery.mp.microsoft.com/ClientWebService/client.asmx', $postData); $out = html_entity_decode($out); consoleLogger('Information has been successfully fetched.'); if($cacheRequests == 1) { $cache = array( 'expires' => time()+120, 'content' => $out, ); if(!file_exists('cache')) mkdir('cache'); @file_put_contents('cache/'.$cacheHash.'.json.gz', gzencode(json_encode($cache)."\n")); unset($cache); } } preg_match_all('/.*?<\/UpdateInfo>/', $out, $updateInfos); $updateInfo = preg_grep('/true<\/IsLeaf>/', $updateInfos[0]); sort($updateInfo); if(empty($updateInfo)) { consoleLogger('An error has occurred'); return array('error' => 'NO_UPDATE_FOUND'); } $errorCount = 0; $updatesNum = count($updateInfo); $num = 0; $updateArray = array(); foreach($updateInfo as $val) { $num++; consoleLogger("Checking build information for update {$num} of {$updatesNum}..."); $info = parseFetchUpdate($val, $out, $arch, $ring, $flight, $build, $sku, $type); if(isset($info['error'])) { $errorCount++; continue; } $updateArray[] = $info; } if($errorCount == $updatesNum) { return array('error' => 'EMPTY_FILELIST'); } return array( 'apiVersion' => uupApiVersion(), 'updateId' => $updateArray[0]['updateId'], 'updateTitle' => $updateArray[0]['updateTitle'], 'foundBuild' => $updateArray[0]['foundBuild'], 'arch' => $updateArray[0]['arch'], 'fileWrite' => $updateArray[0]['fileWrite'], 'updateArray' => $updateArray, ); } function parseFetchUpdate($updateInfo, $out, $arch, $ring, $flight, $build, $sku, $type) { $updateNumId = preg_replace('/|<\/ID>.*/i', '', $updateInfo); $updates = preg_replace('//', "\n", $out); preg_match_all('/.*<\/Update>/', $updates, $updates); $updateMeta = preg_grep('/'.$updateNumId.'<\/ID>/', $updates[0]); sort($updateMeta); $updateFiles = preg_grep('/.*<\/Files>/', $updateMeta); sort($updateFiles); if(!isset($updateFiles[0])) { consoleLogger('An error has occurred'); return array('error' => 'EMPTY_FILELIST'); } preg_match('/.*<\/Files>/', $updateFiles[0], $fileList); if(!isset($fileList[0]) || empty($fileList[0])) { consoleLogger('An error has occurred'); return array('error' => 'EMPTY_FILELIST'); } preg_match('/ProductReleaseInstalled Name\="(.*?)\..*\.(.*?)" Version\="10\.0\.(.*?)"/', $updateInfo, $info); $foundType = @strtolower($info[1]); $foundArch = @strtolower($info[2]); $foundBuild = @$info[3]; if(!isset($foundArch) || empty($foundArch)) { preg_match('/ProductReleaseInstalled Name\="(.*?)\.(.*?)" Version\="10\.0\.(.*?)"/', $updateInfo, $info); $foundType = @strtolower($info[1]); $foundArch = @strtolower($info[2]); $foundBuild = @$info[3]; } $updateTitle = preg_grep('/.*<\/Title>/', $updateMeta); sort($updateTitle); preg_match('/<Title>.*?<\/Title>/i', $updateTitle[0], $updateTitle); $updateTitle = preg_replace('/<Title>|<\/Title>/i', '', $updateTitle); sort($updateTitle); if(isset($updateTitle[0])) { $updateTitle = $updateTitle[0]; } else { $updateTitle = 'Windows 10 build '.$foundBuild; } if($foundType == 'hololens' || $foundType == 'wcosdevice0') $updateTitle = preg_replace('/ for .{3,5}-based/i', ' for', $updateTitle); $isCumulativeUpdate = 0; if(preg_match('/\d{4}-\d{2}.+Update|Cumulative Update|Microsoft Edge|Windows Feature Experience Pack/i', $updateTitle)) { $isCumulativeUpdate = 1; $updateTitle = preg_replace('/ for .{3,5}-based systems| \(KB.*?\)/i', '', $updateTitle); } $updateTitle = preg_replace("/ ?\d{4}-\d{2}\D ?| ?$foundArch ?| ?x64 ?/i", '', $updateTitle); if($foundType == 'server') $updateTitle = str_replace('Windows 10', 'Windows Server', $updateTitle); if($sku == 406) $updateTitle = str_replace('Microsoft server operating system', 'Azure Stack HCI', $updateTitle); if($foundType == 'sedimentpack') $updateTitle = $updateTitle.' - KB4023057'; if($foundType == 'hololens' || $foundType == 'wcosdevice0') $updateTitle = $updateTitle.' - '.$type; if(!preg_match("/$foundBuild/i", $updateTitle)) $updateTitle = $updateTitle.' ('.$foundBuild.')'; preg_match('/UpdateID=".*?"/', $updateInfo, $updateId); preg_match('/RevisionNumber=".*?"/', $updateInfo, $updateRev); $updateId = preg_replace('/UpdateID="|"$/', '', $updateId[0]); $updateRev = preg_replace('/RevisionNumber="|"$/', '', $updateRev[0]); consoleLogger('Successfully checked build information.'); $updateString = $updateId; if($updateRev != 1) { $updateString = $updateId.'_rev.'.$updateRev; } $ids = uupListIds(); if(!isset($ids['error'])) { $ids = $ids['builds']; $namesList = array(); foreach($ids as $val) { $testName = $val['build'].' '.$val['title'].' '.$val['arch']; if($val['uuid'] != $updateString) { $namesList[$val['uuid']] = $testName; } } $num = 1; $buildName = $foundBuild.' '.$updateTitle.' '.$foundArch; while(in_array($buildName, $namesList, true)) { $num++; $buildName = "$foundBuild $updateTitle ($num) $foundArch"; } if($num > 1) $updateTitle = "$updateTitle ($num)"; } consoleLogger("--- UPDATE INFORMATION ---"); consoleLogger("Title: ".$updateTitle); consoleLogger("Architecture: ".$foundArch); consoleLogger("Build number: ".$foundBuild); consoleLogger("Update ID: ".$updateString); consoleLogger("--- UPDATE INFORMATION ---"); if((!$foundBuild) && (!$foundArch)) { consoleLogger('No architecture nor build number specified! What the hell is this?'); return array('error' => 'BROKEN_UPDATE'); } if(preg_match('/Corpnet Required/i', $updateTitle)) { consoleLogger('Skipping corpnet only update...'); return array('error' => 'CORPNET_ONLY_UPDATE'); } $fileWrite = 'NO_SAVE'; if(!file_exists('fileinfo/'.$updateString.'.json')) { consoleLogger('WARNING: This build is NOT in the database. It will be saved now.'); consoleLogger('Parsing information to write...'); if(!file_exists('fileinfo')) mkdir('fileinfo'); $fileList = preg_replace('/<Files>|<\/Files>/', '', $fileList[0]); preg_match_all('/<File .*?>/', $fileList, $fileList); $shaArray = array(); foreach($fileList[0] as $val) { preg_match('/Digest=".*?"/', $val, $sha1); $sha1 = preg_replace('/Digest="|"$/', '', $sha1[0]); $sha1 = bin2hex(base64_decode($sha1)); preg_match('/FileName=".*?"/', $val, $name); $name = preg_replace('/FileName="|"$/', '', $name[0]); preg_match('/Size=".*?"/', $val, $size); $size = preg_replace('/Size="|"$/', '', $size[0]); $temp = array( 'name' => $name, 'size' => $size, ); $shaArray = array_merge($shaArray, array($sha1 => $temp)); } unset($temp, $sha1, $name, $size); ksort($shaArray); $temp = array(); $temp['title'] = $updateTitle; $temp['ring'] = $ring; $temp['flight'] = $flight; $temp['arch'] = $foundArch; $temp['build'] = $foundBuild; $temp['checkBuild'] = $build; $temp['sku'] = $sku; if($isCumulativeUpdate) { $temp['containsCU'] = 1; } if($foundType == 'hololens' || $foundType == 'wcosdevice0') { $temp['releasetype'] = $type; } $temp['created'] = time(); $temp['files'] = $shaArray; consoleLogger('Successfully parsed the information.'); consoleLogger('Writing new build information to the disk...'); $success = file_put_contents('fileinfo/'.$updateString.'.json', json_encode($temp)."\n"); if($success) { consoleLogger('Successfully written build information to the disk.'); $fileWrite = 'INFO_WRITTEN'; } else { consoleLogger('An error has occured while writing the information to the disk.'); } } else { consoleLogger('This build already exists in the database.'); } return array( 'updateId' => $updateString, 'updateTitle' => $updateTitle, 'foundBuild' => $foundBuild, 'arch' => $foundArch, 'fileWrite' => $fileWrite, ); }