Сравните 2 PHP-файла, заполненных переменными, добавьте недостающие переменные от одного к другому - PullRequest
0 голосов
/ 02 марта 2019

У меня есть 2 файла (settings1.php и settings1.default.php), которые содержат переменные настроек для веб-сайта.Когда файлы сайта обновляются, он отправляется на Github, чтобы другие пользователи могли загружать и использовать шаблон сайта.Очевидно, я не хочу, чтобы кто-либо загружал мой settings1.php файл, содержащий информацию о базе данных MySQL и другую личную информацию, и я не хочу, чтобы settings1.php удалялся при выполнении git pull, поэтому у меня есть settings1.default.phpкоторые я обновляю по мере добавления новых функций.

Выдержка из файла:

<?php
$apikey = "11111111111111";    
$TZ = "Europe/London";
$UTC = "1";
$lon = 0.2;
$lat = 50.1;
?>

Моя цель - создать PHP-скрипт, который (быстро) проверяет, есть ли каждая переменная в settings1.default.php существует в settings1.php, и для каждой несуществующей переменной она копирует эту переменную, включая ее значение по умолчанию.И если весь файл settings1.php отсутствует, он копирует settings1.default.php в settings1.php.Сценарий должен будет бороться с пользователями, добавляя пустые строки между переменными или переупорядочивая переменные.

Я взломал сценарий, который делает это очень беспорядочно, но только если нет пробелов.линии, и только если каждая переменная находится в точном правильном порядке.Это беспорядок и, вероятно, очень неэффективно, поэтому было бы лучше начать с нуля с помощью людей, которые знают PHP лучше, чем я.

Ответы [ 3 ]

0 голосов
/ 02 марта 2019

Как говорили другие, используйте массив, но я бы сделал это следующим образом

//settings1.default.php
<?php
return [
    'apikey' => "11111111111111",
    'TZ' => "Europe/London";
    'UTC' => "1";
    'lon' => 0.2;
    'lat' => 50.1;
];

Затем, когда вы загрузите их, вы можете сделать это следующим образом:

$default = require 'settings1.default.php';
$settings = require 'settings1.php';

//you could also use array_replace_recursive() but I would avoid array_merge_recursive()
$settings = array_merge($default, $settings);

И тогда, есливы хотите, чтобы вы могли просто использовать объединенные массивы или сохранить его в файле, подобном следующему:

file_put_contents('settings1.php', '<?php return '.var_export($settings, true).';');

Var Export возвращает синтаксически правильный массив, а второй аргумент возвращает его как строку, а не выводитЭто.Затем вам просто нужно добавить тег <?php, return и закрывающий ;, чтобы иметь файл PHP.

Это также сохраняет чистоту вашего переменного пространства, если вы добавляете переменную, у вас нетПолучатель гранта, что кто-то, использующий это, еще не использует эту переменную.Если они не следуют передовым методам в своем коде, существует вероятность перезаписи данных одного или обоих с неизвестными последствиями.Также было бы немного сложно отладить такую ​​проблему.

По-вашему

Можно делать то, что вы хотите, не делая этого, но вам придетсявключите файлы в функцию (чтобы у вас была чистая область видимости), вызовите get_defined_vars, затем объедините 2 массива, затем зациклите их и вручную создайте PHP для файла.

Если вы не используетеget_defined_vars в «чистой» области вы рискуете импортировать другие переменные в ваши файлы настроек.Это также может привести к проблемам с безопасностью.Под чистой областью действия (просто для ясности) я подразумеваю, что в пустой функции определяются только те переменные, которые используются в качестве аргументов функции (с чем мы все должны согласиться).Таким образом, делая это, мы можем легко удалить единственную «ненастраиваемую» переменную, которая является именем файла.Таким образом, мы можем избежать многих из этих проблем.Без этого у вас действительно не будет возможности узнать, что все будет включено в get_defined_vars();, или, по крайней мере, я понятия не имею, что может в него просочиться.

  function loadSettings($file){
      require $file;
      unset($file); //remove file var you cant use this variable name in either file
      return get_defined_vars();
  }

  $default = loadSettings('settings1.default.php');
  $settings = loadSettings('settings1.php');

  //you could also use array_replace_recursive() but I would avoid array_merge_recursive()
  $settings = array_merge($default, $settings);

  $code = '<?php'."\n";

  foreach($settings AS $var => $value){
      /// ${var} = "{value}";\n
      $code .= '$'.$var.' = "'.$value.'"'.";\n"; //some issues with quotes on strings .. and typing here (no objects etc)
  }


  file_put_contents('settings1.php', $code);

Что выглядит каксвязывайся со мнойОбратите внимание, что у вас будут проблемы с кавычками в строках и т. Д. Например, в приведенном выше коде, если значение $value равно 'some "string" here', это приведет к созданию этой строки в файле $foo = "some "string" here";, что является синтаксической ошибкой.Var Export автоматически исключает эти вещи для вас.Не говоря уже о том, что произойдет, если вы попытаетесь поместить массив в это значение ... И т. Д. Честно говоря, мне лень пытаться отработать все крайние случаи для этого.Это то, что я люблю называть наивной реализацией, потому что поначалу это выглядит просто, но когда вы действительно в нее попали, у вас появляются все эти крайние случаи.

Вероятно, единственный способ действительно исправить это использовать var_export в каждой строке следующим образом:

      //...

foreach($settings AS $var => $value){
    /// ${var} = "{value}";\n
    $code .= '$'.$var.' = '.var_export($value,true).";\n";
}

      //...

Вы можете попытаться сделать что-то вроде проверки, является ли он массивом, экранировать любойне экранированные " еще некоторые проверки типов и т. д. Но какой в ​​этом смысл, поскольку вы можете найти другие крайние случаи позже и т. д. Просто головная боль.Var Export делает фантастическую работу, избегая, и если вы сравните две версии кода, должно быть понятно, почему я сначала сделал оригинальное предложение.

Последнее замечание: вы, вероятно, можете упростить смешанныйкавычки ' и ".У меня просто привычка делать все, что является PHP-кодом в ', потому что с этим можно столкнуться с проблемами.

//don't do this
$code .= "$$var = ".var_export($value,true).";\n";
//or this
$code .= "${$var} = ".var_export($value,true).";\n";

Поскольку PHP будет думать, что это код, а не строка.Ну, это будет выглядеть как переменная переменная, а не то, что вам нужно.

ОБНОВЛЕНИЕ

На основе вашего комментария

Завершено с помощьювторой метод, который вы придумали.Кроме того, выяснилось, что если я заменил require с include внутри функции, он вернет пустой массив, поэтому файл settings1.php будет создан со значениями по умолчанию, если он не существует.Единственное, что мне еще нужно решить, - это самый простой способ потребовать settings1.default.php, но не требовать settings1.php

Я бы сделал это небольшое изменение:

  function loadSettings($file){

      if(!file_exists($file)) return []; //add this line

      require $file;
      unset($file); //remove file var you cant use this variable name in either file
      return get_defined_vars();
  }

Хотя include имеет то поведение, которое вам нужно, это не совсем то, что нужно использовать здесь, как вы упомянули

Мне все еще нужно потренироваться, это самый простой способ потребовать settings1.default.php, но нетребуется settings1.php

Это нарушает общность между ними, что означает, что мы должны писать больше кода практически без пользы.Мы можем избежать этого, добавив регистрацию. Единственное отличие здесь состоит в том, что использование require против include немного бессмысленно, , и оба файла вернут пустой массив , если их не будет.Я бы по-прежнему использовал require, потому что это означает, что этот код важен, когда вы на него смотрите, точнее или нет, он на самом деле ничего не делает.

Часть, выделенная жирным шрифтом выше, мы можем действительно легко исправить, выполнив это:

  function loadSettings($file){

      if(basename($file) != 'settings1.default.php' && !file_exists($file)) return []; //add this line

      require $file;
      unset($file); //remove file var you cant use this variable name in either file
      return get_defined_vars();
  }

Я оставил проверку файлов оригинально, потому что думал, что оба файла всегда будут существовать и будут необходимы.Добавление имени файла также добавляет жесткую зависимость от имени файла настроек.Если это имя файла изменилось, вам придется изменить код.Поэтому я хотел добавить его отдельно, так как с другим поведением может быть все в порядке.

Базовое имя получает завершающую часть пути, чтобы избежать проблем с полными путями к файлу, это вернет имя файла.Что немного облегчает сопоставление его с нашей строкой имени файла, так как нам не нужно беспокоиться о пути.

Так что, если базовое имя файла не равно нашему settings.default файл и файл не существует, возвращает массив.Затем, когда файл будет равен этому файлу, он выйдет из условия if и перейдет к обязательной части, или не выйдет файл settings.default .В основном это будет обрабатывать settings.default как требование, но все равно будет возвращать массив других файлов, если они не существуют (например, include).

Cheers!

0 голосов
/ 02 марта 2019

Вы должны включить settings1.default.php в settings1.php, а затем вызвать get_defined_vars (), у которого будет список переменных, определенных в settings1.default.php, тогда, если какая-то переменная не существует в этом массиве, создайте дополнительную конфигурациюзначения в settings1.php.

settings1.php.

<?php

include_once('settings1.default.php');
$varialbes_defined_settings1_default = get_defined_vars();

?>

0 голосов
/ 02 марта 2019

Я бы просто сохранил все переменные в массиве, затем использовал бы extract, чтобы преобразовать их в фактические переменные, и использовал бы array_intersect_key, чтобы посмотреть, равна ли длина пересечения массивов длине.из $defaultSettings:

//settings1.default.php
$defaultSettings = [
    'apikey' => "11111111111111",
    'TZ' => "Europe/London";
    'UTC' => "1";
    'lon' => 0.2;
    'lat' => 50.1;
];

//settings.php
$settings = [
    'apikey' => "11111111111111",
    'TZ' => "Europe/London";
    'UTC' => "1";
    'lon' => 0.2;
    'lat' => 50.1;
];
extract($settings); // creates the variables $apikey, $TZ, etc.

//check.php
require('settings1.default.php')
require('settings.php')
//if they don't have the same keys
if (count(array_intersect_key($settings , $defaultSettings)) !== count($defaultSettings)) {
    throw new \Exception("Invalid configuration");
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...