public function loadFromBSMX($bsmxFile) { $fileStr = file_get_contents($bsmxFile); $fileStr = html_entity_decode(htmlspecialchars_decode($fileStr)); var_dump($fileStr); $beerXML = simplexml_load_string($fileStr, "SimpleXMLElement"); if (!$beerXML) { return false; } $matches = array(); // Matches: whole version string, revision number, yeast code, major version, minor version preg_match_all('/\\((\\d+)-([\\w|\\d|,]+)-(\\d+).(\\d+)\\)/', $bsmxFile, $matches); var_dump($matches); // Check to see if the matches are empty or not, if not we have an initial candidate for the versioning... if (count($matches) >= 5) { if (count($matches[1]) == 1) { $this->revisionNumber = intval($matches[1][0]); } if (count($matches[2]) == 1) { $this->yeastCode = $matches[2][0]; } if (count($matches[3]) == 1) { $this->majorVersionNumber = intval($matches[3][0]); } if (count($matches[4]) == 1) { $this->minorVersionNumber = intval($matches[4][0]); } } $data = $beerXML->Data->Recipe; var_dump($data); // Convert basic, top-level recipe data $this->beerName = (string) $data->F_R_NAME; $equipmentXML = $data->F_E_BATCH_VOL; $this->expectedEff = round(floatval((string) $equipmentXML->F_E_EFFICIENCY), 1); $this->expectedBatchVolL = fluidOzToL(floatval((string) $equipmentXML->F_E_BATCH_VOL)); $this->expectedPreboilVolL = fluidOzToL(floatval((string) $equipmentXML->F_E_BOIL_VOL)); $this->boilTimeMin = intval((string) $equipmentXML->F_E_BOIL_TIME); $this->whirlpoolTimeMin = 30; // default to 30 minutes $this->expectedOG = round(floatval((string) $data->F_R_DESIRED_OG), 3); $this->expectedIBUs = round(floatval((string) $data->F_R_DESIRED_IBU), 0); $styleXML = $data->F_R_STYLE; $this->beerStyleName = (string) $styleXML->F_S_NAME; // Convert the mash and sparge... $mashVolL = 0.0; $mashXML = $data->F_R_MASH; $stepsXML = $mashXML->steps; $numSteps = intval((string) $stepsXML->Size); if ($numSteps <= 0) { return false; } foreach ($stepsXML->Data->MashStep as $step) { array_push($this->mashSteps, array("name" => (string) $step->F_MS_NAME, "stepLengthMin" => intval((string) $step->F_MS_STEP_TIME), "riseTimeMin" => intval((string) $step->F_MS_RISE_TIME), "tempC" => degreesFtoC(floatval((string) $step->F_MS_STEP_TEMP)))); // Find the first infusion step - this will give us the mash volume $infusionVolL = floatval((string) $step->F_MS_INFUSION); if ($infusionVolL > 0 && $mashVolL == 0) { $mashVolL = fluidOzToL($infusionVolL); } } $this->spargeTempC = degreesFtoC(floatval((string) $mashXML->F_MH_SPARGE_TEMP)); if (intval((string) $mashXML->F_MH_BATCH) > 0) { $this->spargeType = "Batch Sparge"; } else { $this->flySpargeType = "Fly Sparge"; } if (intval((string) $mashXML->F_MH_BATCH_DRAIN) > 0) { $this->spargeNotes = "Drain the mash tun first, then batch sparge with initial sparge volume of " . round(floatval((string) $mashXML->F_MH_BATCH_PCT), 0) . "% at {$this->spargeTempC} degrees Celcius."; } // Ingredients $maxWhirlpoolTime = 0; $ingredientXML = $data->Ingredients; //var_dump($ingredientXML); // Different types of misc. ingredients... $miscXML = $ingredientXML->Data->Misc; foreach ($miscXML as $misc) { $name = (string) $misc->F_M_NAME; $unit = intval((string) $misc->F_M_UNITS); $unitName = BeersmithRecipe::bsUnitToStr($unit); $amount = floatval((string) $misc->F_M_AMOUNT); $timeInMin = intval((string) $misc->F_M_TIME); // If the type of unit is a non-conventional / non-specific unit (e.g., tsp, tbsp, item, etc.) then we deal with // it differently than more scientific units... if (isNonScientificUnit($unitName)) { // Leave the unit name as is, clean up the ingredient name $dataFromName = BeersmithRecipe::parseIngredientName($name); $stage = "boil"; if ($dataFromName["boiloutFound"]) { $timeInMin = 0; $stage = "boil"; } else { if ($dataFromName["whirlpoolFound"]) { $timeInMin = min($dataFromName["whirlpoolTimeMin"], 30); $maxWhirlpoolTime = max($maxWhirlpoolTime, $timeInMin); $stage = "Whirlpool"; } } array_push($this->adjuncts, array("name" => $dataFromName["cleanName"], "amount" => $amount, "unit" => $unitName, "timeMin" => $timeInMin, "stage" => $stage)); continue; } $type = intval((string) $misc->F_M_TYPE); switch ($type) { default: // Other // Other case 0: // Spice $volUnitMultiplierToL = unitTypeMultiplierToL($unitName); if ($volUnitMultiplierToL != false) { $amount *= $volUnitMultiplierToL; $unitName = "l"; } else { $amount *= unitTypeMultiplierToKg($unitName); $unitName = "kg"; } // Check to see if the name contains the word whirlpool... if it does then we need to modify this... $dataFromName = BeersmithRecipe::parseIngredientName($name); $stage = "boil"; if ($dataFromName["boiloutFound"]) { $timeInMin = 0; $stage = "boil"; } else { if ($dataFromName["whirlpoolFound"]) { $timeInMin = min($dataFromName["whirlpoolTimeMin"], 30); $maxWhirlpoolTime = max($maxWhirlpoolTime, $timeInMin); $stage = "Whirlpool"; } } array_push($this->adjuncts, array("name" => $dataFromName["cleanName"], "amount" => $amount, "unit" => $unitName, "timeMin" => $timeInMin, "stage" => $stage)); break; case 5: // Water addition... calculate the ppm based on the mash water... $volUnitMultiplierToML = unitTypeMultiplierToML($unitName); if ($volUnitMultiplierToML != false) { $mashOrSparge = "sparge"; if (stristr($name, "MASH")) { $mashOrSparge = "mash"; } $mlAmt = $volUnitMultiplierToML * $amount; $name = trim(preg_replace("/([^\\w\\s\\(\\)\\%]|MASH|Mash|mash|SPARGE|Sparge|sparge)/", "", $name)); array_push($this->waterAcidAdditions, array("name" => $name, "type" => $mashOrSparge, "volMl" => $mlAmt)); } else { if ($mashVolL > 0 && stristr($name, "MASH")) { if (!isVolumeUnit($unitName)) { $gramAmt = unitTypeMultiplierToG($unitName) * $amount; $gPerL = $gramAmt / $mashVolL; // Parse any "MASH" or non-word or space characters out of the name $name = trim(preg_replace("/([^\\w\\s\\(\\)\\%]|MASH|Mash|mash)/", "", $name)); array_push($this->waterSaltAdditions, array("name" => $name, "gPerL" => $gPerL)); } } } break; } } // Grains and simple fermentables... $grainXML = $ingredientXML->Data->Grain; foreach ($grainXML as $grain) { //var_dump($grain); // Remove the supplier name from the name of the grain $name = (string) $grain->F_G_NAME; $supplier = (string) $grain->F_G_SUPPLIER; $capitalizedSupplier = ucfirst($supplier); $nameData = BeersmithRecipe::parseIngredientName($name); $name = $nameData["cleanName"]; $cleanName = trim(preg_replace("/\\(\\s*(" . $supplier . "|" . $capitalizedSupplier . "|" . strtolower($supplier) . "|" . strtoupper($supplier) . ")\\s*\\)/", "", $name)) ?: $name; $isMalted = true; $additionTimeMin = -1; $stage = "boil"; if ($nameData["whirlpoolFound"]) { $isMalted = false; $additionTimeMin = min($nameData["whirlpoolTimeMin"] ?: 30, 30); $maxWhirlpoolTime = max($maxWhirlpoolTime, $additionTimeMin); $stage = "whirlpool"; } else { if ($nameData["boiloutFound"]) { $isMalted = false; $additionTimeMin = 0; } else { if ($nameData["boilTime"] >= 0) { $isMalted = false; $additionTimeMin = $nameData["boilTime"]; } else { if ($nameData["postBoilStage"]) { $stage = $nameData["postBoilStage"]; } } } } $addAfterBoil = (bool) $grain->F_G_ADD_AFTER_BOIL; $kgAmt = round(massOzToKg(floatval((string) $grain->F_G_AMOUNT)), 3); if ($isMalted && !$addAfterBoil) { array_push($this->grains, array("name" => $cleanName, "amountKg" => $kgAmt, "supplier" => $capitalizedSupplier)); } else { // Probably an adjunct sugar / fruit addition... array_push($this->otherFermentables, array("name" => $cleanName, "amountKg" => $kgAmt, "supplier" => $capitalizedSupplier, "timeMin" => $additionTimeMin, "stage" => $stage)); } } $hopsXML = $ingredientXML->Data->Hops; foreach ($hopsXML as $hop) { $hopName = (string) $hop->F_H_NAME; //$alpha = floatval((string)$hop->F_H_ALPHA); $kgAmt = massOzToKg(floatval((string) $hop->F_H_AMOUNT)); $ibus = floatval((string) $hop->F_H_IBU_CONTRIB); $stage = BeersmithRecipe::bsHopUseToStr((string) $hop->F_H_USE); $timeUnit = "min"; $timeVal = 0; if (strtolower($stage) == "dry hop") { $timeUnit = "days"; $timeVal = intval((string) $hop->F_H_DRY_HOP_TIME); } else { $timeVal = intval((string) $hop->F_H_BOIL_TIME); } array_push($this->hops, array("name" => $hopName, "ibus" => $ibus, "amountKg" => $kgAmt, "stage" => $stage, "timeUnit" => $timeUnit, "time" => $timeVal)); } $yeastXML = $ingredientXML->Data->Yeast; foreach ($yeastXML as $yeast) { //var_dump($yeast); // TODO: Deal with brett and lacto... // for lacto figure out whether it goes into fermenter or just kettle souring... $name = (string) $yeast->F_Y_NAME; $lab = (string) $yeast->F_Y_LAB; array_push($this->yeast, array("name" => $name, "lab" => $lab)); } var_dump($this); return true; }
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> <title>Beersmith Test</title> </head> <body> <?php require_once './include/content_utils.php'; require_once './include/beersmith_recipe.php'; $recipe = new BeersmithRecipe(); $recipe->loadFromBSMX('./include/the_final_straw(8-wyeast3944-0.6)[ag,5gal].bsmx'); ?> </body> </html>