Store text in PHP array or MySQL database? - php

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;

Related

Is there a way to execute required php file once per session?

I am new to php and have just written a basic index.php that will display family tree information for an individual based on input id.
The index.php includes a file called "xml-people-list.php" which loads the information from the family tree and creates a sorted list of people.
My problem is that every time you click on a person to display their details, the included php is reloaded which causes the read from file and creation of sorted list to happen again.
Is there a way to only run this code once per session to avoid multiple loads?
I tried to look at session variables but wasn't sure if they would help or how to use them in this case or if there is another way?
Contents of "xml-people-list.php:
<?php require 'xml-load-person.php';
if (file_exists('people.xml'))
{
$people = simplexml_load_file('people.xml');
foreach ($people->person as $person)
{
$person_list[(string)$person['ID']] = strtoupper($person->FamilyName) . ", " . $person->GivenNames;
}
asort($person_list);
}
else
{
exit('Failed to open people.xml.');
}
?>
Thanks for any help!
Yes, you could use session variables. If you wanted to only parse the list once per visitor, and then "cache" the result into a session variable, you could do something like this (for a simple example):
if (!empty($_SESSION['person_list'])) {
// Here we fetch and decode the the ready list from a session variable, if it's defined:
$person_list = json_decode($_SESSION['person_list']);
}
// Otherwise we load it:
else {
require 'xml-load-person.php';
if (file_exists('people.xml'))
{
$people = simplexml_load_file('people.xml');
foreach ($people->person as $person)
{
$person_list[(string)$person['ID']] = strtoupper($person->FamilyName) . ", " . $person->GivenNames;
}
asort($person_list);
// Here we assign the ready list to a session variable (as a JSON string):
$person_list = json_encode($person_list);
$_SESSION['person_list'] = $person_list;
// Here we revert the JSON-encoded (originally SimpleXML) object into a stdClass object.
$person_list = json_decode($person_list);
}
else
{
exit('Failed to open people.xml.');
}
}
You will need to call session_start() in your file (either this one, or any other file including it, but importantly before any output is sent to the browser). Homework: Read up on sessions in PHP.
Update: Since SimpleXML objects can't be serialized, and since adding an object to $_SESSION causes serialization, I've updated the answer to json_encode/decode the object. Yes there's a bit of processing, but that'd be the case with the default serialization as well, and json_en/decode is fairly light-weight. Certainly heaps lighter than parsing XML on each page load!
Be aware that the returned object will be a stdClass object, not a SimpleXML object. I'm assuming it won't be a problem in your use case.
Maybe try require_once() function
1) First of all, try to see if your buttons are anchor tags then be sure that the href attribute is directing to # example: <a href="#">
2) try to use include_once instead of requiring
3) if you tried this and these couple solutions didn't work for you you can send the id of a person using the global $_GET variable
//this should be you URL http://localhost/projectname/index.php?person_id=1
// your href of each person should appoint to their URL
// <a href="index.php?person_id=1">
you can use this $_GET['person_id'] and store it into a variable so it will give you the id of person.

Writing values to INI file

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. :)

query string in php url which fetches values from files in directories

for security reasons we need to disable a php/mysql for a non-profit site as it has a lot of vulnerabilities. It's a small site so we want to just rebuild the site without database and bypass the vulnerability of an admin page.
The website just needs to stay alive and remain dormant. We do not need to keep updating the site in future so we're looking for a static-ish design.
Our current URL structure is such that it has query strings in the url which fetches values from the database.
e.g. artist.php?id=2
I'm looking for a easy and quick way change artist.php so instead of fetching values from a database it would just include data from a flat html file so.
artist.php?id=1 = fetch data from /artist/1.html
artist.php?id=2 = fetch data from /artist/2.html
artist.php?id=3 = fetch data from /artist/3.html
artist.php?id=4 = fetch data from /artist/4.html
artist.php?id=5 = fetch data from /artist/5.html
The reason for doing it this way is that we need to preserve the URL structure for SEO purposes. So I do not want to use the html files for the public.
What basic php code would I need to achieve this?
To do it exactly as you ask would be like this:
$id = intval($_GET['id']);
$page = file_get_contents("/artist/$id.html");
In case $id === 0 there was something else besides numbers in the query parameter. You could also have the artist information in an array:
// datafile.php
return array(
1 => "Artist 1 is this and that",
2 => "Artist 2..."
)
And then in your artist.php
$data = include('datafile.php');
if (array_key_exists($_GET['id'], $data)) {
$page = $data[$_GET['id']];
} else {
// 404
}
HTML isn't your best option, but its cousin is THE BEST for static data files.
Let me introduce you to XML! (documentation to PHP parser)
XML is similar to HTML as structure, but it's made to store data rather than webpages.
If instead your html pages are already completed and you just need to serve them, you can use the url rewriting from your webserver (if you're using Apache, see mod_rewrite)
At last, a pure PHP solution (which I don't recommend)
<?php
//protect from displaying unwanted webpages or other vulnerabilities:
//we NEVER trust user input, and we NEVER use it directly without checking it up.
$valid_ids = array(1,2,3,4,5 /*etc*/);
if(in_array($_REQUEST['id'])){
$id = $_REQUEST['id'];
} else {
echo "missing artist!"; die;
}
//read the html file
$html_page = file_get_contents("/artist/$id.html");
//display the html file
echo $html_page;

Clean URLS in MVC structure using PHP

I am creating a website using the MVC structure. Below is a code I have used to use clean URLS and load the appropriate files. However it only works for the first level.
Say I wanted to visit mywebsite.com/admin it would work, however mywebsite.com/admin/dashboard would not. The problem is in the arrays, how could I get the array to load content after the 2nd level along with the second level.
Would it be best to create an array like this?
Array
- controller
- view
- dashboard
Any help here would be great. Also as a side question. What would be the best way to set up "custom" urls. So if I were to put in mywebsite.com/announcement it would check to see if its got controllers, failing that, check to see if it's got custom content (maybe a file of the same name in "customs" folder, and then if there's nothing execute the 404 page not found stuff) This isn't a priority question though, but loosely associated in how the code works so I thought it best to add.
function hook() {
$params = parse_params();
$url = $_SERVER['REQUEST_URI'];
$url = str_replace('?'.$_SERVER['QUERY_STRING'], '', $url);
$urlArray = array();
$urlArray = explode("/",$url);
var_dump($urlArray);
if (isset($urlArray[2]) & !empty($urlArray[2])) {
$route['controller'] = $urlArray[2];
} else {
$route['controller'] = 'front'; // Default Action
}
if (isset($urlArray[3]) & !empty($urlArray[3])) {
$route['view'] = $urlArray[3];
} else {
$route['view'] = 'index'; // Default Action
}
include(CONTROLLER_PATH.$route['controller'].'.php');
include(VIEW_PATH.$route['controller'].DS.$route['view'].'.php');
var_dump($route['controller']);
var_dump($route['view']);
var_dump($urlArray);
var_dump($params);
// reseting messages
$_SESSION['flash']['notice'] = '';
$_SESSION['flash']['warning'] = '';
}
// Return form array
function parse_params() {
$params = array();
if(!empty($_POST)) {
$params = array_merge($params, $_POST);
}
if(!empty($_GET)) {
$params = array_merge($params, $_GET);
}
return $params;
}
Can you clarify this: "The problem is in the arrays, how could I get the array to load content after the 2nd level along with the second level."
I don't understand how you want this thing to work. I checked your code and it works. Maybe you just need to put $urlArray[1] instead of $urlArray[2] and 2 instead of 3? First element in the array is at index 0.
Usually it's done like this:
Url format:
/controller/action/param1/param2/...
-controller- should be a class. That class has a method/function called -action-.
ex. /shoes/show/121/ --> this will load controller shoes
and execute the method/function show(121)
that will show the shoes that have the id 121 in the
database.
ex. /shoes/list/sport --> this will load controller shoes
and execute function list('sport') that will list all
shoes in the sport category.
As you can see, you only load one controller and from that controller you run only one function and that function will get the rest of the path and use it as parameters.
If you want to have multiple controllers for one URL, then the rest of the controllers will have to be loaded from the main controller. Most MVCs (like CodeIgniter) load only one controller per URL.
Second question:
Best way for pretty urls would be to save them in the db. This means you can have URLs like this:
/I-can-write-anything-here-No-need-to-add-ids-or-controller-names
Then you take this URL and search it in db and get the -controller- and -action- that you need for this URL.
But I have yet to see a popular MVC framework do this. I guess the reason is that the db will get a lot of queries for text matches and that will slow things down.
Popular MVC frameworks use:
/controller/action/param1/param2
This has the benefit that you can directly find the controller/action from the url.
The downside is that you will get urls like:
/shoes/list/sport
//when what you really want is
/shoes/sport
//or just
/sport //if the website only sells shoes
This can be fixed by redirecting /shoes/sport to /shoes/list/sport
If you make your own MVC then you should use OOP because if not, thing will get ugly quick: all actions/functions are in the same namespace.
Personally I would recommend that you use one of the many PHP frameworks that exist as that will take care of the routing for you and let you concentrate on writing your application. CakePHP is one that I've used for a while and it makes my life so much easier.
What I do:
I create a .htaccess file that redirects an url like www.example.com/url/path/or/something to www.example.com/index.php?url=url/path/or/something, so it will be pretty easy to do an explode on your $_GET['url']
Second, it's better because everything a user input, will be redirected to your index.php, so you have FULL control over EVERYTHING.
If you want I can PM you the url to my mvc (bitbucket) so you can have a look on how I do this ;)
(Sorry for the others, but I don't like to put url's to my site in public)
edit:
To be more precise to your particular question; It will solve your problem, because everything goes to index.php and you have full control over the requested url.

POST data to permanent json file using PHP

using a url, my idea is that any user can post data. For example via
http://myweb.com/index.php?name=Peter&surname=Brown
Using the "jedwards" answer, present here, I am able to create a json and save it to a file.
<?
/* This needs to be at the top of your file, without ANYTHING above it */
session_start();
/* ... */
if(!array_key_exists('entries', $_SESSION))
{
$_SESSION['entries'] = array();
}
$_SESSION['entries'][] = array("name" => $_GET["name"], "surname" => $_GET["surname"]);
$json_string = json_encode($_SESSION['entries']);
My problem is that this is not permanent amongst different session or user. It works only on the same session. On different session the json built start from the beginning.
First of all, don't use GET requests to change the state of the server. GET is only supposed to read (or.. um.. GET) data from the server.
In order to change data, use POST. It's more fitted, slightly more secure, and is great when transferring larger amounts of data.
Now, for the problem at hand. For a more permenant solution, the best option is to enforce user registration, and save the required data on a database, with a reference to the user's ID.
Yes because sessions, as the name imply, are only temporary (and sort of local). When the browser is closed it's gone. Depending on what your demands are you'll have to choose between using a database or textfiles on the server.
Cookies or sessions is not made for this kind of data.
Well if you are looking for a rudimentary solution, see below. If not, use a database as suggested in the other answers.
<?
/* This needs to be at the top of your file, without ANYTHING above it */
session_start();
/* ... */
$file = sys_get_temp_dir() . '/entries.json';
$data = file_get_contents($file);
$entries = (!empty($data)) ? json_decode($data) : array();
$entries[] = array("name" => $_GET["name"], "surname" => $_GET["surname"]);
file_put_contents($file,json_encode($entries),FILE_APPEND);

Categories