public static function cpu_model()
 {
     // Returns the processor name / frequency information
     $info = null;
     if (isset(phodevi::$vfs->cpuinfo)) {
         $physical_cpu_ids = phodevi_linux_parser::read_cpuinfo('physical id');
         $physical_cpu_count = count(array_unique($physical_cpu_ids));
         $cpu_strings = phodevi_linux_parser::read_cpuinfo(array('model name', 'Processor', 'cpu', 'cpu model'));
         $cpu_strings_unique = array_unique($cpu_strings);
         if ($physical_cpu_count == 1 || empty($physical_cpu_count)) {
             // Just one processor
             if (isset($cpu_strings[0]) && ($cut = strpos($cpu_strings[0], ' (')) !== false) {
                 $cpu_strings[0] = substr($cpu_strings[0], 0, $cut);
             }
             $info = isset($cpu_strings[0]) ? $cpu_strings[0] : null;
             if (strpos($info, 'ARM') !== false) {
                 if (is_dir('/sys/devices/system/exynos-core/') && stripos($info, 'Exynos') === false) {
                     $info = 'Exynos ' . $info;
                 }
             }
         } else {
             if ($physical_cpu_count > 1 && count($cpu_strings_unique) == 1) {
                 // Multiple processors, same model
                 $info = $physical_cpu_count . ' x ' . $cpu_strings[0];
             } else {
                 if ($physical_cpu_count > 1 && count($cpu_strings_unique) > 1) {
                     // Multiple processors, different models
                     $current_id = -1;
                     $current_string = $cpu_strings[0];
                     $current_count = 0;
                     $cpus = array();
                     for ($i = 0; $i < count($physical_cpu_ids); $i++) {
                         if ($current_string != $cpu_strings[$i] || $i == count($physical_cpu_ids) - 1) {
                             array_push($cpus, $current_count . ' x ' . $current_string);
                             $current_string = $cpu_strings[$i];
                             $current_count = 0;
                         }
                         if ($physical_cpu_ids[$i] != $current_id) {
                             $current_count++;
                             $current_id = $physical_cpu_ids[$i];
                         }
                     }
                     $info = implode(', ', $cpus);
                 }
             }
         }
     } else {
         if (phodevi::is_solaris()) {
             $dmi_cpu = phodevi_solaris_parser::read_sun_ddu_dmi_info('CPUType', '-C');
             if (count($dmi_cpu) == 0) {
                 $dmi_cpu = phodevi_solaris_parser::read_sun_ddu_dmi_info('ProcessorName');
             }
             if (count($dmi_cpu) > 0) {
                 $info = $dmi_cpu[0];
             } else {
                 $info = trim(shell_exec('dmesg 2>&1 | grep cpu0'));
                 $info = trim(substr($info, strrpos($info, 'cpu0:') + 6));
                 if (empty($info)) {
                     $info = array_pop(phodevi_solaris_parser::read_sun_ddu_dmi_info('ProcessorManufacturer'));
                 }
             }
             //TODO: Add in proper support for reading multiple CPUs, similar to the code from above
             $physical_cpu_count = count(phodevi_solaris_parser::read_sun_ddu_dmi_info('ProcessorSocketType'));
             if ($physical_cpu_count > 1 && !empty($info)) {
                 // TODO: For now assuming when multiple CPUs are installed, that they are of the same type
                 $info = $physical_cpu_count . ' x ' . $info;
             }
         } else {
             if (phodevi::is_bsd()) {
                 $info = phodevi_bsd_parser::read_sysctl('hw.model');
             } else {
                 if (phodevi::is_macosx()) {
                     $info = phodevi_osx_parser::read_osx_system_profiler('SPHardwareDataType', 'ProcessorName');
                 } else {
                     if (phodevi::is_windows()) {
                         $info = phodevi_windows_parser::read_cpuz('Processor 1', 'Name');
                         if (!$info) {
                             $info = getenv('PROCESSOR_IDENTIFIER');
                         }
                     }
                 }
             }
         }
     }
     if (empty($info)) {
         $info = 'Unknown';
     } else {
         if (($strip_point = strpos($info, '@')) > 0) {
             $info = trim(substr($info, 0, $strip_point));
             // stripping out the reported freq, since the CPU could be overclocked, etc
         }
         $info = pts_strings::strip_string($info);
         // It seems Intel doesn't report its name when reporting Pentium hardware
         if (strpos($info, 'Pentium') !== false && strpos($info, 'Intel') === false) {
             $info = 'Intel ' . $info;
         }
         if (substr($info, 0, 5) == 'Intel') {
             $cpu_words = explode(' ', $info);
             $cpu_words_count = count($cpu_words);
             // Convert strings like 'Intel Core i7 M 620' -> 'Intel Core i7 620M' and 'Intel Core i7 X 990' -> 'Intel Core i7 990X' to better reflect Intel product marketing names
             if ($cpu_words_count > 4 && is_numeric($cpu_words[$cpu_words_count - 1]) && strlen($cpu_words[$cpu_words_count - 2]) == 1 && strlen($cpu_words[$cpu_words_count - 3]) == 2) {
                 $cpu_words[$cpu_words_count - 1] .= $cpu_words[$cpu_words_count - 2];
                 unset($cpu_words[$cpu_words_count - 2]);
                 $info = implode(' ', $cpu_words);
             }
         }
     }
     return $info;
 }
 public static function motherboard_string()
 {
     // Returns the motherboard / system model name or number
     $info = null;
     if (phodevi::is_macosx()) {
         $info = phodevi_osx_parser::read_osx_system_profiler('SPHardwareDataType', 'ModelName');
     } else {
         if (phodevi::is_solaris()) {
             $manufacturer = phodevi_solaris_parser::read_sun_ddu_dmi_info(array('MotherBoardInformation,Manufacturer', 'SystemInformation,Manufacturer'));
             $product = phodevi_solaris_parser::read_sun_ddu_dmi_info(array('MotherBoardInformation,Product', 'SystemInformation,Product', 'SystemInformation,Model'));
             if (count($manufacturer) == 1 && count($product) == 1) {
                 $info = $manufacturer[0] . ' ' . $product[0];
             }
         } else {
             if (phodevi::is_bsd()) {
                 $vendor = phodevi_bsd_parser::read_kenv('smbios.system.maker');
                 $product = phodevi_bsd_parser::read_kenv('smbios.system.product');
                 $version = phodevi_bsd_parser::read_kenv('smbios.system.version');
                 // for at least Lenovo ThinkPads this is where it displays ThinkPad model
                 if ($vendor != null && ($product != null || $version != null)) {
                     $info = $vendor . ' ' . $product . ' ' . $version;
                 } else {
                     if (($vendor = phodevi_bsd_parser::read_sysctl('hw.vendor')) != false && ($version = phodevi_bsd_parser::read_sysctl(array('hw.version', 'hw.product'))) != false) {
                         $info = trim($vendor . ' ' . $version);
                     } else {
                         if (($acpi = phodevi_bsd_parser::read_sysctl('dev.acpi.0.%desc')) != false) {
                             $info = trim($acpi);
                         }
                     }
                 }
             } else {
                 if (phodevi::is_linux()) {
                     $vendor = phodevi_linux_parser::read_sys_dmi(array('board_vendor', 'sys_vendor'));
                     $name = phodevi_linux_parser::read_sys_dmi(array('board_name', 'product_name'));
                     $version = phodevi_linux_parser::read_sys_dmi(array('board_version', 'product_version'));
                     if ($vendor != false && $name != false) {
                         $info = strpos($name . ' ', $vendor . ' ') === false ? $vendor . ' ' : null;
                         $info .= $name;
                         if ($version != false && strpos($info, $version) === false && pts_strings::string_only_contains($version, pts_strings::CHAR_NUMERIC | pts_strings::CHAR_DECIMAL)) {
                             $info .= (substr($version, 0, 1) == 'v' ? ' ' : ' v') . $version;
                         }
                     }
                     if (empty($info)) {
                         if ($info == null) {
                             $hw_string = phodevi_linux_parser::read_cpuinfo('Hardware');
                             if (count($hw_string) == 1) {
                                 $info = $hw_string[0];
                             }
                         }
                         $bios_vendor = phodevi_linux_parser::read_sys_dmi('bios_vendor');
                         $bios_version = phodevi_linux_parser::read_sys_dmi('bios_version');
                         if ($bios_vendor != null) {
                             $info = $bios_vendor . ' ' . $bios_version;
                         }
                         if ($info == null) {
                             $hw_string = phodevi_linux_parser::read_cpuinfo('machine');
                             if (count($hw_string) == 1) {
                                 $info = $hw_string[0];
                             }
                         }
                     }
                     if (empty($info)) {
                         $info = phodevi_linux_parser::read_sys_dmi('product_name');
                     }
                     if (empty($info) && is_file('/sys/bus/soc/devices/soc0/machine')) {
                         $info = pts_file_io::file_get_contents('/sys/bus/soc/devices/soc0/machine');
                     }
                     if (empty($info)) {
                         // Works on the MIPS Creator CI20
                         $hardware = phodevi_linux_parser::read_cpuinfo('Hardware');
                         if (!empty($hardware)) {
                             $info = array_pop($hardware);
                         }
                     }
                 } else {
                     if (phodevi::is_windows()) {
                         $info = phodevi_windows_parser::read_cpuz('Mainboard Model', null);
                     }
                 }
             }
         }
     }
     if ((strpos($info, 'Mac ') !== false || strpos($info, 'MacBook') !== false) && strpos($info, 'Apple') === false) {
         $info = 'Apple ' . $info;
     }
     // ensure words aren't repeated (e.g. VMware VMware Virtual and MSI MSI X58M (MS-7593))
     $info = implode(' ', array_unique(explode(' ', $info)));
     return $info;
 }
 private static function sys_battery_power()
 {
     // Returns power consumption rate in mW
     $rate = -1;
     if (phodevi::is_linux()) {
         $power_now = phodevi_linux_parser::read_sysfs_node('/sys/class/power_supply/*/power_now', 'POSITIVE_NUMERIC', array('status' => 'Discharging'));
         if ($power_now != -1) {
             // sysfs power_now seems to be displayed in microWatts
             $rate = pts_math::set_precision($power_now / 1000, 2);
         }
         if ($rate == -1) {
             $battery = array('/battery/BAT0/state', '/battery/BAT1/state');
             $state = phodevi_linux_parser::read_acpi($battery, 'charging state');
             $power = phodevi_linux_parser::read_acpi($battery, 'present rate');
             $voltage = phodevi_linux_parser::read_acpi($battery, 'present voltage');
             if ($state == 'discharging') {
                 $power_unit = substr($power, strrpos($power, ' ') + 1);
                 $power = substr($power, 0, strpos($power, ' '));
                 if ($power_unit == 'mA') {
                     $voltage_unit = substr($voltage, strrpos($voltage, ' ') + 1);
                     $voltage = substr($voltage, 0, strpos($voltage, ' '));
                     if ($voltage_unit == 'mV') {
                         $rate = round($power * $voltage / 1000);
                     }
                 } else {
                     if ($power_unit == 'mW') {
                         $rate = $power;
                     }
                 }
             }
         }
         if ($rate == -1 && is_file('/sys/class/power_supply/BAT0/voltage_now') && is_file('/sys/class/power_supply/BAT0/current_now')) {
             $voltage_now = pts_file_io::file_get_contents('/sys/class/power_supply/BAT0/voltage_now') / 1000;
             $current_now = pts_file_io::file_get_contents('/sys/class/power_supply/BAT0/current_now') / 1000;
             $power_now = $voltage_now * $current_now / 1000;
             if ($power_now > 1) {
                 $rate = $power_now;
             }
         }
         if ($rate == -1 && is_file('/sys/class/power_supply/BAT1/voltage_now') && is_file('/sys/class/power_supply/BAT1/current_now')) {
             $voltage_now = pts_file_io::file_get_contents('/sys/class/power_supply/BAT1/voltage_now') / 1000;
             $current_now = pts_file_io::file_get_contents('/sys/class/power_supply/BAT1/current_now') / 1000;
             $power_now = $voltage_now * $current_now / 1000;
             if ($power_now > 1) {
                 $rate = $power_now;
             }
         }
     } else {
         if (phodevi::is_macosx()) {
             $amperage = abs(phodevi_osx_parser::read_osx_system_profiler('SPPowerDataType', 'Amperage'));
             // in mA
             $voltage = phodevi_osx_parser::read_osx_system_profiler('SPPowerDataType', 'Voltage');
             // in mV
             if ($amperage > 0 && $voltage > 0) {
                 $rate = round($amperage * $voltage / 1000);
             } else {
                 if (pts_client::executable_in_path('ioreg')) {
                     $ioreg = trim(shell_exec("ioreg -l | grep LegacyBatteryInfo | cut -d '{' -f 2 | tr -d \\} | tr ',' '=' | awk -F'=' '{print (\$2*\$10/10^22)}' 2>&1"));
                     if (is_numeric($ioreg) && $ioreg > 0) {
                         $rate = $ioreg;
                     }
                 }
             }
         } else {
             if (phodevi::is_solaris()) {
                 $battery = phodevi_solaris_parser::read_hal_property('/org/freedesktop/Hal/devices/pseudo/acpi_drv_0_battery0_0', 'battery.reporting.rate');
                 if (is_numeric($battery)) {
                     $rate = $battery;
                 }
             } else {
                 if (phodevi::is_bsd()) {
                     $battery = phodevi_bsd_parser::read_acpiconf('Present rate');
                     if ($battery && substr($battery, -2) == 'mW') {
                         $rate = substr($battery, 0, strpos($battery, ' '));
                     }
                 }
             }
         }
     }
     return $rate;
 }
 public static function chipset_string()
 {
     $info = false;
     if (phodevi::is_macosx()) {
         $sb_vendor = phodevi_osx_parser::read_osx_system_profiler('SPSerialATADataType', 'Vendor');
         $sb_product = phodevi_osx_parser::read_osx_system_profiler('SPSerialATADataType', 'Product');
         if ($sb_product == 'SSD') {
             $sb_product = null;
         }
         if (($cut_point = strpos($sb_product, ' ')) > 0) {
             $sb_product = substr($sb_product, 0, $cut_point);
         }
         // TODO: Can't find Northbridge
         $info = $sb_vendor . ' ' . $sb_product;
     } else {
         if (phodevi::is_windows()) {
             $info = phodevi_windows_parser::read_cpuz('Northbridge', null);
             if ($info != null) {
                 if (($e = strpos($info, 'rev')) !== false) {
                     $info = substr($info, 0, $e);
                 }
                 $info = trim($info);
             }
         } else {
             if (phodevi::is_solaris()) {
                 // Vendor Detection
                 $vendor_possible_udis = array('/org/freedesktop/Hal/devices/pci_0_0/pci_ide_3_2_0', '/org/freedesktop/Hal/devices/pci_0_0/pci_ide_1f_1_1');
                 $info = phodevi_solaris_parser::read_hal_property($vendor_possible_udis, 'info.vendor');
                 // TODO: Northbridge and Southbridge Detection For Solaris
             } else {
                 if (phodevi::is_linux() || phodevi::is_hurd()) {
                     $info = phodevi_linux_parser::read_pci(array('RAM memory', 'Host bridge'));
                     if (count(explode(' ', $info)) == 1) {
                         $bridge = phodevi_linux_parser::read_pci(array('Bridge', 'PCI bridge'));
                         if (!empty($bridge)) {
                             $match = false;
                             $break_words = array('Ethernet', 'PCI', 'High', 'USB');
                             for ($i = 0; $i < count($break_words) && !$match; $i++) {
                                 if (($pos = strpos($bridge, $break_words[$i])) > 0) {
                                     $bridge = trim(substr($bridge, 0, $pos));
                                     $info = $bridge;
                                     $match = true;
                                 }
                             }
                         }
                     }
                     if (!isset($bridge) || !empty($bridge)) {
                         // Attempt to detect Southbridge (if applicable)
                         $southbridge = phodevi_linux_parser::read_pci(array('ISA bridge', 'SATA controller'), false);
                         $southbridge_clean = null;
                         if (($start_cut = strpos($southbridge, '(')) > 0 && ($end_cut = strpos($southbridge, ')', $start_cut + 1)) > 0) {
                             $southbridge_extract = substr($southbridge, $start_cut + 1, $end_cut - $start_cut - 1);
                             if (strpos($southbridge_extract, 'rev') === false) {
                                 $southbridge_extract = explode(' ', $southbridge_extract);
                                 $southbridge_clean = $southbridge_extract[0];
                             } else {
                                 if (($s = strpos($southbridge, 'ICH')) > 0) {
                                     $southbridge_extract = substr($southbridge, $s);
                                     $southbridge_clean = substr($southbridge_extract, 0, strpos($southbridge_extract, ' '));
                                 }
                             }
                         } else {
                             if (($start_cut = strpos($southbridge, 'SB')) !== false) {
                                 $southbridge_extract = substr($southbridge, $start_cut);
                                 $southbridge_clean = substr($southbridge_extract, 0, strpos($southbridge_extract, ' '));
                             }
                         }
                         if (!empty($southbridge_clean) && $southbridge_clean != 'SB') {
                             $info .= ' + ' . $southbridge_clean;
                         }
                     }
                 }
             }
         }
     }
     return $info;
 }
 public static function memory_string()
 {
     $mem_string = null;
     $mem_prefix = null;
     $mem_size = false;
     $mem_speed = false;
     $mem_type = false;
     $mem_manufacturer = false;
     $mem_part = false;
     if (phodevi::is_macosx()) {
         $mem_size = phodevi_osx_parser::read_osx_system_profiler('SPMemoryDataType', 'Size', true, array('Empty'));
         $mem_speed = phodevi_osx_parser::read_osx_system_profiler('SPMemoryDataType', 'Speed');
         $mem_type = phodevi_osx_parser::read_osx_system_profiler('SPMemoryDataType', 'Type');
     } else {
         if (phodevi::is_solaris()) {
             $mem_size = phodevi_solaris_parser::read_sun_ddu_dmi_info('MemoryDevice*,InstalledSize');
             $mem_speed = phodevi_solaris_parser::read_sun_ddu_dmi_info('MemoryDevice*,Speed');
             $mem_type = phodevi_solaris_parser::read_sun_ddu_dmi_info('MemoryDevice*,MemoryDeviceType');
             if (is_array($mem_speed) && count($mem_speed) > 0) {
                 $mem_speed = array_shift($mem_speed);
             }
             $mem_speed = str_replace('MHZ', 'MHz', $mem_speed);
         } else {
             if (phodevi::is_windows()) {
                 $mem_size = phodevi_windows_parser::read_cpuz('DIMM #', 'Size', true);
                 foreach ($mem_size as $key => &$individual_size) {
                     $individual_size = pts_arrays::first_element(explode(' ', $individual_size));
                     if (!is_numeric($individual_size)) {
                         unset($mem_size[$key]);
                     }
                 }
                 $mem_type = phodevi_windows_parser::read_cpuz('Memory Type', null);
                 $mem_speed = intval(phodevi_windows_parser::read_cpuz('Memory Frequency', null)) . 'MHz';
             } else {
                 if (phodevi::is_linux()) {
                     $mem_size = phodevi_linux_parser::read_dmidecode('memory', 'Memory Device', 'Size', false, array('Not Installed', 'No Module Installed', 'Undefined'));
                     $mem_speed = phodevi_linux_parser::read_dmidecode('memory', 'Memory Device', 'Speed', true, array('Unknown', 'Undefined'));
                     $mem_type = phodevi_linux_parser::read_dmidecode('memory', 'Memory Device', 'Type', true, array('Unknown', 'Other', 'Flash', 'Undefined'));
                     $mem_manufacturer = phodevi_linux_parser::read_dmidecode('memory', 'Memory Device', 'Manufacturer', true, array('Unknown', 'Undefined'));
                     $mem_part = phodevi_linux_parser::read_dmidecode('memory', 'Memory Device', 'Part Number', true, array('Unknown', 'Undefined'));
                 }
             }
         }
     }
     if (is_array($mem_type)) {
         $mem_type = array_pop($mem_type);
     }
     if ($mem_size != false && (!is_array($mem_size) || count($mem_size) != 0)) {
         for ($i = 0; $i < count($mem_size); $i++) {
             switch (substr($mem_size[$i], -1)) {
                 case 'K':
                     // looks like sometimes Solaris now reports flash chip as memory. its string ends with K
                     unset($mem_size[$i]);
                     unset($mem_speed[$i]);
                     unset($mem_type[$i]);
                     break;
                 case 'M':
                     // report megabytes as MB, just not M, as on Solaris
                     $mem_size[$i] .= 'B';
                     break;
                 case 'B':
                     if (strtolower(substr($mem_size[$i], -2, 1)) == 'k') {
                         // some hardware on Linux via dmidecode reports flash chips
                         unset($mem_size[$i]);
                         //unset($mem_speed[$i]);
                         //unset($mem_type[$i]);
                     }
                     break;
             }
         }
         foreach ($mem_size as $i => $mem_stick) {
             if (!is_numeric(substr($mem_stick, 0, 3)) && stripos($mem_stick, 'GB') == false) {
                 // If the memory size isn't at least three digits (basically 128MB+), chances are something is wrong, i.e. reporting flash chip from dmidecode, so get rid of it.
                 unset($mem_size[$i]);
             }
         }
         $mem_count = count($mem_size);
         if (!empty($mem_type)) {
             if (($cut = strpos($mem_type, ' ')) > 0) {
                 $mem_type = substr($mem_type, 0, $cut);
             }
             if (!in_array($mem_type, array('Other')) && (pts_strings::keep_in_string($mem_type, pts_strings::CHAR_NUMERIC | pts_strings::CHAR_LETTER) == $mem_type || phodevi::is_windows())) {
                 $mem_prefix = $mem_type;
             }
         } else {
             $mem_prefix = null;
         }
         if (!empty($mem_speed)) {
             if (($cut = strpos($mem_speed, ' (')) > 0) {
                 $mem_speed = substr($mem_speed, 0, $cut);
             }
             if (!empty($mem_prefix)) {
                 $mem_prefix .= '-';
             }
             $mem_prefix .= str_replace(' ', null, $mem_speed);
         }
         // TODO: Allow a combination of both functions below, so like 2 x 2GB + 3 x 1GB DDR2-800
         if ($mem_count > 1 && count(array_unique($mem_size)) > 1) {
             $mem_string = implode(' + ', $mem_size) . ' ' . $mem_prefix;
         } else {
             if ($mem_count * $mem_size[0] != phodevi::read_property('memory', 'capacity') && phodevi::read_property('memory', 'capacity') % $mem_size[0] == 0) {
                 // This makes sure the correct number of RAM modules is reported...
                 // On at least Linux with dmidecode on an AMD Opteron multi-socket setup it's only showing the data for one socket
                 if ($mem_size[0] < 1024) {
                     $mem_size[0] *= 1024;
                 }
                 $mem_count = phodevi::read_property('memory', 'capacity') / $mem_size[0];
             }
             $product_string = null;
             if (isset($mem_manufacturer[2]) && ctype_alpha($mem_manufacturer[0]) && stripos($mem_manufacturer, 'manufacturer') === false && stripos($mem_manufacturer, 'part') === false && stripos($mem_manufacturer, 'module') === false && stripos($mem_manufacturer, 'dimm') === false && isset($mem_manufacturer[2]) && ctype_alpha($mem_manufacturer)) {
                 $product_string .= ' ' . $mem_manufacturer;
             }
             if (isset($mem_part[2]) && stripos($mem_part, 'part') === false && stripos($mem_part, 'module') === false && stripos($mem_part, 'dimm') === false && substr($mem_part, 0, 2) != '0x' && !isset($mem_part[24]) && ctype_alnum($mem_part)) {
                 $product_string .= ' ' . $mem_part;
             }
             if (is_numeric($mem_size[0]) && stripos($mem_size[0], 'b') === false) {
                 if ($mem_size >= 1024) {
                     $mem_size[0] .= ' MB';
                 } else {
                     $mem_size[0] .= ' GB';
                 }
             }
             $mem_string = $mem_count . ' x ' . $mem_size[0] . ' ' . $mem_prefix . $product_string;
         }
     }
     if (empty($mem_string)) {
         $mem_string = phodevi::read_property('memory', 'capacity');
         if ($mem_string != null) {
             $mem_string .= 'MB';
         }
     }
     return trim($mem_string);
 }