Trying to access array offset on value of type null
- Cupara
- Member | 90
I'm struggling to get a specific news article to load after I click on it from the news page.
Here is everything so far.
The errors:
Warning: Trying to access array offset on value of type null in /public_html/temp/public_html-templates-news_detail.latte--086403e216.php on line 42
Warning: Trying to access array offset on value of type null in /public_html/temp/public_html-templates-news_detail.latte--086403e216.php on line 45
Warning: Trying to access array offset on value of type null in /public_html/temp/public_html-templates-news_detail.latte--086403e216.php on line 48
news.php file:
<?php
require_once 'vendor/autoload.php';
require_once 'includes/db.php';
$latte = new Latte\Engine;
$latte->setTempDirectory('temp');
if (isset($_GET['slug'])) {
// Display individual news entry
$slug = $_GET['slug'];
$result = $conn->query("SELECT * FROM news WHERE slug = '$slug'");
$news2 = $result->fetch_assoc();
echo $latte->render(__DIR__.'/templates/news_detail.latte', ['news' => $news2]);
} else {
// Display news listing
$result = $conn->query('SELECT * FROM news ORDER BY created_at DESC');
$news = $result->fetch_all(MYSQLI_ASSOC);
echo $latte->render(__DIR__.'/templates/news.latte', ['news' => $news]);
}
news_detail.latte file:
{extends 'layout.latte'}
{block content}
<h2>{$news['title']}</h2>
<p>{$news['content']}</p>
<p><small class="text-muted">{$news['created_at']}</small></p>
{/block}
And the corresponding php file from the temp folder:
<?php
use Latte\Runtime as LR;
/** source: /home/serenitydev/public_html/templates/news_detail.latte */
final class Template086403e216 extends Latte\Runtime\Template
{
public const Source = '/home/serenitydev/public_html/templates/news_detail.latte';
public const Blocks = [
['content' => 'blockContent'],
];
public function main(array $ʟ_args): void
{
extract($ʟ_args);
unset($ʟ_args);
echo "\n";
$this->renderBlock('content', get_defined_vars()) /* line 3 */;
}
public function prepare(): array
{
extract($this->params);
$this->parentName = 'layout.latte';
return get_defined_vars();
}
/** {block content} on line 3 */
public function blockContent(array $ʟ_args): void
{
extract($this->params);
extract($ʟ_args);
unset($ʟ_args);
echo ' <h2>';
echo LR\Filters::escapeHtmlText($news['title']) /* line 4 */;
echo '</h2>
<p>';
echo LR\Filters::escapeHtmlText($news['content']) /* line 5 */;
echo '</p>
<p><small class="text-muted">';
echo LR\Filters::escapeHtmlText($news['created_at']) /* line 6 */;
echo '</small></p>
';
}
}
This is the last thing I need to get fixed then I can start working on the color scheme and get my site launched.
Thanks
Last edited by Cupara (2023-12-22 14:30)
- David Grudl
- Nette Core | 8227
It tells you that $news2
is null,
$result->fetch_assoc()
returns null. This has nothing to do
with Latte.
- nightfish
- Member | 517
Cupara wrote:
So I did var_dump($news2); and it returns NULL but I'm not understanding why so I'm scouring through the docs for Latte to make sure I implemented the call right. I'm not used to using $result->fetch_assoc(); to fetch a single entry.
@Cupara
As David pointed out earlier, the problem is not in Latte. It is in these
two lines:
$result = $conn->query("SELECT * FROM news WHERE slug = '$slug'");
$news2 = $result->fetch_assoc();
First problem: row 1 contains SQL injection vulnerability. Use prepared
statements. If I am correct in the assumption that you are using
mysqli
class, it would be something like:
$statement = $conn->prepare("SELECT * FROM news WHERE slug = ?");
$statement->bindParam('s', $_GET['slug']);
$statement->execute();
$result = $statement->get_result();
$news2 = $result->fetch_assoc();
Second problem – condition in your SQL query probably does not match any
rows – which is why $news2
is NULL.
- Cupara
- Member | 90
I don't see how it's not right as the slug is being passed otherwise the link wouldn't work properly. Maybe it's an issue in my .htaccess file and how it's parsing the link to prettify it.
Thanks for pointing out the prepared statement vulnerability. I haven't played with PHP in quite a few years and I'm forgetting so much stuff.
- nightfish
- Member | 517
@Cupara Well… you could dump your query with specific value for the
slug (“SELECT * FROM news WHERE slug = ‘foobar’”) and then execute it in
your database admin tool (Adminer, PHPStorm etc.) to see if it returns anything.
Also maybe dump $_GET['slug']
to verify that it does not contain
any trailing whitespace or other unwanted characters.
- Cupara
- Member | 90
Ok so I did a test, I grabbed it right from the database slug field for that specific page and updated my statement like so:
$statement = $conn->prepare("SELECT * FROM news WHERE slug = 'this-is-a-test-2'");
Then commented out:
$statement->bind_param('s', $slug);
And it displayed the data for just that entry like I want so I'm not understanding where the issue it.
- Cupara
- Member | 90
@nightfish I am running out of ideas as well.
Here is the link to it online: https://serenitydev.xyz/…-is-a-test-2
- Cupara
- Member | 90
@nightfish What?!? That makes no sense.
Also, could you check my db.php file to make sure I have no vulnerabilities, please? I'm trying to handle this on my phone as my ex-wife is driving down a bumpy road.
db.php:
<?php
$servername = "localhost";
$username = "XXXXXXXXXX";
$password = "XXXXXXXXXX";
$dbname = "XXXXXXXXX";
$conn = new mysqli($servername, $username, $password, $dbname);
if ($conn->connect_error) {
die("Connection failed: " . $conn->connect_error);
}
function generateSlug($text) {
$text = strtolower(trim($text));
$text = preg_replace('/[^a-z0-9-]/', '-', $text);
$text = preg_replace('/-+/', '-', $text);
return $text;
}
Ignore the function as that isn't implemented yet.
- Cupara
- Member | 90
I'm honestly thinking about starting over from scratch for the 15th time. A lot of the startovers prior were because I was having way too many issues with specific template engine systems that I just didn't want to deal with but when I got to Latte, I liked it so much I wanted to deal with the issues I kept running into.
- nightfish
- Member | 517
@Cupara The db.php
file looks okay-ish, but I would
probably advise against using mysqli
. It is preferable to use
PDO
or rather another higher-level database abstraction layer
(nette/database, dibi/dibi, doctrine/dbal, nextras/dbal).
If you want to go full-Nette, I would advise using
nette/database
, as it can be tightly integrated with Nette.
And maybe base your project on nette/web-project
and if you are new
to Nette, go through the tutorial – https://doc.nette.org/en/quickstart.
It will show you how to create a simple blog website (not dissimilar to your
News/NewsDetail).