Writing values to INI file - php

I'm trying to store multiple data and then at the end go a head and push the data into the new .ini file. I found solutions which works but I want to get all the data first and then update the file at the end but the solutions i found updates the file straight away!
A solution I liked and worked is located: https://stackoverflow.com/a/36997282/6613233
I am trying to allow it gather information and then push it to the file at the end. My own attempt at this is below but i keep getting array array in my ini file.
Code:
$fbsettingsDB = parse_ini_file("location.ini", true);
$fbsettingsDB["id"]["value"] = $_POST['fbconfigid'];
$fbsettingsDB["location"]["value"] = $_POST['fbconfigcty'];
file_put_contents('location.ini', implode("\n", $fbsettingsDB));
The above is how I want to collect data. I have a bunch of code which goes in and out of statements, I want it to go ahead.. Assign the values required and at the very end go ahead and put the contents in the file like shown above.
Using the referred code i would then have to do:
config_set("location.ini", "id", "value", $_POST['fbconfigid']);
config_set("location.ini", "location", "value", $_POST['something']);
config_set("location.ini", "result", "value", $_POST['somethingelse']);
Which overwrites the file every time which in my opinion is just crazy! Overkill for my idea, there is obviously some way that can suit my needs so i can just call the function once after making a list of edit/changes and then when i call the function it grabs all my changed data and saves the file the way i want it!

I'll try to explain first why your code doesn't work, compared to the other.
Your inifile-array is build up of a nested array, $array[section][item] = value. The first dimension has the section names. The second dimension is the name of the items in the sections. So $fbsettingsDB["location"] contains an array of items, of which "value" is one.
Implode doesn't check if the array is nested. It just takes the first dimension (the sections) and tries to treat their values as a string. Since those values are actually arrays of items, PHP just converts that to the text 'array'.
Apart from that, you can't just implode the whole array. Section names should be enclosed in square brackets, so there is a little more work to do in that regard too.
If you check the solution in the answer you referred to, you'll see that it contains a loop which takes care of the first layer, the sections.
The array of items of each section is converted separately with implode, which is then prefixed by the section name in square brackets, and the whole lot is appended to the end result.
So, your intention here: You don't want to set a value and write it back to file at once, but update multiple values and only write the end result to disk. Well, fortunately the function doesn't have to be atomic. It already performs three separate actions: loading from disk, modifying the data, and serializing it back to disk. Let's see if those can be isolated in separate functions:
Read the data. Well, hardly worth to make a function, but it may make your application somewhat more consistent if you use the same naming et cetera in a collection of related functions.
Note: I just wrote these from scratch. No PHP at hand to test, so they might contain minor syntactical errors.
So here it is:
// Loads ini file data
function config_read($config_file) {
return parse_ini_file($config_file, true);
}
Setting the config in the loaded data. Again, hardly worth to have a function, but it adds readability and hides how exactly the ini file data is built up, so you don't have to worry about implementation details when using it. Note that the array is passed by reference. The array you specify is updated. The function doesn't return a value.
// Update a setting in loaded inifile data
function config_set(&$config_data, $section, $key, $value) {
$config_data[$section][$key] = $value;
}
Then writing it:
// Serializes inifile config data back to disk.
function config_write($config_data, $config_file) {
$new_content = '';
foreach ($config_data as $section => $section_content) {
$section_content = array_map(function($value, $key) {
return "$key=$value";
}, array_values($section_content), array_keys($section_content));
$section_content = implode("\n", $section_content);
$new_content .= "[$section]\n$section_content\n";
}
file_put_contents($config_file, $new_content);
}
Note that so far I didn't modify any of the code. I just wrapped it in separate functions. If you like, you could even call those functions in another function, so you still got the shorthand to write everything to disk at once. You'll have the original functionality, but without having duplicate code:
// Short-hand function for updating a single config value in a file.
function config_set_file($config_file, $section, $key, $value) {
$config_data = config_read($config_file);
config_set($config_data, $section, $key, $value)
config_write($config_file, $section, $key, $value);
}
So, now you got this collection of functions, you can decide which to use based on the situation. If you just want to update a single value, you might as well write this:
config_set_file("location.ini", "id", "value", $_POST['fbconfigid']);
But if you have multiple configs to set, you can do this:
// Load
$config_data = config_read("location.ini");
// Set multiple values
config_set($config_data, "id", "value", $_POST['fbconfigid']);
config_set($config_data, "location", "value", $_POST['something']);
config_set($config_data, "result", "value", $_POST['somethingelse']);
// Save
config_write($config_data, $config_file);
I can imagine you can add other shorthands, like config_set_array_file, which you could call like this.. I'll leave the implementation of this one to you for exercise. ;)
array_config_set_file($config_file, array(
"id" => $_POST['fbconfigid'],
"location" => $_POST['something'],
"result" => $_POST['somethingelse']));
And after that, you can poor all this into an IniFile class to make it even nicer. :)

Related

How can I refactor code to avoid assigning output of a partial ViewHelper to a variable of another partial ViewHelper?

I have some code where I am struggling to separate "data" from "sending data to Zend partial View Helpers". For example, i.e. I want to create "just data", return just data from my data function to a parent caller
//contains no $this->partial(), deals only with accumulating data
//that may or may not be used for partial later on
$data = $this->getDataOnly();
//deals only with sending data to partial for rendering purposes
$this->generatePartials($data);
In the code below I seem to mix both together. Specifically, I have a partial as part of my data, and that is what I seek to avoid.
// $modalData is an array accumulating data for Zend Partial View Helper
// it already has some data, i.e. id, boolean vars
foreach($modalData as $i => $value)
{
// here we are adding 'modalHtml' view helper variable
// which will contain HTML gotten from (another) partial
// Problem: I am not comfortable using a 'partial' as part of a parent 'partial'
// (which is further down in the code)
// what could've been "clean data only" generation is about to be
// polluted by stuffing a partial into it, mixing data and view
$modalData[$i]['modalHtml'] = $this->partial(
"partial/product.phtml",
parent::getModalContentData($i)
);
}
//here we are appending HTML produced from partialLoop, using $modalData
$modalBoxesHtml .= $this->partialLoop("partial/modal_box.phtml", $modalData);
Question:
can I avoid the part where I am "stuffing a partial (which is HTML code and not data) directly into a variable of another view helper partial"?
Can I use some sort of a better more intelligent construct, similar to addChild of a ViewModel?
I want to get away from assigning "HTML Blocks" to a view helper variable and only assign actual data. Can this be done?
I might have been able to do what I seek
I moved my partial method call into the partial/*.phtml file itself
<div>
<?php
echo $this->partial("partial/product.phtml", $this->modalData);
?>
</div>
I now have nested partials.
My data became nested too
foreach($modalData as $i => $value)
$modalData[$i]['modalHtml'] = parent::getModalContentData($i);

PHP - make $_FILES filenames safe

I have an form that contains an "attachments" field, allowing a user to add multiple attachments. Each attachment is then uploaded but before doing so, each file name is made safe using the following function.
function safeFile($file) {
$lower = strtolower($file);
$trim = rtrim($lower, '.');
$regex = array('#[^A-Za-z0-9\.\_\- ]#');
return trim(preg_replace($regex, '', $trim));
}
So far so good.
I'm then json encoding the file names to store in the database. using the following:
json_decode($_FILES['attachment']['name']);
This outputs the following in the database:
["FILE.jpg", "OTHER.jpg"]
This works, however I'm also trying to call the safeFile() function so that the same action is applied before inserting into the database as it does when uploaded.
I tried using the following which did not work.
json_encode( safeFile($_FILES['add_attachment']['name']) );
To get around this, thinking logically, would I have to create a foreach loop, then making each individual file name safe, then return an array?
Could someone please shove me in the right direction?
You don't need a foreach loop
You need to use array_map() like this
array_map("safeFile", $_FILES['add_attachment']['name']);
Also, what I think you need to be using is json_encode() not json_decode

Wrong dataype for in_array

Good morning.
I'm currently trying to build a very basic caching system for one of my scripts. The cache is JSON data and contains only 1 key and it's value, but many individual fields, something like this;
{"Item1":"Item1 Description"}
{"Item2":"Item2 Description"}
{"Item3":"Item3 Description"}
What I'm intending to do is;
First check if a cache file is available
Then check if an item exists in the cache
Then add the new item along with it's description if it's not already in the cache...
...or return the item description if it's not there.
All data being stored is strings. The cache file doesn't store any other type of data.
I've put together a basic function but I'm having trouble getting it functioning;
function ItemIsInCache($CacheFile, $ItemId) {
if(file_exists($CacheFile)) {
$json = json_decode(file_get_contents($CacheFile, true));
if(in_array($ItemId, $json)) { // <<
$itemname = array_search($ItemId, $json);
return itemname;
} else {
$item[$itemId] = GrabItemName($ItemId);
$itemname = array_search($ItemId, $json); // <<
return $itemname;
}
} else {
$item[$ItemId] = GrabItemName($ItemId);
$ejson = json_encode($item);
file_put_contents($CacheFile, $ejson);
return $item[$ItemId];
}
}
Notes
GrabItemName is a different function that returns the description data based on the $ItemId.
The warnings I'm getting are Wrong datatype for second argument in both array_search() and in_array(), on lines 4 and lines 9 respectively (those are the line numbers in the above code - due to the nature of my script these numbers are later on) -- for simplicity, I've marked the problem lines with // <<.
The function is running in a loop which I've no problems with. The problems lie within this function.
What currently happens
Right now, if the cache doesn't exist, it creates it and adds the first item from the loop to the cache file in it's respective JSON format (that fires since the cache file doesn't exist, so after the final else statement).
However, items from the loop after that don't get added, presumably because the file exists and there's something wrong with the code.
The last part of the function works exactly as I want it to but the first part does not.
Expected behaviour with fixed code
Check cache > Return description if item exists ELSE add new item to cache.
The items and their associated descriptions will NOT change, but I'm pulling them from a rate limited API, and I need to ensure I cache whatever I can for everyones benefit.
So, any ideas what I'm doing wrong with the function? I'm sure it's something incredibly simple that I'm overlooking.
Your file is not JSON for an erray. The correct JSON for an array is
[
{"Item1":"Item1 Description"},
{"Item2":"Item2 Description"},
{"Item3":"Item3 Description"}
]
You're missing the brackets around the array, so you just get a single object.
When creating the initial file, you need to do:
$ejson = json_encode(array($item));
so that it's initialized as an array of one item, not just an item.

How can I bulk update a basic one-to-one key structure located in a.html file with script or text editor like this?

I have a one-to-one key structure of zip codes to user located in a .html that looks like...
...
'80135': 'user1',
'80136': 'user1',
'80137': '',
'80138': '',
'80202': 'user2',
'80203': 'user2',
'80204': '',
'80205': '',
'80206': '',
'80207': '',
...
I would like to take a bulk list zip codes for user3 and fill in or over-write old user. So for example if I have for user3, zip codes (80202,80203,80204) then my previous block of code would change to...
...
'80135': 'user1',
'80136': 'user1',
'80137': '',
'80138': '',
'80202': 'user3',
'80203': 'user3',
'80204': 'user3',
'80205': '',
'80206': '',
'80207': '',
...
The reason for text editor is to complete my set now, but ideally it would be nice to have a client application that our non-programmer team can update and make changes as they please, so a script for this would be nice for future plans.
I am passing the content into my site via...
var list_load = {<?php include_once('list.html'); ?>};
Because I believe some might have an alternate idea on storage of this information, this list is very long, 35,000 lines of code, so any ideas on completely changing my code consider a process to migrate data.
Based on the information you provided I'm going to assume your example code is a subset of a JSON object. I'm also going to assume that you only have a one-to-one relationship of zip-codes to users in your object given that you did not explicitly state otherwise and given that the existing object structure would not allow for one-to-many relationship. Given all these assumptions the solution to your immediate problem is to load the JSON into PHP, make your changes there, and then overwrite the entire file with the updated JSON object.
$json = file_get_contents('list.html');
$array = json_decode($json, true);
$oldUser = 'user2';
$newUser = 'user3';
$listZipCodes = array("80204"); // list of zip codes to update
// Update the JSON based on user ...
foreach ($array as $zipCode => $user) {
if ($user === $oldUser) {
$array[$zipCode] = $newUser;
}
}
// Update the JSON based on zip code ...
foreach (array_keys($array) as $zipCode) {
if (in_array($zipCode, $listZipCodes)) {
$array[$zipCode] = $newUser;
}
}
$json = json_encode($array);
file_put_contents('list.html', $json);
Again, this is all assuming that list.html looks like this...
{
"80135": "user1",
"80136": "user1",
"80137": "",
"80138": "",
"80202": "user2",
"80203": "user2",
"80204": "",
"80205": "",
"80206": "",
"80207": ""
}
Remember it has to be valid a valid JSON object notation in your list.html in order for PHP to be able to parse it correctly. Your existing example is not going to work in PHP because you're using single quotes instead of double quotes, which is a requirement of the JSON spec. So you have to make sure that part is valid in your list.html file.
Beyond that I highly discourage you to take this approach, because it causes a number of serious problems that can't easily be solved. For example, you can not ensure your data won't be corrupted using this approach as anyone two PHP scripts may attempt to overwrite the file at the same time (no data integrity). Also, you can't easily make this scale without it costing you a lot of unnecessary CPU and memory problems if the list gets large enough. Additionally, you have no way to control who may edit the file directly and thus no way to control data flow to the underlying application code that tries to use that data.
A better solution is to use a database and that way you can both control the data and its user privileges, plus you can provide a front-end for non-programmers to edit/modify/read the data through your front-end, via PHP.

Store text in PHP array or MySQL database?

Lets say I've got 50 pages, and I want to write a description for about 30 of them.
The description will be about two paragraphs on each page.
Is it more efficient for my server if I save the descriptions in a MySQL database and then query on each page to see if there is a corresponding description, or is it best if I store them in an array in my PHP file and see if the element exists?
Extra Info:
I would edit the array file manually or the db entry through phpMyAdmin which would both take the same amount of time. Also it would only be me editing them so I don't have to worry about making a quick edit file.
Do it like this:
Store them in an array, in a sepparate file data.php, in this form:
<?php
return array(
// here be data
);
In the caller script you use it like this:
$data = require 'data.php';
and then use the $data variable throughout the site, as needed. You could also split the array and use several files based on specific criterias, like "the language", or "article category" or whatever.
If you do it this way, you can always plug in an editor with a web interface to edit that array and store it back with file_put_contents('data.php', '<?php return '. var_export($data));, where $data has got its value after processing a POST form, for instance, which was generated from the old value of $data.
Really elegant, fast, and maintainable!
As a bonus, write helper functions around those serializations, deserializations, etc, such that if you ever change your mind (because your site grows and you end up with hundreds of such arrays), you only have to reimplement those functions to use a database backend, without ever touching the rest of the codebase.
Code reusability and maintanability at its peak! And you get it up and running immediately, without losing the prospect of making it better in the future, if required.
If you don't change those descriptions frequently, you can store them in array. But it'll be better to keep them in separated files, instead of keeping them all in one PHP file.
But your server can easily handle that kind of small rows. So do what is easy for you.
Maybe you can store them in database for adding/editing stuff and do a cache of it to read from your page.
I would store the information in a DB. It is more slowy but more elegant.
If you want to do it with an array:
Class Page
{
// global configuration
private static $config = null;
// individuel configuration
public $title, $content;
// constructor
function __construct($page) {
// get the configuration
$config = self::getConfig();
// cheack weather the page exists
if(!isset($config[$page]))
die('unknown page "'.$page.'"');
// set some stuff
$this->title = $config[$page]['title'];
$this->content = $config[$page]['content'];
}
// get the configuration
private function getConfig() {
if(self::$config === null)
self::$config = include(dirname(__FILE__) . '/config.php');
return self::$config;
}
}
Configuration:
return Array(
'home' => Array(
'title' => 'Welcome!',
'content' => 'Welcome to my site!' /* maybe include some html for complxe stuff */
)
);
Example:
$myPage = new Page('home');
echo $myPage->content;

Categories