[ 'Vegetarian' => [ 'Batido de iogurte grego, aveia, e frutos vermelhos congelados' => [5601009969135, 5601009967780, 5601009975327], 'Torrada integral com abacate e ovos mexidos' => [5607233572813, 5601009984329, 5601009920334], 'Omelete de espinafres e tomate com pão integral' => [5601009920334, 5601009297641, 5601009986958, 5607233572813], 'Papas de aveia com mel e frutos vermelhos congelados' => [5601009967780, 5607047004982, 5601009975327], 'Batido de whey protein, aveia e frutos vermelhos congelados' => [5601607073999, 5601009967780, 5601009975327], 'Batido de whey protein com banana e leite' => [5601607073999, 95159331, 5601049132995], ], ], 'Lunch' => [ 'Poultry' => [ 'Hambúrguer de peru com batatas-doce assada e salada' => [5601312306610, 5601009922116, 5601009948017], 'Wrap de frango com abacate e legumes' => [5601009984831, 2689349006997, 5601009984329, 5601009985135], 'Peito de frango grelhado com quinoa e espinafres' => [2689349006997, 5607047006467, 5601009297641], 'Wrap de peru com húmus e legumes' => [5601312306610, 5607047020265, 5601009984831, 5601009985135], ], 'Fish' => [ 'Filetes de peixe branco com puré de batatas e feijão-verde' => [5601009500567, 5601009940196, 5601009500758], 'Salmão grelhado com puré de batatas e brócolos' => [5601009960439, 5601009940196, 5601312500223], ], 'Vegetarian' => [ 'Tofu salteado com pimentos e quinoa' => [5607047013687, 5601009942060, 5607047006467], ], ], 'Snack' => [ 'Vegetarian' => [ 'Iogurte grego com frutos vermelhos congelados' => [5601009969135, 5601009975327], 'Queijo cottage com mel e frutos secos' => [5607047008058, 5607047004982, 3271670001421], 'Ovos cozidos com uvas' => [5601009920334, 7754856000204], 'Iogurte grego com granola baixa em açúcar' => [5601009969135, 5601009992706], 'Queijo cottage com uvas' => [5607047008058, 7754856000204], ], ], 'PreWorkout' => [ 'Vegetarian' => [ 'Barra de proteína (baixo em açúcar)' => [5607047017722], 'Tortitas de arroz com mel ou manteiga de amendoim e uma maçã' => [5607047013090, 5607047004982, 5601009997435, 5601009990597], 'Um punhado de frutos secos e uma banana' => [3271670001421, 95159331], ], ], 'Dinner' => [ 'Fish' => [ 'Salmão grelhado com batatas-doce e feijão-verde' => [5601009960439, 5601009922116, 5601009500758], 'Peixe grelhado com legumes salteados' => [5601009500567, 5601009985135], ], 'Meat' => [ 'Salteado de carne de vaca magra com arroz e legumes' => [5600294202255, 5601009996995, 5601009985135], 'Carne picada de vaca com quinoa e pimentos' => [5601002069467, 5607047006467, 5601009942060], ], 'Vegetarian' => [ 'Tofu salteado com pimentos e quinoa' => [5607047013687, 5601009942060, 5607047006467], ], ], ]; function fetchNutritionData($productId) { // Define the directory to store JSON files $dataDirectory = 'nutrition_data/'; // Create the directory if it doesn't exist if (!is_dir($dataDirectory)) { mkdir($dataDirectory, 0777, true); } // Define the file path where the JSON will be saved or loaded $filePath = $dataDirectory . $productId . '.json'; // Check if the file already exists if (file_exists($filePath)) { // Load and return the cached data $jsonData = file_get_contents($filePath); $nutritionData = json_decode($jsonData, true); //echo "Loaded from cache: $productId\n"; } else { // Fetch the data from Open Food Facts API $url = "https://world.openfoodfacts.org/api/v0/product/$productId.json"; // Perform the request $response = file_get_contents($url); // Check if the response is valid if ($response !== false) { // Decode the JSON response $nutritionData = json_decode($response, true); // Save the JSON response to the local file for future use file_put_contents($filePath, $response); //echo "Fetched and saved data: $productId\n"; } else { echo "Error fetching data for product ID: $productId\n"; return null; } } // Access the nutritional data if (isset($nutritionData['product']) && isset($nutritionData['product']['nutriments'])) { $nutrients = $nutritionData['product']['nutriments']; return [ 'calories' => $nutrients['energy-kcal_serving'] ?? $nutrients['energy-kcal_100g'], 'protein' => $nutrients['proteins_serving'] ?? $nutrients['proteins_100g'], 'fat' => $nutrients['fat_serving'] ?? $nutrients['fat_100g'], 'carbs' => $nutrients['carbohydrates_serving'] ?? $nutrients['carbohydrates_100g'], 'portion' => $nutritionData['product']['serving_quantity'] ?? 100, // Assuming values are per 100g 'unit' => $nutritionData['product']['serving_quantity_unit'] ?? 'g', // Default unit for grams 'name' => $nutritionData['product']['product_name_pt'] ?? $nutritionData['product']['product_name'] // Default unit for grams ]; } return null; } // https://en.wikipedia.org/wiki/Harris%E2%80%93Benedict_equation // https://www.nutritioncarepro.com/harris-benedict-equation // https://www.k-state.edu/paccats/Contents/PA/PDF/Physical%20Activity%20and%20Controlling%20Weight.pdf // https://www.healthline.com/health/what-is-basal-metabolic-rate#takeaway function calculateBMR($is_female, $weight, $height, $age, $activity_level) { if ($is_female) $bmr = (9.5634 * $weight) + (1.8496 * $height) - (4.6756 * $age) + 655.0955; else $bmr = (13.7516 * $weight) + (5.0033 * $height) - (6.755 * $age) + 66.473; return $bmr * $activity_level; } function calculateMealNutrition($ingredients, $scaleFactors = []) { $total = ['calories' => 0, 'protein' => 0, 'fat' => 0, 'carbs' => 0]; $ingredientPortions = []; // To track the portions for the shopping list foreach ($ingredients as $ingredient) { $nutritionData = fetchNutritionData($ingredient); if ($nutritionData) { $scale = $scaleFactors[$ingredient] ?? 1; foreach ($total as $key => $value) { $total[$key] += $nutritionData[$key] * $scale; } // Track the portion of each ingredient $ingredientPortions[$ingredient] = ($ingredientPortions[$ingredient] ?? 0) + $scale; } } return ['nutrition' => $total, 'portions' => $ingredientPortions]; } function getBalancedMeal($mealType, &$selectedMeals, &$remainingGoals) { global $mealOptionsAndIngredients; if (!isset($mealOptionsAndIngredients[$mealType])) { return ["Base de Dados vazia :s", [], ['calories' => 0, 'protein' => 0, 'fat' => 0, 'carbs' => 0], []]; } $categories = array_keys($mealOptionsAndIngredients[$mealType]); shuffle($categories); // Shuffle categories for randomness foreach ($categories as $category) { $availableMeals = array_filter( $mealOptionsAndIngredients[$mealType][$category], function ($meal) use ($selectedMeals, $mealType) { return !in_array($meal, $selectedMeals[$mealType]); // Exclude already selected meals } ); // If no meals are available, consider all meals in the category if (empty($availableMeals)) { $availableMeals = $mealOptionsAndIngredients[$mealType][$category]; // Reset selection of this type $selectedMeals[$mealType] = []; } shuffle_with_keys($availableMeals); // Shuffle available meals for randomness foreach ($availableMeals as $mealName => $ingredients) { $totalCalories = 0; $totalProtein = 0; $totalFat = 0; $totalCarbs = 0; // Calculate total nutritional values for the meal dynamically foreach ($ingredients as $ingredientId) { $nutritionData = fetchNutritionData($ingredientId); $totalCalories += $nutritionData['calories']; $totalProtein += $nutritionData['protein']; $totalFat += $nutritionData['fat']; $totalCarbs += $nutritionData['carbs']; } // Calculate scale factors based on remaining goals $scaleCalories = $totalCalories > 0 ? $remainingGoals['calories'] / $totalCalories : 1; $scaleProtein = $totalProtein > 0 ? $remainingGoals['protein'] / $totalProtein : 1; $scaleFat = $totalFat > 0 ? $remainingGoals['fat'] / $totalFat : 1; $scaleCarbs = $totalCarbs > 0 ? $remainingGoals['carbs'] / $totalCarbs : 1; // Scale the meal to fit the remaining nutritional goals $scale = min($scaleCalories, $scaleProtein, $scaleFat, $scaleCarbs); // If a valid scale is found, calculate the nutrition if ($scale > 0) { $mealNutrition = calculateMealNutrition($ingredients, $scale); $nutrition = $mealNutrition['nutrition']; $portions = $mealNutrition['portions']; // Ensure the meal fits within the remaining goals if ( $nutrition['calories'] <= $remainingGoals['calories'] && $nutrition['protein'] <= $remainingGoals['protein'] && $nutrition['fat'] <= $remainingGoals['fat'] && $nutrition['carbs'] <= $remainingGoals['carbs'] ) { $selectedMeals[$mealType] [] = $mealName; foreach ($remainingGoals as $key => &$value) { $value -= $nutrition[$key]; // Update remaining goals } unset($value); // Clean up reference return [$mealName, $ingredients, $nutrition, $portions]; } } } } return ["Já comeste o suficiente, agora passa fome!", [], ['calories' => 0, 'protein' => 0, 'fat' => 0, 'carbs' => 0], []]; } function getWeeksOfCurrentMonth() { $currentDate = new DateTime(); $currentDate->modify('first day of this month'); $startOfMonth = $currentDate->format('Y-m-d'); $endOfMonth = $currentDate->modify('last day of this month')->format('Y-m-d'); $weeks = []; $currentWeekStart = new DateTime($startOfMonth); while ($currentWeekStart->format('Y-m-d') <= $endOfMonth) { $weekStart = clone $currentWeekStart; $weekEnd = clone $currentWeekStart; $weekEnd->modify('next Sunday'); if ($weekEnd->format('Y-m-d') > $endOfMonth) { $weekEnd = new DateTime($endOfMonth); } $weeks[] = [ 'week_start' => $weekStart->format('Y-m-d'), 'week_end' => $weekEnd->format('Y-m-d'), ]; $currentWeekStart->modify('next Monday'); } return $weeks; } function generateMonthPlan($includeWeekends, $is_female, $weight, $height, $age, $activity_level, $bmr = null) { global $mealOptionsAndIngredients; $mealtypeToPortuguese = ['Brunch' => 'Pequeno-almoço', 'Lunch' => 'Almoço', 'Snack' => 'Lanche', 'PreWorkout' => 'Pré-treino', 'Dinner' => 'Jantar']; $bmr = is_null($bmr) ? calculateBMR($is_female, $weight, $height, $age, $activity_level) : $bmr; // https://www.healthline.com/nutrition/best-macronutrient-ratio // These ranges are recommended by the Institute of Medicine and are widely accepted in nutritional science. // https://www.nal.usda.gov/programs/fnic // Carbohydrates provide 4 calories per gram, // protein provides 4 calories per gram, // and fat provides 9 calories per gram. $dailyMacronutrientGoals = [ 'calories' => round($bmr), 'protein' => round($bmr * 0.3 / 4), // "10-35% from protein" 'fat' => round($bmr * 0.25 / 9), // "20-35% from fats" 'carbs' => round($bmr * 0.45 / 4), // "45-65% of your daily calories from carbs" ]; $weeks = getWeeksOfCurrentMonth(); $usedIngredients = []; $plan = "

Plano Alimentar do Mês

\n"; $plan .= "

Meta Diária de Macronutrientes:

\n"; $plan .= ""; foreach ($weeks as $week) { $plan .= "

Semana de {$week['week_start']} a {$week['week_end']}

\n"; $daysOfWeek = $includeWeekends ? ['Segunda-feira', 'Terça-feira', 'Quarta-feira', 'Quinta-feira', 'Sexta-feira', 'Sábado', 'Domingo'] : ['Segunda-feira', 'Terça-feira', 'Quarta-feira', 'Quinta-feira', 'Sexta-feira']; $selectedMeals = ['Brunch' => [], 'Lunch' => [], 'Snack' => [], 'PreWorkout' => [], 'Dinner' => []]; // Reset weekly meal selection foreach ($daysOfWeek as $day) { $plan .= "

{$day}

\n"; $remainingGoals = $dailyMacronutrientGoals; // Use daily goals for each day foreach (['Brunch', 'Lunch', 'Snack', 'PreWorkout', 'Dinner'] as $mealType) { list($meal, $ingredients, $nutrition, $portions) = getBalancedMeal($mealType, $selectedMeals, $remainingGoals); $plan .= "

{$mealtypeToPortuguese[$mealType]}: {$meal}

\n"; $plan .= "

Ingredientes: "; $ingredientList = []; foreach ($ingredients as $ingredientId) { $nutritionData = fetchNutritionData($ingredientId); $gramsRequired = $portions[$ingredientId] * $nutritionData['portion']; $ingredientList[] = "{$nutritionData['name']} ({$gramsRequired} {$nutritionData['unit']})"; } $plan .= implode(", ", $ingredientList) . "

\n"; $plan .= "

Informação Nutricional: {$nutrition['calories']} kcal, {$nutrition['protein']} g proteína, " . "{$nutrition['fat']} g gordura, {$nutrition['carbs']} g carboidratos

\n"; // Update used ingredients and portions foreach ($portions as $ingredientId => $portion) { $ingredientPortions[$ingredientId] = ($ingredientPortions[$ingredientId] ?? 0) + $portion; } } } } // Generate shopping list $plan .= "

Lista de Compras do Mês

\n"; return $plan; } // Check if all required GET parameters are set if ($_SERVER['REQUEST_METHOD'] != 'GET' || !isset($_GET['is_female'], $_GET['weight'], $_GET['height'], $_GET['age'], $_GET['activity_level'])) { echo "O plano será gerado assim que preencheres o formulário."; exit; } else { // Process parameters $includeWeekends = ($_GET['include_weekends'] == "on") ? true : false; $is_female = ($_GET['is_female'] == "true"); $weight = (float) $_GET['weight']; $height = (int) $_GET['height']; $age = (int) $_GET['age']; $activity_level = (float) $_GET['activity_level']; $bmr = (isset($_GET['bmr']) && !empty($_GET['bmr'])) ? (int) $_GET['bmr'] : null; echo generateMonthPlan($includeWeekends, $is_female, $weight, $height, $age, $activity_level, $bmr); }